mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-01 00:17:27 +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
 |