Esempio n. 1
0
int
ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    int x;
    int chunk;
    UINT8* out;
    UINT8* ptr;

    ptr = buf;

    chunk = 3 * state->xsize;

    for (;;) {

	/* We need data for two full lines before we can do anything */
	if (bytes < chunk)
	    return ptr - buf;

	/* Unpack first line */
	out = state->buffer;
	for (x = 0; x < state->xsize; x++) {
	    out[0] = ptr[x];
	    out[1] = ptr[(x+4*state->xsize)/2];
	    out[2] = ptr[(x+5*state->xsize)/2];
	    out += 3;
	}

	state->shuffle((UINT8*) im->image[state->y],
		       state->buffer, state->xsize);

	if (++state->y >= state->ysize)
	    return -1; /* This can hardly happen */

	/* Unpack second line */
	out = state->buffer;
	for (x = 0; x < state->xsize; x++) {
	    out[0] = ptr[x+state->xsize];
	    out[1] = ptr[(x+4*state->xsize)/2];
	    out[2] = ptr[(x+5*state->xsize)/2];
	    out += 3;
	}

	state->shuffle((UINT8*) im->image[state->y],
		       state->buffer, state->xsize);

	if (++state->y >= state->ysize)
	    return -1;

	ptr += chunk;
	bytes -= chunk;

    }
}
Esempio n. 2
0
int
ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    UINT8 n;
    UINT8* ptr;

    ptr = buf;

    for (;;) {

	if (bytes < 1)
	    return ptr - buf;

	if ((*ptr & 0xC0) == 0xC0) {

	    /* Run */
	    if (bytes < 2)
		return ptr - buf;

	    n = ptr[0] & 0x3F;
	    
	    while (n > 0) {
		if (state->x >= state->bytes) {
		    state->errcode = IMAGING_CODEC_OVERRUN;
		    break;
		}
		state->buffer[state->x++] = ptr[1];
		n--;
	    }

	    ptr += 2; bytes -= 2;

	} else {

	    /* Literal */
	    state->buffer[state->x++] = ptr[0];
	    ptr++; bytes--;

	}

	if (state->x >= state->bytes) {

	    /* Got a full line, unpack it */
	    state->shuffle((UINT8*) im->image[state->y + state->yoff] +
			   state->xoff * im->pixelsize, state->buffer,
			   state->xsize);

	    state->x = 0;

	    if (++state->y >= state->ysize) {
		/* End of file (errcode = 0) */
		return -1;
	    }
	}

    }
}
Esempio n. 3
0
int
ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    UINT8* ptr;
    int a, b;

    ptr = buf;

    for (;;) {

	if (bytes < 2)
	    return ptr - buf;

	a = HEX(ptr[0]);
	b = HEX(ptr[1]);

	if (a < 0 || b < 0) {

	    ptr++;
	    bytes--;

	} else {

	    ptr += 2;
	    bytes -= 2;

	    state->buffer[state->x] = (a<<4) + b;

	    if (++state->x >= state->bytes) {

		/* Got a full line, unpack it */
		state->shuffle((UINT8*) im->image[state->y], state->buffer,
			       state->xsize);

		state->x = 0;

		if (++state->y >= state->ysize) {
		    /* End of file (errcode = 0) */
		    return -1;
		}
	    }

	}
    }
}
Esempio n. 4
0
int
ImagingPackbitsDecode(Imaging im, ImagingCodecState state,
		      UINT8* buf, Py_ssize_t bytes)
{
    UINT8 n;
    UINT8* ptr;
    int i;

    ptr = buf;

    for (;;) {

	if (bytes < 1)
	    return ptr - buf;

	if (ptr[0] & 0x80) {

	    if (ptr[0] == 0x80) {
		/* Nop */
		ptr++; bytes--;
		continue;
	    }

	    /* Run */
	    if (bytes < 2)
		return ptr - buf;

	    for (n = 257 - ptr[0]; n > 0; n--) {
		if (state->x >= state->bytes) {
		    /* state->errcode = IMAGING_CODEC_OVERRUN; */
		    break;
		}
		state->buffer[state->x++] = ptr[1];
	    }

	    ptr += 2; bytes -= 2;

	} else {

	    /* Literal */
	    n = ptr[0]+2;

	    if (bytes < n)
		return ptr - buf;

	    for (i = 1; i < n; i++) {
		if (state->x >= state->bytes) {
		    /* state->errcode = IMAGING_CODEC_OVERRUN; */
		    break;
		}
		state->buffer[state->x++] = ptr[i];
	    }

	    ptr += n; bytes -= n;

	}

	if (state->x >= state->bytes) {

	    /* Got a full line, unpack it */
	    state->shuffle((UINT8*) im->image[state->y + state->yoff] +
			   state->xoff * im->pixelsize, state->buffer,
			   state->xsize);

	    state->x = 0;

	    if (++state->y >= state->ysize) {
		/* End of file (errcode = 0) */
		return -1;
	    }
	}

    }
}
Esempio n. 5
0
int
ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    ZIPSTATE* context = (ZIPSTATE*) state->context;
    int err;
    int n;
    UINT8* ptr;
    int i, bpp;

    if (!state->state) {

	/* Initialization */
	if (context->mode == ZIP_PNG || context->mode == ZIP_PNG_PALETTE)
	    context->prefix = 1; /* PNG */

	/* Expand standard buffer to make room for the (optional) filter
	   prefix, and allocate a buffer to hold the previous line */
	free(state->buffer);
	state->buffer = (UINT8*) malloc(state->bytes+1);
	context->previous = (UINT8*) malloc(state->bytes+1);
	if (!state->buffer || !context->previous) {
	    state->errcode = IMAGING_CODEC_MEMORY;
	    return -1;
	}

        context->last_output = 0;

	/* Initialize to black */
	memset(context->previous, 0, state->bytes+1);

	/* Setup decompression context */
	context->z_stream.zalloc = (alloc_func)0;
	context->z_stream.zfree = (free_func)0;
	context->z_stream.opaque = (voidpf)0;

	err = inflateInit(&context->z_stream);
	if (err < 0) {
	    state->errcode = IMAGING_CODEC_CONFIG;
	    return -1;
	}

	/* Ready to decode */
	state->state = 1;

    }

    /* Setup the source buffer */
    context->z_stream.next_in = buf;
    context->z_stream.avail_in = bytes;

    /* Decompress what we've got this far */
    while (context->z_stream.avail_in > 0) {

	context->z_stream.next_out = state->buffer + context->last_output;
	context->z_stream.avail_out =
            state->bytes + context->prefix - context->last_output;

	err = inflate(&context->z_stream, Z_NO_FLUSH);

	if (err < 0) {
	    /* Something went wrong inside the compression library */
	    if (err == Z_DATA_ERROR)
		state->errcode = IMAGING_CODEC_BROKEN;
	    else if (err == Z_MEM_ERROR)
		state->errcode = IMAGING_CODEC_MEMORY;
	    else
		state->errcode = IMAGING_CODEC_CONFIG;
	    free(context->previous);
	    inflateEnd(&context->z_stream);
	    return -1;
	}

	n = state->bytes + context->prefix - context->z_stream.avail_out;

	if (n < state->bytes + context->prefix) {
            context->last_output = n;
	    break; /* need more input data */
	}

	/* Apply predictor */
	switch (context->mode) {
	case ZIP_PNG:
	    switch (state->buffer[0]) {
	    case 0:
		break;
	    case 1:
		/* prior */
		bpp = (state->bits + 7) / 8;
		for (i = bpp+1; i <= state->bytes; i++)
		    state->buffer[i] += state->buffer[i-bpp];
		break;
	    case 2:
		/* up */
		for (i = 1; i <= state->bytes; i++)
		    state->buffer[i] += context->previous[i];
		break;
	    case 3:
		/* average */
		bpp = (state->bits + 7) / 8;
		for (i = 1; i <= bpp; i++)
		    state->buffer[i] += context->previous[i]/2;
		for (; i <= state->bytes; i++)
		    state->buffer[i] +=
			(state->buffer[i-bpp] + context->previous[i])/2;
		break;
	    case 4:
		/* paeth filtering */
		bpp = (state->bits + 7) / 8;
		for (i = 1; i <= bpp; i++)
		    state->buffer[i] += context->previous[i];
		for (; i <= state->bytes; i++) {
		    int a, b, c;
		    int pa, pb, pc;

		    /* fetch pixels */
		    a = state->buffer[i-bpp];
		    b = context->previous[i];
		    c = context->previous[i-bpp];

		    /* distances to surrounding pixels */
		    pa = abs(b - c);
		    pb = abs(a - c);
		    pc = abs(a + b - 2*c);

		    /* pick predictor with the shortest distance */
		    state->buffer[i] +=
			(pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;

		}
		break;
	    default:
		state->errcode = IMAGING_CODEC_UNKNOWN;
		free(context->previous);
		inflateEnd(&context->z_stream);
		return -1;
	    }
	    break;
	case ZIP_TIFF_PREDICTOR:
	    bpp = (state->bits + 7) / 8;
	    for (i = bpp+1; i <= state->bytes; i++)
		state->buffer[i] += state->buffer[i-bpp];
	    break;
	}

	/* Stuff data into the image */
	state->shuffle((UINT8*) im->image[state->y + state->yoff] + 
		       state->xoff * im->pixelsize,
		       state->buffer + context->prefix,
		       state->xsize);

	state->y++;

        /* all inflate output has been consumed */
        context->last_output = 0;

	if (state->y >= state->ysize || err == Z_STREAM_END) {

	    /* The image and the data should end simultaneously */
	    /* if (state->y < state->ysize || err != Z_STREAM_END)
		state->errcode = IMAGING_CODEC_BROKEN; */

	    free(context->previous);
	    inflateEnd(&context->z_stream);
	    return -1; /* end of file (errcode=0) */

	}

	/* Swap buffer pointers */
	ptr = state->buffer;
	state->buffer = context->previous;
	context->previous = ptr;

    }

    return bytes; /* consumed all of it */

}
Esempio n. 6
0
int
ImagingXbmEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    const char *hex = "0123456789abcdef";

    UINT8* ptr = buf;
    int i, n;

    if (!state->state) {

	/* 8 pixels are stored in no more than 6 bytes */
	state->bytes = 6*(state->xsize+7)/8;

	state->state = 1;

    }

    if (bytes < state->bytes) {
	state->errcode = IMAGING_CODEC_MEMORY;
	return 0;
    }

    ptr = buf;

    while (bytes >= state->bytes) {

	state->shuffle(state->buffer,
		       (UINT8*) im->image[state->y + state->yoff] +
		       state->xoff * im->pixelsize, state->xsize);

	if (state->y < state->ysize-1) {

	    /* any line but the last */
	    for (n = 0; n < state->xsize; n += 8) {

		i = state->buffer[n/8];

		*ptr++ = '0';
		*ptr++ = 'x';
		*ptr++ = hex[(i>>4)&15];
		*ptr++ = hex[i&15];
		*ptr++ = ',';
		bytes -= 5;

		if (++state->count >= 79/5) {
		    *ptr++ = '\n';
		    bytes--;
		    state->count = 0;
		}

	    }

	    state->y++;

	} else {

	    /* last line */
	    for (n = 0; n < state->xsize; n += 8) {

		i = state->buffer[n/8];

		*ptr++ = '0';
		*ptr++ = 'x';
		*ptr++ = hex[(i>>4)&15];
		*ptr++ = hex[i&15];

		if (n < state->xsize-8) {
		    *ptr++ = ',';
		    if (++state->count >= 79/5) {
			*ptr++ = '\n';
			bytes--;
			state->count = 0;
		    }
		} else
		    *ptr++ = '\n';

		bytes -= 5;

	    }

	    state->errcode = IMAGING_CODEC_END;
	    break;
	}
    }
Esempio n. 7
0
int
ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    UINT8* ptr;
    int this;

    GIFENCODERBLOCK* block;
    GIFENCODERSTATE *context = (GIFENCODERSTATE*) state->context;

    if (!state->state) {

	/* place a clear code in the output buffer */
	context->bitbuffer = CLEAR_CODE;
	context->bitcount = 9;

	state->count = FIRST_CODE;

	if (context->interlace) {
	    context->interlace = 1;
	    context->step = 8;
	} else
	    context->step = 1;

        context->last = -1;

        /* sanity check */
        if (state->xsize <= 0 || state->ysize <= 0)
            state->state = ENCODE_EOF;

    }

    ptr = buf;

    for (;;)

	switch (state->state) {

        case INIT:
        case ENCODE:

            /* identify and store a run of pixels */

            if (state->x == 0 || state->x >= state->xsize) {

                if (!context->interlace && state->y >= state->ysize) {
                    state->state = ENCODE_EOF;
                    break;
                }

                if (context->flush) {
                    state->state = FLUSH;
                    break;
                }

                /* get another line of data */
                state->shuffle(
                    state->buffer,
                    (UINT8*) im->image[state->y + state->yoff] +
                    state->xoff * im->pixelsize, state->xsize
                    );

                state->x = 0;

                if (state->state == INIT) {
                    /* preload the run-length buffer and get going */
                    context->last = state->buffer[0];
                    context->count = state->x = 1;
                    state->state = ENCODE;
                }

                /* step forward, according to the interlace settings */
                state->y += context->step;
                while (context->interlace && state->y >= state->ysize)
                    switch (context->interlace) {
                    case 1:
                        state->y = 4;
                        context->interlace = 2;
                        break;
                    case 2:
                        context->step = 4;
                        state->y = 2;
                        context->interlace = 3;
                        break;
                    case 3:
                        context->step = 2;
                        state->y = 1;
                        context->interlace = 0;
                        break;
                    default:
                        /* just make sure we don't loop forever */
                        context->interlace = 0;
                    }

            }

            this = state->buffer[state->x++];

            if (this == context->last)
                context->count++;
            else {
                EMIT_RUN(label1);
                context->last = this;
                context->count = 1;
            }
	    break;


        case ENCODE_EOF:

            /* write the final run */
            EMIT_RUN(label2);

            /* write an end of image marker */
            EMIT(EOF_CODE);

            /* empty the bit buffer */
            while (context->bitcount > 0) {
                if (!emit(context, (UINT8) context->bitbuffer)) {
                    state->errcode = IMAGING_CODEC_MEMORY;
                    return 0;
                }
                context->bitbuffer >>= 8;
                context->bitcount -= 8;
            }

            /* flush the last block, and exit */
            if (context->block) {
                GIFENCODERBLOCK* block;
                block = context->flush;
                while (block && block->next)
                    block = block->next;
                if (block)
                    block->next = context->block;
                else
                    context->flush = context->block;
                context->block = NULL;
            }

            state->state = EXIT;

            /* fall through... */

	case EXIT:
	case FLUSH:

            while (context->flush) {

                /* get a block from the flush queue */
                block = context->flush;

                if (block->size > 0) {

                    /* make sure it fits into the output buffer */
                    if (bytes < block->size+1)
                        return ptr - buf;

                    ptr[0] = block->size;
                    memcpy(ptr+1, block->data, block->size);

                    ptr += block->size+1;
                    bytes -= block->size+1;

                }

                context->flush = block->next;

                if (context->free)
                    free(context->free);
                context->free = block;

            }

            if (state->state == EXIT) {
                /* this was the last block! */
                if (context->free)
                    free(context->free);
                state->errcode = IMAGING_CODEC_END;
                return ptr - buf;
            }

            state->state = ENCODE;
	    break;
        }
}
Esempio n. 8
0
int
ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    JPEGENCODERSTATE* context = (JPEGENCODERSTATE*) state->context;
    int ok;

    if (setjmp(context->error.setjmp_buffer)) {
	/* JPEG error handler */
	jpeg_destroy_compress(&context->cinfo);
	state->errcode = IMAGING_CODEC_BROKEN;
	return -1;
    }

    if (!state->state) {

	/* Setup compression context (very similar to the decoder) */
	context->cinfo.err = jpeg_std_error(&context->error.pub);
	context->error.pub.error_exit = error;
	jpeg_create_compress(&context->cinfo);
	jpeg_buffer_dest(&context->cinfo, &context->destination);

        context->extra_offset = 0;

	/* Ready to encode */
	state->state = 1;

    }

    /* Load the destination buffer */
    context->destination.pub.next_output_byte = buf;
    context->destination.pub.free_in_buffer = bytes;

    switch (state->state) {

    case 1:

	context->cinfo.image_width = state->xsize;
	context->cinfo.image_height = state->ysize;

	switch (state->bits) {
        case 8:
            context->cinfo.input_components = 1;
            context->cinfo.in_color_space = JCS_GRAYSCALE;
            break;
        case 24:
            context->cinfo.input_components = 3;
            if (strcmp(im->mode, "YCbCr") == 0)
                context->cinfo.in_color_space = JCS_YCbCr;
            else
                context->cinfo.in_color_space = JCS_RGB;
            break;
        case 32:
            context->cinfo.input_components = 4;
            context->cinfo.in_color_space = JCS_CMYK;
            break;
        default:
            state->errcode = IMAGING_CODEC_CONFIG;
            return -1;
	}

	/* Compressor configuration */
	jpeg_set_defaults(&context->cinfo);

	/* Use custom quantization tables */
	if (context->qtables) {
        int i;
        int quality = 100;
        if (context->quality > 0) {
            quality = context->quality;
        }
        for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int); i++) {
             // TODO: Should add support for none baseline
            jpeg_add_quant_table(&context->cinfo, i, context->qtables[i],
                quality, TRUE);
        }
	} else if (context->quality > 0) {
	    jpeg_set_quality(&context->cinfo, context->quality, 1);
	}

	/* Set subsampling options */
	switch (context->subsampling)
	{
		case 0:  /* 1x1 1x1 1x1 (4:4:4) : None */
		{
			context->cinfo.comp_info[0].h_samp_factor = 1;
			context->cinfo.comp_info[0].v_samp_factor = 1;
			context->cinfo.comp_info[1].h_samp_factor = 1;
			context->cinfo.comp_info[1].v_samp_factor = 1;
			context->cinfo.comp_info[2].h_samp_factor = 1;
			context->cinfo.comp_info[2].v_samp_factor = 1;
			break;
		}
		case 1:  /* 2x1, 1x1, 1x1 (4:2:2) : Medium */
		{
			context->cinfo.comp_info[0].h_samp_factor = 2;
			context->cinfo.comp_info[0].v_samp_factor = 1;
			context->cinfo.comp_info[1].h_samp_factor = 1;
			context->cinfo.comp_info[1].v_samp_factor = 1;
			context->cinfo.comp_info[2].h_samp_factor = 1;
			context->cinfo.comp_info[2].v_samp_factor = 1;
			break;
		}
		case 2:  /* 2x2, 1x1, 1x1 (4:1:1) : High */
		{
			context->cinfo.comp_info[0].h_samp_factor = 2;
			context->cinfo.comp_info[0].v_samp_factor = 2;
			context->cinfo.comp_info[1].h_samp_factor = 1;
			context->cinfo.comp_info[1].v_samp_factor = 1;
			context->cinfo.comp_info[2].h_samp_factor = 1;
			context->cinfo.comp_info[2].v_samp_factor = 1;
			break;
		}
		default:
		{
			/* Use the lib's default */
			break;
		}
	}
	if (context->progressive)
	    jpeg_simple_progression(&context->cinfo);
	context->cinfo.smoothing_factor = context->smooth;
	context->cinfo.optimize_coding = (boolean) context->optimize;
        if (context->xdpi > 0 && context->ydpi > 0) {
            context->cinfo.density_unit = 1; /* dots per inch */
            context->cinfo.X_density = context->xdpi;
            context->cinfo.Y_density = context->ydpi;
        }
	switch (context->streamtype) {
	case 1:
	    /* tables only -- not yet implemented */
	    state->errcode = IMAGING_CODEC_CONFIG;
	    return -1;
	case 2:
	    /* image only */
	    jpeg_suppress_tables(&context->cinfo, TRUE);
	    jpeg_start_compress(&context->cinfo, FALSE);
            /* suppress extra section */
            context->extra_offset = context->extra_size;
        //add exif header
        if (context->rawExifLen > 0)
            jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen);

	    break;
	default:
	    /* interchange stream */
	    jpeg_start_compress(&context->cinfo, TRUE);
        //add exif header
        if (context->rawExifLen > 0)
            jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen);

        break;
	}
	state->state++;
	/* fall through */

    case 2:

        if (context->extra) {
            /* copy extra buffer to output buffer */
            unsigned int n = context->extra_size - context->extra_offset;
            if (n > context->destination.pub.free_in_buffer)
                n = context->destination.pub.free_in_buffer;
            memcpy(context->destination.pub.next_output_byte,
                   context->extra + context->extra_offset, n);
            context->destination.pub.next_output_byte += n;
            context->destination.pub.free_in_buffer -= n;
            context->extra_offset += n;
            if (context->extra_offset >= context->extra_size)
                state->state++;
            else
                break;
        } else
              state->state++;

    case 3:

	ok = 1;
	while (state->y < state->ysize) {
	    state->shuffle(state->buffer,
			   (UINT8*) im->image[state->y + state->yoff] +
			   state->xoff * im->pixelsize, state->xsize);
	    ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1);
	    if (ok != 1)
		break;
	    state->y++;
	}

	if (ok != 1)
	    break;
	state->state++;
	/* fall through */

    case 4:

	/* Finish compression */
	if (context->destination.pub.free_in_buffer < 100)
	    break;
	jpeg_finish_compress(&context->cinfo);

	/* Clean up */
        if (context->extra)
            free(context->extra);
	jpeg_destroy_compress(&context->cinfo);
	/* if (jerr.pub.num_warnings) return BROKEN; */
	state->errcode = IMAGING_CODEC_END;
	break;

    }

    /* Return number of bytes in output buffer */
    return context->destination.pub.next_output_byte - buf;

}
Esempio n. 9
0
int
ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    enum { LINE = 1, SKIP };
    RAWSTATE* rawstate = state->context;

    UINT8* ptr;

    if (state->state == 0) {

	/* Initialize context variables */

	/* get size of image data and padding */
	state->bytes = (state->xsize * state->bits + 7) / 8;
	rawstate->skip = (rawstate->stride) ?
	    rawstate->stride - state->bytes : 0;

	/* check image orientation */
	if (state->ystep < 0) {
	    state->y = state->ysize-1;
	    state->ystep = -1;
	} else
	    state->ystep = 1;

	state->state = LINE;

    }

    ptr = buf;

    for (;;) {

	if (state->state == SKIP) {

	    /* Skip padding between lines */

	    if (bytes < rawstate->skip)
		return ptr - buf;

	    ptr += rawstate->skip;
	    bytes -= rawstate->skip;

	    state->state = LINE;

	}

	if (bytes < state->bytes)
	    return ptr - buf;

	/* Unpack data */
	state->shuffle((UINT8*) im->image[state->y + state->yoff] + 
		       state->xoff * im->pixelsize, ptr, state->xsize);

	ptr += state->bytes;
	bytes -= state->bytes;

	state->y += state->ystep;

	if (state->y < 0 || state->y >= state->ysize) {
	    /* End of file (errcode = 0) */
	    return -1;
	}

	state->state = SKIP;

    }

}
Esempio n. 10
0
int
ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    UINT8* ptr;

    if (!state->state) {

	/* The "count" field holds the stride, if specified.  Fix
	   things up so "bytes" is the full size, and "count" the
	   packed size */

	if (state->count > 0) {
	    int bytes = state->count;

	    /* stride must not be less than real size */
	    if (state->count < state->bytes) {
		state->errcode = IMAGING_CODEC_CONFIG;
		return -1;
	    }
	    state->count = state->bytes;
	    state->bytes = bytes;
	} else
	    state->count = state->bytes;

	/* The "ystep" field specifies the orientation */

	if (state->ystep < 0) {
	    state->y = state->ysize-1;
	    state->ystep = -1;
	} else
	    state->ystep = 1;

	state->state = 1;

    }

    if (bytes < state->bytes) {
	state->errcode = IMAGING_CODEC_CONFIG;
	return 0;
    }

    ptr = buf;

    while (bytes >= state->bytes) {

	state->shuffle(ptr, (UINT8*) im->image[state->y + state->yoff] +
		       state->xoff * im->pixelsize, state->xsize);

	if (state->bytes > state->count)
	    /* zero-pad the buffer, if necessary */
	    memset(ptr + state->count, 0, state->bytes - state->count);

	ptr += state->bytes;
	bytes -= state->bytes;

	state->y += state->ystep;

	if (state->y < 0 || state->y >= state->ysize) {
	    state->errcode = IMAGING_CODEC_END;
	    break;
	}

    }

    return ptr - buf;

}
Esempio n. 11
0
int
ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    ZIPSTATE* context = (ZIPSTATE*) state->context;
    int err;
    int compress_level, compress_type;
    UINT8* ptr;
    int i, bpp, s, sum;
    ImagingSectionCookie cookie;

    if (!state->state) {

        /* Initialization */

        /* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */

        /* overflow check for malloc */
        if (state->bytes > INT_MAX - 1) {
            state->errcode = IMAGING_CODEC_MEMORY;
            return -1;
        }

        /* Expand standard buffer to make room for the filter selector,
           and allocate filter buffers */
        free(state->buffer);
        /* malloc check ok, overflow checked above */
        state->buffer = (UINT8*) malloc(state->bytes+1);
        context->previous = (UINT8*) malloc(state->bytes+1);
        context->prior = (UINT8*) malloc(state->bytes+1);
        context->up = (UINT8*) malloc(state->bytes+1);
        context->average = (UINT8*) malloc(state->bytes+1);
        context->paeth = (UINT8*) malloc(state->bytes+1);
        if (!state->buffer || !context->previous || !context->prior ||
            !context->up || !context->average || !context->paeth) {
            free(context->paeth);
            free(context->average);
            free(context->up);
            free(context->prior);
            free(context->previous);
            state->errcode = IMAGING_CODEC_MEMORY;
            return -1;
        }

        /* Initialise filter buffers */
        state->buffer[0] = 0;
        context->prior[0] = 1;
        context->up[0] = 2;
        context->average[0] = 3;
        context->paeth[0] = 4;

        /* Initialise previous buffer to black */
        memset(context->previous, 0, state->bytes+1);

        /* Setup compression context */
        context->z_stream.zalloc = (alloc_func)0;
        context->z_stream.zfree = (free_func)0;
        context->z_stream.opaque = (voidpf)0;
        context->z_stream.next_in = 0;
        context->z_stream.avail_in = 0;

        compress_level = (context->optimize) ? Z_BEST_COMPRESSION
                                             : context->compress_level;

        if (context->compress_type == -1) {
            compress_type = (context->mode == ZIP_PNG) ? Z_FILTERED
                                                       : Z_DEFAULT_STRATEGY;
        } else {
            compress_type = context->compress_type;
        }

        err = deflateInit2(&context->z_stream,
                           /* compression level */
                           compress_level,
                           /* compression method */
                           Z_DEFLATED,
                           /* compression memory resources */
                           15, 9,
                           /* compression strategy (image data are filtered)*/
                           compress_type);
        if (err < 0) {
            state->errcode = IMAGING_CODEC_CONFIG;
            return -1;
        }

        if (context->dictionary && context->dictionary_size > 0) {
            err = deflateSetDictionary(&context->z_stream, (unsigned char *)context->dictionary,
                                       context->dictionary_size);
            if (err < 0) {
                state->errcode = IMAGING_CODEC_CONFIG;
                return -1;
            }
        }

        /* Ready to decode */
        state->state = 1;

    }

    /* Setup the destination buffer */
    context->z_stream.next_out = buf;
    context->z_stream.avail_out = bytes;
    if (context->z_stream.next_in && context->z_stream.avail_in > 0) {
        /* We have some data from previous round, deflate it first */
        err = deflate(&context->z_stream, Z_NO_FLUSH);

        if (err < 0) {
            /* Something went wrong inside the compression library */
            if (err == Z_DATA_ERROR)
                state->errcode = IMAGING_CODEC_BROKEN;
            else if (err == Z_MEM_ERROR)
                state->errcode = IMAGING_CODEC_MEMORY;
            else
                state->errcode = IMAGING_CODEC_CONFIG;
            free(context->paeth);
            free(context->average);
            free(context->up);
            free(context->prior);
            free(context->previous);
            deflateEnd(&context->z_stream);
            return -1;
        }
    }

    ImagingSectionEnter(&cookie);
    for (;;) {

        switch (state->state) {

        case 1:

            /* Compress image data */
            while (context->z_stream.avail_out > 0) {

                if (state->y >= state->ysize) {
                    /* End of image; now flush compressor buffers */
                    state->state = 2;
                    break;

                }

                /* Stuff image data into the compressor */
                state->shuffle(state->buffer+1,
                               (UINT8*) im->image[state->y + state->yoff] +
                               state->xoff * im->pixelsize,
                               state->xsize);

                state->y++;

                context->output = state->buffer;

                if (context->mode == ZIP_PNG) {

                    /* Filter the image data.  For each line, select
                       the filter that gives the least total distance
                       from zero for the filtered data (taken from
                       LIBPNG) */

                    bpp = (state->bits + 7) / 8;

                    /* 0. No filter */
                    for (i = 1, sum = 0; i <= state->bytes; i++) {
                        UINT8 v = state->buffer[i];
                        sum += (v < 128) ? v : 256 - v;
                    }

                    /* 2. Up.  We'll test this first to save time when
                       an image line is identical to the one above. */
                    if (sum > 0) {
                        for (i = 1, s = 0; i <= state->bytes; i++) {
                            UINT8 v = state->buffer[i] - context->previous[i];
                            context->up[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        if (s < sum) {
                            context->output = context->up;
                            sum = s; /* 0 if line was duplicated */
                        }
                    }

                    /* 1. Prior */
                    if (sum > 0) {
                        for (i = 1, s = 0; i <= bpp; i++) {
                            UINT8 v = state->buffer[i];
                            context->prior[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        for (; i <= state->bytes; i++) {
                            UINT8 v = state->buffer[i] - state->buffer[i-bpp];
                            context->prior[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        if (s < sum) {
                            context->output = context->prior;
                            sum = s; /* 0 if line is solid */
                        }
                    }

                    /* 3. Average (not very common in real-life images,
                       so its only used with the optimize option) */
                    if (context->optimize && sum > 0) {
                        for (i = 1, s = 0; i <= bpp; i++) {
                            UINT8 v = state->buffer[i] - context->previous[i]/2;
                            context->average[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        for (; i <= state->bytes; i++) {
                            UINT8 v = state->buffer[i] -
                                      (state->buffer[i-bpp] + context->previous[i])/2;
                            context->average[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        if (s < sum) {
                            context->output = context->average;
                            sum = s;
                        }
                    }

                    /* 4. Paeth */
                    if (sum > 0) {
                        for (i = 1, s = 0; i <= bpp; i++) {
                            UINT8 v = state->buffer[i] - context->previous[i];
                            context->paeth[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        for (; i <= state->bytes; i++) {
                            UINT8 v;
                            int a, b, c;
                            int pa, pb, pc;

                            /* fetch pixels */
                            a = state->buffer[i-bpp];
                            b = context->previous[i];
                            c = context->previous[i-bpp];

                            /* distances to surrounding pixels */
                            pa = abs(b - c);
                            pb = abs(a - c);
                            pc = abs(a + b - 2*c);

                            /* pick predictor with the shortest distance */
                            v = state->buffer[i] -
                                ((pa <= pb && pa <= pc) ? a :
                                 (pb <= pc) ? b : c);
                            context->paeth[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        if (s < sum) {
                            context->output = context->paeth;
                            sum = s;
                        }
                    }
                }

                /* Compress this line */
                context->z_stream.next_in = context->output;
                context->z_stream.avail_in = state->bytes+1;

                err = deflate(&context->z_stream, Z_NO_FLUSH);

                if (err < 0) {
                    /* Something went wrong inside the compression library */
                    if (err == Z_DATA_ERROR)
                        state->errcode = IMAGING_CODEC_BROKEN;
                    else if (err == Z_MEM_ERROR)
                        state->errcode = IMAGING_CODEC_MEMORY;
                    else
                        state->errcode = IMAGING_CODEC_CONFIG;
                    free(context->paeth);
                    free(context->average);
                    free(context->up);
                    free(context->prior);
                    free(context->previous);
                    deflateEnd(&context->z_stream);
                    ImagingSectionLeave(&cookie);
                    return -1;
                }

                /* Swap buffer pointers */
                ptr = state->buffer;
                state->buffer = context->previous;
                context->previous = ptr;

            }

            if (context->z_stream.avail_out == 0)
                break; /* Buffer full */

        case 2:

            /* End of image data; flush compressor buffers */

            while (context->z_stream.avail_out > 0) {

                err = deflate(&context->z_stream, Z_FINISH);

                if (err == Z_STREAM_END) {

                    free(context->paeth);
                    free(context->average);
                    free(context->up);
                    free(context->prior);
                    free(context->previous);

                    deflateEnd(&context->z_stream);

                    state->errcode = IMAGING_CODEC_END;

                    break;
                }

                if (context->z_stream.avail_out == 0)
                    break; /* Buffer full */

            }

        }
        ImagingSectionLeave(&cookie);
        return bytes - context->z_stream.avail_out;

    }

    /* Should never ever arrive here... */
    state->errcode = IMAGING_CODEC_CONFIG;
    ImagingSectionLeave(&cookie);
    return -1;
}
Esempio n. 12
0
int
ImagingTgaRleDecode(Imaging im, ImagingCodecState state,
                    UINT8* buf, int bytes)
{
    int n, depth;
    UINT8* ptr;

    ptr = buf;

    if (state->state == 0) {

        /* check image orientation */
        if (state->ystep < 0) {
            state->y = state->ysize-1;
            state->ystep = -1;
        } else
            state->ystep = 1;

        state->state = 1;

    }

    depth = state->count;

    for (;;) {

        if (bytes < 1)
            return ptr - buf;

        if (ptr[0] & 0x80) {

            /* Run (1 + pixelsize bytes) */

            if (bytes < 1 + depth)
                break;

            n = depth * ((ptr[0] & 0x7f) + 1);

            if (state->x + n > state->bytes) {
                state->errcode = IMAGING_CODEC_OVERRUN;
                return -1;
            }

            if (depth == 1)
                memset(state->buffer + state->x, ptr[1], n);
            else {
                int i;
                for (i = 0; i < n; i += depth)
                    memcpy(state->buffer + state->x + i, ptr+1, depth);
            }

            ptr += 1 + depth;
            bytes -= 1 + depth;

        } else {

            /* Literal (1+n+1 bytes block) */
            n = depth * (ptr[0] + 1);

            if (bytes < 1 + n)
                break;

            if (state->x + n > state->bytes) {
                state->errcode = IMAGING_CODEC_OVERRUN;
                return -1;
            }

            memcpy(state->buffer + state->x, ptr + 1, n);

            ptr += 1 + n;
            bytes -= 1 + n;

        }

        state->x += n;

        if (state->x >= state->bytes) {

            /* Got a full line, unpack it */
            state->shuffle((UINT8*) im->image[state->y + state->yoff] +
                           state->xoff * im->pixelsize, state->buffer,
                           state->xsize);

            state->x = 0;

            state->y += state->ystep;

            if (state->y < 0 || state->y >= state->ysize) {
                /* End of file (errcode = 0) */
                return -1;
            }

        }

    }

    return ptr - buf;
}
Esempio n. 13
0
int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes) {
    /* One shot encoder. Encode everything to the tiff in the clientstate.
       If we're running off of a FD, then run once, we're good, everything
       ends up in the file, we close and we're done.

       If we're going to memory, then we need to write the whole file into memory, then
       parcel it back out to the pystring buffer bytes at a time.

    */

    TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
    TIFF *tiff = clientstate->tiff;

    TRACE(("in encoder: bytes %d\n", bytes));
    TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
           state->x, state->y, state->ystep));
    TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
           state->xoff, state->yoff));
    TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
    TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
    TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3]));
    TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
           im->mode, im->type, im->bands, im->xsize, im->ysize));
    TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n",
           im->image8, im->image32, im->image, im->block));
    TRACE(("Image: pixelsize: %d, linesize %d \n",
           im->pixelsize, im->linesize));

    dump_state(clientstate);

    if (state->state == 0) {
        TRACE(("Encoding line bt line"));
        while(state->y < state->ysize){
            state->shuffle(state->buffer,
                           (UINT8*) im->image[state->y + state->yoff] +
                           state->xoff * im->pixelsize,
                           state->xsize);

            if (TIFFWriteScanline(tiff, (tdata_t)(state->buffer), (uint32)state->y, 0) == -1) {
                TRACE(("Encode Error, row %d\n", state->y));
                state->errcode = IMAGING_CODEC_BROKEN;
                TIFFClose(tiff);
                if (!clientstate->fp){
                    free(clientstate->data);
                }
                return -1;
            }
            state->y++;
        }

        if (state->y == state->ysize) {
            state->state=1;

            TRACE(("Flushing \n"));
            if (!TIFFFlush(tiff)) {
                TRACE(("Error flushing the tiff"));
                // likely reason is memory.
                state->errcode = IMAGING_CODEC_MEMORY;
                TIFFClose(tiff);
                if (!clientstate->fp){
                    free(clientstate->data);
                }
                return -1;
            }
            TRACE(("Closing \n"));
            TIFFClose(tiff);
            // reset the clientstate metadata to use it to read out the buffer.
            clientstate->loc = 0;
            clientstate->size = clientstate->eof; // redundant?
        }
    }

    if (state->state == 1 && !clientstate->fp) {
        int read = (int)_tiffReadProc(clientstate, (tdata_t)buffer, (tsize_t)bytes);
        TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
        if (clientstate->loc == clientstate->eof) {
            TRACE(("Hit EOF, calling an end, freeing data"));
            state->errcode = IMAGING_CODEC_END;
            free(clientstate->data);
        }
        return read;
    }

    state->errcode = IMAGING_CODEC_END;
    return 0;
}
Esempio n. 14
0
int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes) {
    TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
    char *filename = "tempfile.tif";
    char *mode = "r";
    TIFF *tiff;

    /* buffer is the encoded file, bytes is the length of the encoded file */
    /*     it all ends up in state->buffer, which is a uint8* from Imaging.h */

    TRACE(("in decoder: bytes %d\n", bytes));
    TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
           state->x, state->y, state->ystep));
    TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
           state->xoff, state->yoff));
    TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
    TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
    TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3]));
    TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
           im->mode, im->type, im->bands, im->xsize, im->ysize));
    TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n",
           im->image8, im->image32, im->image, im->block));
    TRACE(("Image: pixelsize: %d, linesize %d \n",
           im->pixelsize, im->linesize));

    dump_state(clientstate);
    clientstate->size = bytes;
    clientstate->eof = clientstate->size;
    clientstate->loc = 0;
    clientstate->data = (tdata_t)buffer;
    clientstate->flrealloc = 0;
    dump_state(clientstate);

    TIFFSetWarningHandler(NULL);
    TIFFSetWarningHandlerExt(NULL);

    if (clientstate->fp) {
        TRACE(("Opening using fd: %d\n",clientstate->fp));
        lseek(clientstate->fp,0,SEEK_SET); // Sometimes, I get it set to the end.
        tiff = TIFFFdOpen(clientstate->fp, filename, mode);
    } else {
        TRACE(("Opening from string\n"));
        tiff = TIFFClientOpen(filename, mode,
                              (thandle_t) clientstate,
                              _tiffReadProc, _tiffWriteProc,
                              _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
                              _tiffMapProc, _tiffUnmapProc);
    }

    if (!tiff){
        TRACE(("Error, didn't get the tiff\n"));
        state->errcode = IMAGING_CODEC_BROKEN;
        return -1;
    }

    if (clientstate->ifd){
        int rv;
        uint32 ifdoffset = clientstate->ifd;
        TRACE(("reading tiff ifd %u\n", ifdoffset));
        rv = TIFFSetSubDirectory(tiff, ifdoffset);
        if (!rv){
            TRACE(("error in TIFFSetSubDirectory"));
            return -1;
        }
    }

    if (TIFFIsTiled(tiff)) {
        UINT32 x, y, tile_y, row_byte_size;
        UINT32 tile_width, tile_length, current_tile_width;
        UINT8 *new_data;

        TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width);
        TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length);

        // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size
        row_byte_size = (tile_width * state->bits + 7) / 8;
        state->bytes = row_byte_size * tile_length;

        /* overflow check for malloc */
        if (state->bytes > INT_MAX - 1) {
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        /* realloc to fit whole tile */
        new_data = realloc (state->buffer, state->bytes);
        if (!new_data) {
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        state->buffer = new_data;

        TRACE(("TIFFTileSize: %d\n", state->bytes));

        for (y = state->yoff; y < state->ysize; y += tile_length) {
            for (x = state->xoff; x < state->xsize; x += tile_width) {
                if (ReadTile(tiff, x, y, (UINT32*) state->buffer) == -1) {
                    TRACE(("Decode Error, Tile at %dx%d\n", x, y));
                    state->errcode = IMAGING_CODEC_BROKEN;
                    TIFFClose(tiff);
                    return -1;
                }

                TRACE(("Read tile at %dx%d; \n\n", x, y));

                current_tile_width = min(tile_width, state->xsize - x);

                // iterate over each line in the tile and stuff data into image
                for (tile_y = 0; tile_y < min(tile_length, state->ysize - y); tile_y++) {
                    TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width));

                    // UINT8 * bbb = state->buffer + tile_y * row_byte_size;
                    // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));

                    state->shuffle((UINT8*) im->image[tile_y + y] + x * im->pixelsize,
                       state->buffer + tile_y * row_byte_size,
                       current_tile_width
                    );
                }
            }
        }
    } else {
        UINT32 strip_row, row_byte_size;
        UINT8 *new_data;
        UINT32 rows_per_strip;

        TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
        TRACE(("RowsPerStrip: %u \n", rows_per_strip));

        // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size
        row_byte_size = (state->xsize * state->bits + 7) / 8;
        state->bytes = rows_per_strip * row_byte_size;

        TRACE(("StripSize: %d \n", state->bytes));

        /* realloc to fit whole strip */
        new_data = realloc (state->buffer, state->bytes);
        if (!new_data) {
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        state->buffer = new_data;

        for (; state->y < state->ysize; state->y += rows_per_strip) {
            if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) {
                TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0)));
                state->errcode = IMAGING_CODEC_BROKEN;
                TIFFClose(tiff);
                return -1;
            }

            TRACE(("Decoded strip for row %d \n", state->y));

            // iterate over each row in the strip and stuff data into image
            for (strip_row = 0; strip_row < min(rows_per_strip, state->ysize - state->y); strip_row++) {
                TRACE(("Writing data into line %d ; \n", state->y + strip_row));

                // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip);
                // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));

                state->shuffle((UINT8*) im->image[state->y + state->yoff + strip_row] +
                               state->xoff * im->pixelsize,
                               state->buffer + strip_row * row_byte_size,
                               state->xsize);
            }
        }
    }

    TIFFClose(tiff);
    TRACE(("Done Decoding, Returning \n"));
    // Returning -1 here to force ImageFile.load to break, rather than
    // even think about looping back around.
    return -1;
}
Esempio n. 15
0
int
ImagingWebPEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    WEBPCONTEXT* context = (WEBPCONTEXT*) state->context;

    UINT8* buffer;
    UINT8* ptr;
    int y, stride;
    float quality = 75.0F;

    if (!state->state) {
	/* copy image contents to packed buffer and compress it */

	stride = state->xsize * 3;
	buffer = malloc(im->ysize * stride);
	if (!buffer) {
	    state->errcode = IMAGING_CODEC_MEMORY;
	    return -1;
	}

	for (ptr = buffer, y = 0; y < state->ysize; ptr += stride, y++) {
	    state->shuffle(ptr, (UINT8*) im->image[y + state->yoff] +
			   state->xoff * im->pixelsize, state->xsize);
	}

	if (context->quality > 0)
	    quality = (float) context->quality;

	context->output_size = WebPEncodeRGB(buffer,
					     state->xsize, state->ysize,
					     stride, quality,
					     &context->output_data);

	free(buffer);

	if (!context->output_size) {
	    state->errcode = IMAGING_CODEC_BROKEN;
	    return -1;
	}

	state->state++;

	/* keep a pointer to the full buffer */
	context->output_buffer = context->output_data;

    }

    if (context->output_size < bytes) {
	/* copy remaining part to output buffer */
        memcpy(buf, context->output_data, context->output_size);
	state->errcode = IMAGING_CODEC_END;
	free(context->output_buffer);
	return context->output_size;
    } else {
	/* not enough space; fill the buffer and try again next time */
	memcpy(buf, context->output_data, bytes);
	context->output_data += bytes;
	context->output_size -= bytes;
	return bytes;
    }
}