int SplashDecodePng(Splash * splash, png_rw_ptr read_func, void *io_ptr) { int stride; ImageFormat srcFormat; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; png_bytep image_data = NULL; int success = 0; double gamma; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 width, height; int bit_depth, color_type; ImageRect srcRect, dstRect; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { goto done; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { goto done; } if (setjmp(png_ptr->jmpbuf)) { goto done; } png_ptr->io_ptr = io_ptr; png_ptr->read_data_fn = read_func; png_set_sig_bytes(png_ptr, SIG_BYTES); /* we already read the 8 signature bytes */ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] * this may be sub-optimal but this simplifies implementation */ png_set_expand(png_ptr); png_set_tRNS_to_alpha(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); if (!SAFE_TO_ALLOC(rowbytes, height)) { goto done; } if ((image_data = (unsigned char *) malloc(rowbytes * height)) == NULL) { goto done; } if (!SAFE_TO_ALLOC(height, sizeof(png_bytep))) { goto done; } if ((row_pointers = (png_bytepp) malloc(height * sizeof(png_bytep))) == NULL) { goto done; } for (i = 0; i < height; ++i) row_pointers[i] = image_data + i * rowbytes; png_read_image(png_ptr, row_pointers); SplashCleanup(splash); splash->width = width; splash->height = height; if (!SAFE_TO_ALLOC(splash->width, splash->imageFormat.depthBytes)) { goto done; } stride = splash->width * splash->imageFormat.depthBytes; if (!SAFE_TO_ALLOC(splash->height, stride)) { goto done; } splash->frameCount = 1; splash->frames = (SplashImage *) malloc(sizeof(SplashImage) * splash->frameCount); if (splash->frames == NULL) { goto done; } splash->loopCount = 1; splash->frames[0].bitmapBits = malloc(stride * splash->height); if (splash->frames[0].bitmapBits == NULL) { free(splash->frames); goto done; } splash->frames[0].delay = 0; /* FIXME: sort out the real format */ initFormat(&srcFormat, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); srcFormat.byteOrder = BYTE_ORDER_MSBFIRST; initRect(&srcRect, 0, 0, width, height, 1, rowbytes, image_data, &srcFormat); initRect(&dstRect, 0, 0, width, height, 1, stride, splash->frames[0].bitmapBits, &splash->imageFormat); convertRect(&srcRect, &dstRect, CVT_COPY); SplashInitFrameShape(splash, 0); png_read_end(png_ptr, NULL); success = 1; done: free(row_pointers); free(image_data); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return success; }
void *tsi_ReAllocArray(register tsiMemObject *t, void *pIn, size_t size, size_t n) { tsi_Assert(t, SAFE_TO_ALLOC(size, n), T2K_ERR_MEM_MALLOC_FAILED); return tsi_ReAllocMem(t, pIn, size*n); }
int SplashDecodeJpeg(Splash * splash, struct jpeg_decompress_struct *cinfo) { int rowStride, stride; JSAMPARRAY buffer; ImageFormat srcFormat; jpeg_read_header(cinfo, TRUE); jpeg_start_decompress(cinfo); splash->width = cinfo->output_width; splash->height = cinfo->output_height; if (!SAFE_TO_ALLOC(splash->imageFormat.depthBytes, splash->width)) { return 0; } stride = splash->width * splash->imageFormat.depthBytes; if (!SAFE_TO_ALLOC(stride, splash->height)) { return 0; } if (!SAFE_TO_ALLOC(cinfo->output_width, cinfo->output_components)) { return 0; } splash->frameCount = 1; splash->frames = (SplashImage *) malloc(sizeof(SplashImage) * splash->frameCount); if (splash->frames == NULL) { return 0; } memset(splash->frames, 0, sizeof(SplashImage) * splash->frameCount); splash->loopCount = 1; splash->frames[0].delay = 0; splash->frames[0].bitmapBits = malloc(stride * splash->height); if (splash->frames[0].bitmapBits == NULL) { free(splash->frames); return 0; } rowStride = cinfo->output_width * cinfo->output_components; buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, rowStride, 1); if (buffer == NULL) { free(splash->frames[0].bitmapBits); free(splash->frames); return 0; } initFormat(&srcFormat, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000); srcFormat.byteOrder = BYTE_ORDER_LSBFIRST; srcFormat.depthBytes = 3; srcFormat.fixedBits = 0xFF000000; splash->maskRequired = 0; // reset maskRequired as JPEG can't be transparent while (cinfo->output_scanline < cinfo->output_height) { rgbquad_t *out = (rgbquad_t *) ((byte_t *) splash->frames[0].bitmapBits + cinfo->output_scanline * stride); jpeg_read_scanlines(cinfo, buffer, 1); convertLine(buffer[0], sizeof(JSAMPLE) * 3, out, splash->imageFormat.depthBytes, cinfo->output_width, &srcFormat, &splash->imageFormat, CVT_COPY, NULL, 0, NULL, cinfo->output_scanline, 0); } jpeg_finish_decompress(cinfo); return 1; }