mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +03:00 
			
		
		
		
	find * -type f "-(" -name "*.bdf" -o -name "*.c" -o -name "*.h" -o -name "*.py" -o -name "*.rst" -o -name "*.txt" "-)" -exec sed -e "s/[[:space:]]*$//" -i {} \;
		
	
			
		
			
				
	
	
		
			272 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			272 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * The Python Imaging Library.
 | 
						|
 * $Id$
 | 
						|
 *
 | 
						|
 * decoder for ZIP (deflated) image data.
 | 
						|
 *
 | 
						|
 * history:
 | 
						|
 * 1996-12-14 fl   Created (for PNG)
 | 
						|
 * 1997-01-15 fl   Prepared to read TIFF/ZIP
 | 
						|
 * 2001-11-19 fl   PNG incomplete read patch (from Bernhard Herzog)
 | 
						|
 *
 | 
						|
 * Copyright (c) Fredrik Lundh 1996.
 | 
						|
 * Copyright (c) Secret Labs AB 1997-2001.
 | 
						|
 *
 | 
						|
 * See the README file for information on usage and redistribution.
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#include "Imaging.h"
 | 
						|
 | 
						|
#ifdef	HAVE_LIBZ
 | 
						|
 | 
						|
#include "Zip.h"
 | 
						|
 | 
						|
static const int OFFSET[] = { 7, 3, 3, 1, 1, 0, 0 };
 | 
						|
static const int STARTING_COL[] = { 0, 4, 0, 2, 0, 1, 0 };
 | 
						|
static const int STARTING_ROW[] = { 0, 0, 4, 0, 2, 0, 1 };
 | 
						|
static const int COL_INCREMENT[] = { 8, 8, 4, 4, 2, 2, 1 };
 | 
						|
static const int ROW_INCREMENT[] = { 8, 8, 8, 4, 4, 2, 2 };
 | 
						|
 | 
						|
/* Get the length in bytes of a scanline in the pass specified,
 | 
						|
 * for interlaced images */
 | 
						|
static int get_row_len(ImagingCodecState state, int pass)
 | 
						|
{
 | 
						|
    int row_len = (state->xsize + OFFSET[pass]) / COL_INCREMENT[pass];
 | 
						|
    return ((row_len * state->bits) + 7) / 8;
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/* Decoder								*/
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
int
 | 
						|
ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
 | 
						|
{
 | 
						|
    ZIPSTATE* context = (ZIPSTATE*) state->context;
 | 
						|
    int err;
 | 
						|
    int n;
 | 
						|
    UINT8* ptr;
 | 
						|
    int i, bpp;
 | 
						|
    int row_len;
 | 
						|
 | 
						|
    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) NULL;
 | 
						|
	context->z_stream.zfree = (free_func) NULL;
 | 
						|
	context->z_stream.opaque = (voidpf) NULL;
 | 
						|
 | 
						|
	err = inflateInit(&context->z_stream);
 | 
						|
	if (err < 0) {
 | 
						|
	    state->errcode = IMAGING_CODEC_CONFIG;
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (context->interlaced) {
 | 
						|
	    context->pass = 0;
 | 
						|
	    state->y = STARTING_ROW[context->pass];
 | 
						|
	}
 | 
						|
 | 
						|
	/* Ready to decode */
 | 
						|
	state->state = 1;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    if (context->interlaced) {
 | 
						|
	row_len = get_row_len(state, context->pass);
 | 
						|
    } else {
 | 
						|
	row_len = state->bytes;
 | 
						|
    }
 | 
						|
 | 
						|
    /* 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 =
 | 
						|
	    row_len + 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 = row_len + context->prefix - context->z_stream.avail_out;
 | 
						|
 | 
						|
	if (n < row_len + 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 <= row_len; i++)
 | 
						|
		    state->buffer[i] += state->buffer[i-bpp];
 | 
						|
		break;
 | 
						|
	    case 2:
 | 
						|
		/* up */
 | 
						|
		for (i = 1; i <= row_len; 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 <= row_len; 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 <= row_len; 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 <= row_len; i++)
 | 
						|
		state->buffer[i] += state->buffer[i-bpp];
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Stuff data into the image */
 | 
						|
	if (context->interlaced) {
 | 
						|
	    int col = STARTING_COL[context->pass];
 | 
						|
	    if (state->bits >= 8) {
 | 
						|
		/* Stuff pixels in their correct location, one by one */
 | 
						|
		for (i = 0; i < row_len; i += ((state->bits + 7) / 8)) {
 | 
						|
		    state->shuffle((UINT8*) im->image[state->y] +
 | 
						|
				   col * im->pixelsize,
 | 
						|
				   state->buffer + context->prefix + i, 1);
 | 
						|
		    col += COL_INCREMENT[context->pass];
 | 
						|
		}
 | 
						|
	    } else {
 | 
						|
		/* Handle case with more than a pixel in each byte */
 | 
						|
		int row_bits = ((state->xsize + OFFSET[context->pass])
 | 
						|
		        / COL_INCREMENT[context->pass]) * state->bits;
 | 
						|
		for (i = 0; i < row_bits; i += state->bits) {
 | 
						|
		    UINT8 byte = *(state->buffer + context->prefix + (i / 8));
 | 
						|
		    byte <<= (i % 8);
 | 
						|
		    state->shuffle((UINT8*) im->image[state->y] +
 | 
						|
				   col * im->pixelsize, &byte, 1);
 | 
						|
		    col += COL_INCREMENT[context->pass];
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    /* Find next valid scanline */
 | 
						|
	    state->y += ROW_INCREMENT[context->pass];
 | 
						|
	    while (state->y >= state->ysize || row_len <= 0) {
 | 
						|
		context->pass++;
 | 
						|
		if (context->pass == 7) {
 | 
						|
		    /* Force exit below */
 | 
						|
		    state->y = state->ysize;
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
		state->y = STARTING_ROW[context->pass];
 | 
						|
		row_len = get_row_len(state, context->pass);
 | 
						|
		/* Since we're moving to the "first" line, the previous line
 | 
						|
		 * should be black to make filters work corectly */
 | 
						|
		memset(state->buffer, 0, state->bytes+1);
 | 
						|
	    }
 | 
						|
	} else {
 | 
						|
	    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 */
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#endif
 |