tahoma2d/toonz/sources/common/psdlib/psdutils.cpp
Toshihiro Shimizu 890dddabbd first commit
2016-03-19 02:57:51 +09:00

220 lines
4.3 KiB
C++

#if _MSC_VER >= 1400
#define _CRT_SECURE_NO_DEPRECATE 1
#endif
#include "zlib.h"
#include "psdutils.h"
void readrow(FILE *psd,
TPSDChannelInfo *chan,
psdPixel row, // row index
unsigned char *inbuffer, // dest buffer for the uncompressed row
unsigned char *tmpbuffer) // temp rlebuffer for compressed data, 2xrb in size
{
psdPixel n = 0, rlebytes;
psdByte pos;
int seekres = 0;
switch (chan->comptype) {
case RAWDATA: /* uncompressed */
pos = chan->filepos + chan->rowbytes * row;
seekres = fseek(psd, pos, SEEK_SET);
if (seekres != -1)
n = fread(inbuffer, 1, chan->rowbytes, psd);
break;
case RLECOMP:
pos = chan->rowpos[row];
seekres = fseek(psd, pos, SEEK_SET);
if (seekres != -1) {
rlebytes = fread(tmpbuffer, 1, chan->rowpos[row + 1] - pos, psd);
n = unpackrow(inbuffer, tmpbuffer, chan->rowbytes, rlebytes);
}
break;
case ZIPWITHPREDICTION:
case ZIPWITHOUTPREDICTION:
memcpy(inbuffer, chan->unzipdata + chan->rowbytes * row, chan->rowbytes);
return;
}
// if we don't recognise the compression type, skip the row
// FIXME: or would it be better to use the last valid type seen?
// if(seekres == -1)
// alwayswarn("# can't seek to " LL_L("%lld\n","%ld\n"), pos);
if (n < chan->rowbytes) {
//warn("row data short (wanted %d, got %d bytes)", chan->rowbytes, n);
// zero out unwritten part of row
memset(inbuffer + n, 0, chan->rowbytes - n);
}
}
int unpackrow(unsigned char *out, unsigned char *in,
psdPixel outlen, psdPixel inlen)
{
psdPixel i, len;
int val;
for (i = 0; inlen > 1 && i < outlen;) {
len = *in++;
--inlen;
if (len == 128) /* ignore RLE flag value */
;
else {
if (len > 128) {
len = 1 + 256 - len;
val = *in++;
--inlen;
if ((i + len) <= outlen)
memset(out, val, len);
else {
memset(out, val, outlen - i); // fill to complete row
len = 0;
}
} else {
++len;
if ((i + len) <= outlen) {
if (len > inlen)
break;
memcpy(out, in, len);
in += len;
inlen -= len;
} else {
memcpy(out, in, outlen - i); // copy to complete row
len = 0;
}
}
out += len;
i += len;
}
}
if (i < outlen) {
//WARNING: not enough RLE data for row;
}
return i;
}
void skipBlock(FILE *f)
{
psdByte n = read4Bytes(f);
if (n) {
fseek(f, n, SEEK_CUR);
} else {
}
}
// Read 2byte unsigned binary value.
// BigEndian.
unsigned read2UBytes(FILE *f)
{
unsigned n = fgetc(f) << 8;
return n |= fgetc(f);
}
// Read 2byte binary value
// BigEndian.
int read2Bytes(FILE *f)
{
unsigned n = fgetc(f) << 8;
n |= fgetc(f);
return n < 0x8000 ? n : n - 0x10000;
}
// Read 4byte signed binary value.
// BigEndian.
long read4Bytes(FILE *f)
{
long n = fgetc(f) << 24;
n |= fgetc(f) << 16;
n |= fgetc(f) << 8;
return n | fgetc(f);
}
void *mymalloc(long n)
{
void *p = malloc(n);
if (p)
return p;
else {
//ALLOCATION ERROR
}
return NULL;
}
// ZIP COMPRESSION
// ZIP WITHOUT PREDICTION
// If no error returns 1 else returns 0
int psdUnzipWithoutPrediction(unsigned char *src_buf, int src_len,
unsigned char *dst_buf, int dst_len)
{
z_stream stream;
int state;
memset(&stream, 0, sizeof(z_stream));
stream.data_type = Z_BINARY;
stream.next_in = (Bytef *)src_buf;
stream.avail_in = src_len;
stream.next_out = (Bytef *)dst_buf;
stream.avail_out = dst_len;
if (inflateInit(&stream) != Z_OK)
return 0;
do {
state = inflate(&stream, Z_PARTIAL_FLUSH);
if (state == Z_STREAM_END)
break;
if (state == Z_DATA_ERROR || state != Z_OK)
break;
} while (stream.avail_out > 0);
if (state != Z_STREAM_END && state != Z_OK)
return 0;
return 1;
}
// ZIP WITH PREDICTION
int psdUnzipWithPrediction(unsigned char *src_buf, int src_len,
unsigned char *dst_buf, int dst_len,
int row_size, int color_depth)
{
int status;
int len;
unsigned char *buf;
status = psdUnzipWithoutPrediction(src_buf, src_len, dst_buf, dst_len);
if (!status)
return status;
buf = dst_buf;
do {
len = row_size;
if (color_depth == 16) {
while (--len) {
buf[2] += buf[0] + ((buf[1] + buf[3]) >> 8);
buf[3] += buf[1];
buf += 2;
}
buf += 2;
dst_len -= row_size * 2;
} else {
while (--len) {
*(buf + 1) += *buf;
buf++;
}
buf++;
dst_len -= row_size;
}
} while (dst_len > 0);
return 1;
}