int /* PRIVATE */ pngx_read_tiff(png_structp png_ptr, png_infop info_ptr, FILE *stream) { struct minitiff_info tiff_info; unsigned int width, height, pixel_size, sample_depth, sample_max; int color_type; int sample_overflow; png_bytepp row_pointers; png_bytep row; unsigned int i, j, k; pngx_err_ptr = png_ptr; num_extra_images = 0; minitiff_init_info(&tiff_info); tiff_info.error_handler = pngx_tiff_error; tiff_info.warning_handler = pngx_tiff_warning; minitiff_read_info(&tiff_info, stream); minitiff_validate_info(&tiff_info); width = (unsigned int)tiff_info.width; height = (unsigned int)tiff_info.height; pixel_size = tiff_info.samples_per_pixel; sample_depth = tiff_info.bits_per_sample; switch (pixel_size) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: png_error(png_ptr, "Unsupported TIFF color space"); return 0; /* avoid "uninitialized color_type" warning */ } if (sample_depth > 16) png_error(png_ptr, "Unsupported TIFF sample depth"); sample_max = (1 << sample_depth) - 1; sample_overflow = 0; png_set_IHDR(png_ptr, info_ptr, width, height, (sample_depth <= 8) ? 8 : 16, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); row_pointers = pngx_malloc_rows(png_ptr, info_ptr, 0); if (sample_depth <= 8) { for (i = 0; i < height; ++i) { row = row_pointers[i]; minitiff_read_row(&tiff_info, row, i, stream); if (sample_depth < 8) { for (j = 0; j < pixel_size * width; ++j) { unsigned int b = row[j]; if (b > sample_max) { b = sample_max; sample_overflow = 1; } row[j] = (png_byte)((b * 255 + sample_max / 2) / sample_max); } } if (tiff_info.photometric == 0) { for (j = 0; j < pixel_size * width; ++j) row[j] = (png_byte)(255 - row[j]); } } } else { for (i = 0; i < height; ++i) { row = row_pointers[i]; minitiff_read_row(&tiff_info, row, i, stream); if (tiff_info.byte_order == 'I') { /* "Intel" byte order => swap row bytes */ for (j = k = 0; j < pixel_size * width; ++j, k+=2) { png_byte b = row[k]; row[k] = row[k + 1]; row[k + 1] = b; } } if (sample_depth < 16) { for (j = k = 0; k < pixel_size * width; ++j, k+=2) { unsigned int b = (row[k] << 8) + row[k + 1]; if (b > sample_max) { b = sample_max; sample_overflow = 1; } b = (b * 65535U + sample_max / 2) / sample_max; row[k] = (png_byte)(b >> 8); row[k + 1] = (png_byte)(b & 255); } } } } if (sample_overflow) png_warning(png_ptr, "Overflow in TIFF samples"); minitiff_destroy_info(&tiff_info); return 1 + num_extra_images; }
int /* PRIVATE */ pngx_read_gif(png_structp png_ptr, png_infop info_ptr, FILE *stream) { /* GIF-specific data */ struct GIFScreen screen; struct GIFImage image; struct GIFExtension ext; struct GIFGraphicCtlExt graphicExt; int code; unsigned char *colorTable; unsigned int numColors; unsigned int transparent; unsigned int numImages; /* PNG-specific data */ png_uint_32 width, height; png_bytepp row_pointers; /* Set up the custom error handling. */ pngx_err_ptr = png_ptr; GIFError = pngx_gif_error; GIFWarning = pngx_gif_warning; /* Read the GIF screen. */ GIFReadScreen(&screen, stream); width = screen.Width; height = screen.Height; /* Set the PNG image type. */ png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Allocate memory. */ row_pointers = pngx_malloc_rows(png_ptr, info_ptr, (int)screen.Background); /* Complete the initialization of the GIF reader. */ GIFInitImage(&image, &screen, row_pointers); GIFInitExtension(&ext, &screen, NULL, 0); transparent = (unsigned int)(-1); numImages = 0; /* Iterate over the GIF file. */ for ( ; ; ) { code = GIFReadNextBlock(&image, &ext, stream); if (code == GIF_IMAGE) /* ',' */ { if (image.Rows != NULL) { /* Complete the PNG info. */ if (image.InterlaceFlag) pngx_set_interlace_type(png_ptr, info_ptr, PNG_INTERLACE_ADAM7); colorTable = GIFGetColorTable(&image, &numColors); pngx_set_GIF_palette(png_ptr, info_ptr, colorTable, numColors); if (transparent < 256) pngx_set_GIF_transparent(png_ptr, info_ptr, transparent); /* Inform the GIF routines not to read the upcoming images. */ image.Rows = NULL; } ++numImages; } else if (code == GIF_EXTENSION && ext.Label == GIF_GRAPHICCTL) /* '!' */ { GIFGetGraphicCtl(&ext, &graphicExt); if (image.Rows != NULL && graphicExt.TransparentFlag) if (transparent >= 256) transparent = graphicExt.Transparent; } else if (code == GIF_TERMINATOR) /* ';' */ break; } /* Deallocate the GIF reader's extension buffer. * Use free() in conjunction with the reader's realloc(). */ if (ext.Buffer != NULL) free(ext.Buffer); /* FIXME: * Deallocate ext.Buffer on error, to prevent memory leaks. */ if (image.Rows != NULL) png_error(png_ptr, "No image in GIF file"); return numImages; }
int /* PRIVATE */ pngx_read_pnm(png_structp png_ptr, png_infop info_ptr, FILE *stream) { pnm_struct pnminfo; unsigned int format, depth, width, height, maxval; unsigned int max_width, num_samples, sample_size; unsigned int *pnmrow; size_t row_size; png_bytepp row_pointers; png_color_8 sig_bit; unsigned int i, j; int failed, overflow; /* Read the PNM header. */ if (pnm_fget_header(&pnminfo, stream) != 1) return 0; /* not PNM */ format = pnminfo.format; depth = pnminfo.depth; width = pnminfo.width; height = pnminfo.height; maxval = pnminfo.maxval; if (format > PNM_P6) png_error(png_ptr, "Can't handle PNM formats newer than PPM (\"P6\")"); max_width = (sizeof(size_t) <= sizeof(unsigned int)) ? UINT_MAX / sizeof(unsigned int) / depth : UINT_MAX; #if UINT_MAX > PNGX_PNM_LENGTH_MAX if (max_width > PNGX_PNM_LENGTH_MAX) max_width = PNGX_PNM_LENGTH_MAX; #endif if (width > max_width) png_error(png_ptr, "Can't handle exceedingly large PNM dimensions"); sample_size = 1; row_size = num_samples = depth * width; if (maxval > 65535) png_error(png_ptr, "Can't handle PNM samples larger than 16 bits"); else if (maxval > 255) { sample_size = 2; row_size *= 2; } /* Set the PNG image type. */ png_set_IHDR(png_ptr, info_ptr, width, height, (maxval <= 255) ? 8 : 16, (depth == 1) ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); for (i = 1, j = 2; j - 1 < maxval; ++i, j <<= 1) { } if (j - 1 != maxval) png_warning(png_ptr, "Possibly inexact sample conversion from PNM to PNG"); else if (i % 8 != 0 && (depth > 1 || 8 % i != 0)) { sig_bit.red = sig_bit.green = sig_bit.blue = sig_bit.gray = (png_byte)i; sig_bit.alpha = 0; png_set_sBIT(png_ptr, info_ptr, &sig_bit); } /* Allocate memory. */ row_pointers = pngx_malloc_rows(png_ptr, info_ptr, -1); if ((format >= PNM_P4) && (maxval == 255 || maxval == 65535)) pnmrow = NULL; /* can read raw data directly into row_pointers */ else pnmrow = (unsigned int *) png_malloc(png_ptr, num_samples * sizeof(unsigned int)); /* Read the image data. */ failed = 0; overflow = 0; if (pnmrow != NULL) { for (i = 0; i < height; ++i) { if (pnm_fget_values(&pnminfo, pnmrow, 1, stream) <= 0) failed = 1; /* Transfer the samples, even on partial (unsuccessful) reads. */ if (maxval <= 255) { for (j = 0; j < num_samples; ++j) { unsigned int val = pnmrow[j]; if (val > maxval) { val = 255; overflow = 1; } else if (maxval != 255) val = (val * 255 + maxval/2) / maxval; row_pointers[i][j] = (png_byte)val; } } else /* maxval > 255 */ { for (j = 0; j < num_samples; ++j) { png_uint_32 val = pnmrow[j]; if (val > maxval) { val = 65535; overflow = 1; } else if (maxval != 65535) val = (val * 65535 + maxval/2) / maxval; row_pointers[i][2 * j] = (png_byte)(val >> 8); row_pointers[i][2 * j + 1] = (png_byte)(val & 0xff); } } if (failed) break; } } else /* read the raw data directly */ { for (i = 0; i < height; ++i)