From 81fd113506e4c5833e64998651f232734ebb2cb7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 20 Jun 2019 23:40:51 +0200 Subject: [PATCH] Support TGA reading We add PHP bindings for libgd's features to read TGA files, which are available as of libgd 2.1.0. As PHP's bundled libgd doesn't yet include the respective features of the external libgd, we add these. Since TGA has no easily recognizable file signature, we don't add TGA support for imagecreatefromstring() or getimagesize() and friends. --- NEWS | 3 + UPGRADING | 6 + ext/gd/config.m4 | 4 +- ext/gd/config.w32 | 3 +- ext/gd/gd.c | 31 ++ ext/gd/libgd/gd.h | 4 + ext/gd/libgd/gd_tga.c | 360 ++++++++++++++++++ ext/gd/libgd/gd_tga.h | 52 +++ ext/gd/php_gd.h | 5 + ext/gd/tests/imagecreatefromtga.png | Bin 0 -> 2559 bytes ext/gd/tests/imagecreatefromtga_basic.phpt | 17 + ext/gd/tests/imagecreatefromtga_basic.tga | Bin 0 -> 90444 bytes .../tests/imagecreatefromtga_variation.phpt | 17 + ext/gd/tests/imagecreatefromtga_variation.tga | Bin 0 -> 9987 bytes ext/gd/tests/imagetypes_tga.phpt | 12 + 15 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 ext/gd/libgd/gd_tga.c create mode 100644 ext/gd/libgd/gd_tga.h create mode 100644 ext/gd/tests/imagecreatefromtga.png create mode 100644 ext/gd/tests/imagecreatefromtga_basic.phpt create mode 100644 ext/gd/tests/imagecreatefromtga_basic.tga create mode 100644 ext/gd/tests/imagecreatefromtga_variation.phpt create mode 100644 ext/gd/tests/imagecreatefromtga_variation.tga create mode 100644 ext/gd/tests/imagetypes_tga.phpt diff --git a/NEWS b/NEWS index 50402e8411..ef7507d088 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,9 @@ PHP NEWS - Date: . Fixed #69044 (discrepency between time and microtime). (krakjoe) +- GD: + . Added TGA read support. (cmb) + - Opcache: . Fixed bug #78106 (Path resolution fails if opcache disabled during request). (Nikita) diff --git a/UPGRADING b/UPGRADING index 4acfa3e775..be14f0699b 100644 --- a/UPGRADING +++ b/UPGRADING @@ -354,6 +354,12 @@ PHP 7.4 UPGRADE NOTES exception that it ignores overloaded array casts, such as used by ArrayObject. +- GD: + . Added imagecreatefromtga() function, which allows to read images in TGA + format. TGA support is now also indicated by gd_info() and imagetypes(). + Note that TGA images are not recognized by imagecreatefromstring() and + getimagesize(). + - OpenSSL: . Added openssl_x509_verify(mixed cert, mixed key) function that verifies the signature of the certificate using a public key. A wrapper around the diff --git a/ext/gd/config.m4 b/ext/gd/config.m4 index a13313c8e8..742ed412cd 100644 --- a/ext/gd/config.m4 +++ b/ext/gd/config.m4 @@ -126,6 +126,7 @@ AC_DEFUN([PHP_GD_CHECK_VERSION],[ PHP_CHECK_LIBRARY(gd, gdImageCreateFromJpeg, [AC_DEFINE(HAVE_GD_JPG, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) PHP_CHECK_LIBRARY(gd, gdImageCreateFromXpm, [AC_DEFINE(HAVE_GD_XPM, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) PHP_CHECK_LIBRARY(gd, gdImageCreateFromBmp, [AC_DEFINE(HAVE_GD_BMP, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) + PHP_CHECK_LIBRARY(gd, gdImageCreateFromTga, [AC_DEFINE(HAVE_GD_TGA, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) PHP_CHECK_LIBRARY(gd, gdImageStringFT, [AC_DEFINE(HAVE_GD_FREETYPE, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) PHP_CHECK_LIBRARY(gd, gdVersionString, [AC_DEFINE(HAVE_GD_LIBVERSION, 1, [ ])], [], [ $GD_SHARED_LIBADD ]) ]) @@ -146,7 +147,7 @@ if test "$PHP_GD" != "no"; then libgd/gd_topal.c libgd/gd_gif_in.c libgd/gd_xbm.c libgd/gd_gif_out.c libgd/gd_security.c \ libgd/gd_filter.c libgd/gd_pixelate.c libgd/gd_rotate.c libgd/gd_color_match.c \ libgd/gd_transform.c libgd/gd_crop.c libgd/gd_interpolation.c libgd/gd_matrix.c \ - libgd/gd_bmp.c" + libgd/gd_bmp.c libgd/gd_tga.c" dnl check for fabsf and floorf which are available since C99 AC_CHECK_FUNCS(fabsf floorf) @@ -155,6 +156,7 @@ dnl These are always available with bundled library AC_DEFINE(HAVE_GD_BUNDLED, 1, [ ]) AC_DEFINE(HAVE_GD_PNG, 1, [ ]) AC_DEFINE(HAVE_GD_BMP, 1, [ ]) + AC_DEFINE(HAVE_GD_TGA, 1, [ ]) dnl Various checks for GD features PHP_GD_ZLIB diff --git a/ext/gd/config.w32 b/ext/gd/config.w32 index bd73f572d3..6695976d0e 100644 --- a/ext/gd/config.w32 +++ b/ext/gd/config.w32 @@ -40,7 +40,7 @@ if (PHP_GD != "no") { gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \ gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c gd_xbm.c gd_security.c gd_transform.c \ gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c \ - gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c", "gd"); + gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c", "gd"); AC_DEFINE('HAVE_LIBGD', 1, 'GD support'); ADD_FLAG("CFLAGS_GD", " \ /D HAVE_GD_DYNAMIC_CTX_EX=1 \ @@ -63,6 +63,7 @@ if (PHP_GD != "no") { /D HAVE_GD_XPM \ /D HAVE_GD_FREETYPE=1 \ /D HAVE_GD_BMP \ +/D HAVE_GD_TGA \ /D HAVE_LIBGD13=1 \ /D HAVE_LIBGD15=1 \ /D HAVE_LIBGD20=1 \ diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 1bdcba71fb..96c0e23edf 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -356,6 +356,12 @@ ZEND_BEGIN_ARG_INFO(arginfo_imagecreatefrombmp, 0) ZEND_END_ARG_INFO() #endif +#if defined(HAVE_GD_TGA) +ZEND_BEGIN_ARG_INFO(arginfo_imagecreatefromtga, 0) + ZEND_ARG_INFO(0, filename) +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_INFO_EX(arginfo_imagexbm, 0, 0, 2) ZEND_ARG_INFO(0, im) ZEND_ARG_INFO(0, filename) @@ -942,6 +948,9 @@ static const zend_function_entry gd_functions[] = { #ifdef HAVE_GD_BMP PHP_FE(imagecreatefrombmp, arginfo_imagecreatefrombmp) #endif +#ifdef HAVE_GD_TGA + PHP_FE(imagecreatefromtga, arginfo_imagecreatefromtga) +#endif #ifdef HAVE_GD_PNG PHP_FE(imagepng, arginfo_imagepng) #endif @@ -1109,6 +1118,7 @@ PHP_MINIT_FUNCTION(gd) REGISTER_LONG_CONSTANT("IMG_XPM", PHP_IMG_XPM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMG_WEBP", PHP_IMG_WEBP, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMG_BMP", PHP_IMG_BMP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IMG_TGA", PHP_IMG_TGA, CONST_CS | CONST_PERSISTENT); /* special colours for gd */ REGISTER_LONG_CONSTANT("IMG_COLOR_TILED", gdTiled, CONST_CS | CONST_PERSISTENT); @@ -1316,6 +1326,9 @@ PHP_MINFO_FUNCTION(gd) #endif #ifdef HAVE_GD_BMP php_info_print_table_row(2, "BMP Support", "enabled"); +#endif +#ifdef HAVE_GD_TGA + php_info_print_table_row(2, "TGA Read Support", "enabled"); #endif php_info_print_table_end(); DISPLAY_INI_ENTRIES(); @@ -1373,6 +1386,11 @@ PHP_FUNCTION(gd_info) #else add_assoc_bool(return_value, "BMP Support", 0); #endif +#ifdef HAVE_GD_TGA + add_assoc_bool(return_value, "TGA Read Support", 1); +#else + add_assoc_bool(return_value, "TGA Read Support", 0); +#endif #if defined(USE_GD_JISX0208) add_assoc_bool(return_value, "JIS-mapped Japanese Font Support", 1); #else @@ -2203,6 +2221,9 @@ PHP_FUNCTION(imagetypes) #ifdef HAVE_GD_BMP ret |= PHP_IMG_BMP; #endif +#ifdef HAVE_GD_TGA + ret |= PHP_IMG_TGA; +#endif if (zend_parse_parameters_none() == FAILURE) { return; @@ -2599,6 +2620,16 @@ PHP_FUNCTION(imagecreatefrombmp) /* }}} */ #endif +#if defined(HAVE_GD_TGA) +/* {{{ proto resource imagecreatefromtga(string filename) + Create a new image from TGA file or URL */ +PHP_FUNCTION(imagecreatefromtga) +{ + _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_TGA, "TGA", gdImageCreateFromTga, gdImageCreateFromTgaCtx); +} +/* }}} */ +#endif + /* {{{ _php_image_output */ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)()) diff --git a/ext/gd/libgd/gd.h b/ext/gd/libgd/gd.h index 30f59b38f6..461024f0f7 100644 --- a/ext/gd/libgd/gd.h +++ b/ext/gd/libgd/gd.h @@ -364,6 +364,10 @@ gdImagePtr gdImageCreateFromWebp(FILE *fd); gdImagePtr gdImageCreateFromWebpCtx(gdIOCtxPtr in); gdImagePtr gdImageCreateFromWebpPtr (int size, void *data); +gdImagePtr gdImageCreateFromTga( FILE * fp ); +gdImagePtr gdImageCreateFromTgaCtx(gdIOCtx* ctx); +gdImagePtr gdImageCreateFromTgaPtr(int size, void *data); + gdImagePtr gdImageCreateFromBmp (FILE * inFile); gdImagePtr gdImageCreateFromBmpPtr (int size, void *data); gdImagePtr gdImageCreateFromBmpCtx (gdIOCtxPtr infile); diff --git a/ext/gd/libgd/gd_tga.c b/ext/gd/libgd/gd_tga.c new file mode 100644 index 0000000000..67e77f7b98 --- /dev/null +++ b/ext/gd/libgd/gd_tga.c @@ -0,0 +1,360 @@ +/** + * File: TGA Input + * + * Read TGA images. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "gd_tga.h" +#include "gd.h" +#include "gd_errors.h" +#include "gdhelpers.h" + +/* + Function: gdImageCreateFromTga + + Creates a gdImage from a TGA file + + Parameters: + + infile - Pointer to TGA binary file + */ +gdImagePtr gdImageCreateFromTga(FILE *fp) +{ + gdImagePtr image; + gdIOCtx* in = gdNewFileCtx(fp); + if (in == NULL) return NULL; + image = gdImageCreateFromTgaCtx(in); + in->gd_free( in ); + return image; +} + +/* + Function: gdImageCreateFromTgaPtr +*/ +gdImagePtr gdImageCreateFromTgaPtr(int size, void *data) +{ + gdImagePtr im; + gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0); + if (in == NULL) return NULL; + im = gdImageCreateFromTgaCtx(in); + in->gd_free(in); + return im; +} + + +/* + Function: gdImageCreateFromTgaCtx + + Creates a gdImage from a gdIOCtx referencing a TGA binary file. + + Parameters: + ctx - Pointer to a gdIOCtx structure + */ +gdImagePtr gdImageCreateFromTgaCtx(gdIOCtx* ctx) +{ + int bitmap_caret = 0; + oTga *tga = NULL; + /* int pixel_block_size = 0; + int image_block_size = 0; */ + volatile gdImagePtr image = NULL; + int x = 0; + int y = 0; + + tga = (oTga *) gdMalloc(sizeof(oTga)); + if (!tga) { + return NULL; + } + + tga->bitmap = NULL; + tga->ident = NULL; + + if (read_header_tga(ctx, tga) < 0) { + free_tga(tga); + return NULL; + } + + /*TODO: Will this be used? + pixel_block_size = tga->bits / 8; + image_block_size = (tga->width * tga->height) * pixel_block_size; + */ + + if (read_image_tga(ctx, tga) < 0) { + free_tga(tga); + return NULL; + } + + image = gdImageCreateTrueColor((int)tga->width, (int)tga->height ); + + if (image == 0) { + free_tga( tga ); + return NULL; + } + + /*! \brief Populate GD image object + * Copy the pixel data from our tga bitmap buffer into the GD image + * Disable blending and save the alpha channel per default + */ + if (tga->alphabits) { + gdImageAlphaBlending(image, 0); + gdImageSaveAlpha(image, 1); + } + + /* TODO: use alphabits as soon as we support 24bit and other alpha bps (ie != 8bits) */ + for (y = 0; y < tga->height; y++) { + register int *tpix = image->tpixels[y]; + for ( x = 0; x < tga->width; x++, tpix++) { + if (tga->bits == TGA_BPP_24) { + *tpix = gdTrueColor(tga->bitmap[bitmap_caret + 2], tga->bitmap[bitmap_caret + 1], tga->bitmap[bitmap_caret]); + bitmap_caret += 3; + } else if (tga->bits == TGA_BPP_32 && tga->alphabits) { + register int a = tga->bitmap[bitmap_caret + 3]; + + *tpix = gdTrueColorAlpha(tga->bitmap[bitmap_caret + 2], tga->bitmap[bitmap_caret + 1], tga->bitmap[bitmap_caret], gdAlphaMax - (a >> 1)); + bitmap_caret += 4; + } + } + } + + if (tga->flipv && tga->fliph) { + gdImageFlipBoth(image); + } else if (tga->flipv) { + gdImageFlipVertical(image); + } else if (tga->fliph) { + gdImageFlipHorizontal(image); + } + + free_tga(tga); + + return image; +} + +/*! \brief Reads a TGA header. + * Reads the header block from a binary TGA file populating the referenced TGA structure. + * \param ctx Pointer to TGA binary file + * \param tga Pointer to TGA structure + * \return int 1 on sucess, -1 on failure + */ +int read_header_tga(gdIOCtx *ctx, oTga *tga) +{ + + unsigned char header[18]; + + if (gdGetBuf(header, sizeof(header), ctx) < 18) { + gd_error("fail to read header"); + return -1; + } + + tga->identsize = header[0]; + tga->colormaptype = header[1]; + tga->imagetype = header[2]; + tga->colormapstart = header[3] + (header[4] << 8); + tga->colormaplength = header[5] + (header[6] << 8); + tga->colormapbits = header[7]; + tga->xstart = header[8] + (header[9] << 8); + tga->ystart = header[10] + (header[11] << 8); + tga->width = header[12] + (header[13] << 8); + tga->height = header[14] + (header[15] << 8); + tga->bits = header[16]; + tga->alphabits = header[17] & 0x0f; + tga->fliph = (header[17] & 0x10) ? 1 : 0; + tga->flipv = (header[17] & 0x20) ? 0 : 1; + +#if DEBUG + printf("format bps: %i\n", tga->bits); + printf("flip h/v: %i / %i\n", tga->fliph, tga->flipv); + printf("alpha: %i\n", tga->alphabits); + printf("wxh: %i %i\n", tga->width, tga->height); +#endif + + if (!((tga->bits == TGA_BPP_24 && tga->alphabits == 0) + || (tga->bits == TGA_BPP_32 && tga->alphabits == 8))) + { + gd_error_ex(GD_WARNING, "gd-tga: %u bits per pixel with %u alpha bits not supported\n", + tga->bits, tga->alphabits); + return -1; + } + + tga->ident = NULL; + + if (tga->identsize > 0) { + tga->ident = (char *) gdMalloc(tga->identsize * sizeof(char)); + if(tga->ident == NULL) { + return -1; + } + + gdGetBuf(tga->ident, tga->identsize, ctx); + } + + return 1; +} + +/*! \brief Reads a TGA image data into buffer. + * Reads the image data block from a binary TGA file populating the referenced TGA structure. + * \param ctx Pointer to TGA binary file + * \param tga Pointer to TGA structure + * \return int 0 on sucess, -1 on failure + */ +int read_image_tga( gdIOCtx *ctx, oTga *tga ) +{ + int pixel_block_size = (tga->bits / 8); + int image_block_size; + int* decompression_buffer = NULL; + unsigned char* conversion_buffer = NULL; + int buffer_caret = 0; + int bitmap_caret = 0; + int i = 0; + int encoded_pixels; + int rle_size; + + if(overflow2(tga->width, tga->height)) { + return -1; + } + + if(overflow2(tga->width * tga->height, pixel_block_size)) { + return -1; + } + + image_block_size = (tga->width * tga->height) * pixel_block_size; + if(overflow2(image_block_size, sizeof(int))) { + return -1; + } + + /*! \todo Add more image type support. + */ + if (tga->imagetype != TGA_TYPE_RGB && tga->imagetype != TGA_TYPE_RGB_RLE) + return -1; + + /*! \brief Allocate memmory for image block + * Allocate a chunk of memory for the image block to be passed into. + */ + tga->bitmap = (int *) gdMalloc(image_block_size * sizeof(int)); + if (tga->bitmap == NULL) + return -1; + + switch (tga->imagetype) { + case TGA_TYPE_RGB: + /*! \brief Read in uncompressed RGB TGA + * Chunk load the pixel data from an uncompressed RGB type TGA. + */ + conversion_buffer = (unsigned char *) gdMalloc(image_block_size * sizeof(unsigned char)); + if (conversion_buffer == NULL) { + return -1; + } + + if (gdGetBuf(conversion_buffer, image_block_size, ctx) != image_block_size) { + gd_error("gd-tga: premature end of image data\n"); + gdFree(conversion_buffer); + return -1; + } + + while (buffer_caret < image_block_size) { + tga->bitmap[buffer_caret] = (int) conversion_buffer[buffer_caret]; + buffer_caret++; + } + + gdFree(conversion_buffer); + break; + + case TGA_TYPE_RGB_RLE: + /*! \brief Read in RLE compressed RGB TGA + * Chunk load the pixel data from an RLE compressed RGB type TGA. + */ + decompression_buffer = (int*) gdMalloc(image_block_size * sizeof(int)); + if (decompression_buffer == NULL) { + return -1; + } + conversion_buffer = (unsigned char *) gdMalloc(image_block_size * sizeof(unsigned char)); + if (conversion_buffer == NULL) { + gd_error("gd-tga: premature end of image data\n"); + gdFree( decompression_buffer ); + return -1; + } + + rle_size = gdGetBuf(conversion_buffer, image_block_size, ctx); + if (rle_size <= 0) { + gdFree(conversion_buffer); + gdFree(decompression_buffer); + return -1; + } + + buffer_caret = 0; + + while( buffer_caret < rle_size) { + decompression_buffer[buffer_caret] = (int)conversion_buffer[buffer_caret]; + buffer_caret++; + } + + buffer_caret = 0; + + while( bitmap_caret < image_block_size ) { + + if (buffer_caret + pixel_block_size > rle_size) { + gdFree( decompression_buffer ); + gdFree( conversion_buffer ); + return -1; + } + + if ((decompression_buffer[buffer_caret] & TGA_RLE_FLAG) == TGA_RLE_FLAG) { + encoded_pixels = ( ( decompression_buffer[ buffer_caret ] & ~TGA_RLE_FLAG ) + 1 ); + buffer_caret++; + + if ((bitmap_caret + (encoded_pixels * pixel_block_size)) > image_block_size + || buffer_caret + pixel_block_size > rle_size) { + gdFree( decompression_buffer ); + gdFree( conversion_buffer ); + return -1; + } + + for (i = 0; i < encoded_pixels; i++) { + memcpy(tga->bitmap + bitmap_caret, decompression_buffer + buffer_caret, pixel_block_size * sizeof(int)); + bitmap_caret += pixel_block_size; + } + buffer_caret += pixel_block_size; + + } else { + encoded_pixels = decompression_buffer[ buffer_caret ] + 1; + buffer_caret++; + + if ((bitmap_caret + (encoded_pixels * pixel_block_size)) > image_block_size + || buffer_caret + (encoded_pixels * pixel_block_size) > rle_size) { + gdFree( decompression_buffer ); + gdFree( conversion_buffer ); + return -1; + } + + memcpy(tga->bitmap + bitmap_caret, decompression_buffer + buffer_caret, encoded_pixels * pixel_block_size * sizeof(int)); + bitmap_caret += (encoded_pixels * pixel_block_size); + buffer_caret += (encoded_pixels * pixel_block_size); + } + } + gdFree( decompression_buffer ); + gdFree( conversion_buffer ); + break; + } + + return 1; +} + +/*! \brief Cleans up a TGA structure. + * Dereferences the bitmap referenced in a TGA structure, then the structure itself + * \param tga Pointer to TGA structure + */ +void free_tga(oTga * tga) +{ + if (tga) { + if (tga->ident) + gdFree(tga->ident); + if (tga->bitmap) + gdFree(tga->bitmap); + gdFree(tga); + } +} diff --git a/ext/gd/libgd/gd_tga.h b/ext/gd/libgd/gd_tga.h new file mode 100644 index 0000000000..297f3dc99d --- /dev/null +++ b/ext/gd/libgd/gd_tga.h @@ -0,0 +1,52 @@ +#ifndef __TGA_H +#define __TGA_H 1 + +#include "gd.h" +#include "gdhelpers.h" + +#include "gd_intern.h" + +typedef struct oTga_ { + uint8_t identsize; // size of ID field that follows 18 uint8_t header (0 usually) + uint8_t colormaptype; // type of colour map 0=none, 1=has palette [IGNORED] Adrian requested no support + uint8_t imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + int colormapstart; // first colour map entry in palette [IGNORED] Adrian requested no support + int colormaplength; // number of colours in palette [IGNORED] Adrian requested no support + uint8_t colormapbits; // number of bits per palette entry 15,16,24,32 [IGNORED] Adrian requested no support + + int xstart; // image x origin + int ystart; // image y origin + int width; // image width in pixels + int height; // image height in pixels + uint8_t bits; // image bits per pixel 8,16,24,32 + uint8_t alphabits; // alpha bits (low 4bits of header 17) + uint8_t fliph; // horizontal or vertical + uint8_t flipv; // flip + char *ident; // identifcation tag string + int *bitmap; // bitmap data + +} oTga; + +#define TGA_TYPE_NO_IMAGE 0 +#define TGA_TYPE_INDEXED 1 +#define TGA_TYPE_RGB 2 +#define TGA_TYPE_GREYSCALE 3 +#define TGA_TYPE_INDEXED_RLE 9 +#define TGA_TYPE_RGB_RLE 10 +#define TGA_TYPE_GREYSCALE_RLE 11 +#define TGA_TYPE_INDEXED_HUFFMAN_DELTA_RLE 32 +#define TGA_TYPE_RGB_HUFFMAN_DELTA_QUADTREE_RLE 33 + +#define TGA_BPP_8 8 +#define TGA_BPP_16 16 +#define TGA_BPP_24 24 +#define TGA_BPP_32 32 + +#define TGA_RLE_FLAG 128 + +int read_header_tga(gdIOCtx *ctx, oTga *tga); +int read_image_tga(gdIOCtx *ctx, oTga *tga); +void free_tga(oTga *tga); + +#endif //__TGA_H diff --git a/ext/gd/php_gd.h b/ext/gd/php_gd.h index 982decd064..e6db0c0ec0 100644 --- a/ext/gd/php_gd.h +++ b/ext/gd/php_gd.h @@ -47,6 +47,7 @@ #define PHP_GDIMG_TYPE_GD2PART 10 #define PHP_GDIMG_TYPE_WEBP 11 #define PHP_GDIMG_TYPE_BMP 12 +#define PHP_GDIMG_TYPE_TGA 13 #define PHP_IMG_GIF 1 #define PHP_IMG_JPG 2 @@ -56,6 +57,7 @@ #define PHP_IMG_XPM 16 #define PHP_IMG_WEBP 32 #define PHP_IMG_BMP 64 +#define PHP_IMG_TGA 128 #ifdef PHP_WIN32 # define PHP_GD_API __declspec(dllexport) @@ -163,6 +165,9 @@ PHP_FUNCTION(imagecreatefromgd2part); #if defined(HAVE_GD_BMP) PHP_FUNCTION(imagecreatefrombmp); #endif +#if defined(HAVE_GD_TGA) +PHP_FUNCTION(imagecreatefromtga); +#endif #if defined(HAVE_GD_XPM) PHP_FUNCTION(imagecreatefromxpm); #endif diff --git a/ext/gd/tests/imagecreatefromtga.png b/ext/gd/tests/imagecreatefromtga.png new file mode 100644 index 0000000000000000000000000000000000000000..4a3060d974e426da033964e2a53d03b4713630e1 GIT binary patch literal 2559 zcma)8dpHyN8{Z`y97ZEWlao@%btt#FRa7o>KW^pLF-wfXjOI3VP;)CCa*&d1VIh~? z9TSB)2{YTwrAQkyi^=u3^Y`!kE`Pl5=lQ(f=lgxW&*$^L&-31Ma=0WVp(p_W0Hka# zTe%2vKp3}v5EbU^B95vM#BW~qiUa_p$$tm%cMWMJVXe-_>YQ6l;WBe1O9>5p%i|uu zYveYjl~)+rzcg+!YFlVaW0V|kluiWDk@c zf(?jB*O=uRJ$+lJ_0#X*zR%rQ<92Q}Ydw>-2_sP(au!vs>(GnwxQQp|g?Lu1*|d?V zsg>2k_+X}z%0rYyT3RaT_}sIkw3yQ>$Cdw`_UBPMfb57WHwT}Mch_TX(0`(BFht3> z546j?+B07rl*bSQ|KclWi>@{%t?$2nA@v~C<(L)u0#KIcWNBq8CnF0H`9~TvUGc~3 zB$8|_5A99@$`}sW}?m%28 znJYRoUyzv2me}}Cv;gyCv;B40FFzM6Re>UAnMD6ga+i(k9*gz;mEF{H-fUJ-9tTJg z8~dxz{*MF9cJC(v`T7GQGd10MUHu1M0^?L)aoXXX=O@Yi`^H&V{tceDnhFWfC9TQF z*<03vxFWeoY|}xnl#4=1{c4ZOOhV6l_-=;PQdIduA^rS8+@ z5qOST4+C`e8($?+($kOf26akf&*;^Vqi#>D#8pX6gibnFCV~IeNCkhF)$R?9&D2CN zcee?s1fuw5Rco3XTH^ugx}4qr(G~-}QG#$C=Z!vBy2QIO6h$SAkkOr(g`o*tAITd> zDy62Px0h1v%GO*y7pJFG)WePwJw2cylKMz9a)`#Hv@8iL@(C1x3lvOEdd5puyJ*4y z1sh8gf790ay>=EcTKD5-+xYF}jgs{Zyfb*R(J|bE-B|0>DRNb;aw5bdcWN_oruvE= z@%@EUW*Un2V7Zc+M;bcxZ zt>oRrx$@YOtQv`25Ia%ZXkyD?6#7$S`awZpIV$Ufv5JU)g*T}W%dA6j z13)e-f|B7I9TWLgbh84MU8SM^+NcfAZ&lpjDBuq7y58ZeCSLO`CaGciUT?r4&NJXx z;5jYBqc_iNHU3&0Hf3)6u)}yzb%^jOY?RioP0ZVtmbMvwZtziUY5i_-|Dc*pe4*w$ zJIk+>dH184M+9b{nFinXI1r5gL~O>jY3B_BzeN{aR9dbe>_mq~-!}Ies`=%uH_Po7 zgYe+&ZfzoNr+ixqtMRs$nxuy>YQM<#K1vAQbKu! z#tTE-R>zk^L1(Jsrm(^(aOhHy!Z4}%DTZObQi~!Mb`(<;G~8!*uJALP6Nt|2FqnJd zoVwwsa5&&%XSCN!bu4QyvmE37hELIBwI>&*U%S=*U7!0>=3tj(AY2)%-Z%PzZ(BEZ zIQtw9Bk!~AxXue=-VaAycYfg zHx2fcx%LQ$>xB9Z{JQ-!+Y~&!{o)7Q-P3jY=9l6yKMcuj&vGQ9-9oGGB-a?4yS5KU z;oBl>>46T~AfbU%N4aoixBF#5WuEFnP>!w| zcZ60H#8vM6A%h$$bchMa;WkCCQ?ggRTT2}x$tttqVcl({W8R3 zSk=)MSVn@5cj=o*#LQ_Ep!t%ZYW$OIZ?WX{GW8xKQx zQGsIf&dn~GK5q-}F=*YeA=xcV1*P=aC%k>upTxr^``jVTUZy*q+%=Tk5bO1{cV&!5 z-og0$zPuFHvFjV9q>rHPn(-P)ufZ+o?Gycz@6vf` zws^SmZwZ%5O2@d?+xFl!7njP0)?*7LIh1dFdcotp-ns=MY&_zWe(Q7J`t$m(cIU;Q z6WTh+YBBo}Y1B*==7#lShy=!j-O9fkXw6AyikEvGKK3eE6k4yMfUM5QkW%k^h*uQQ zqS5U4H@@LNBpR8^@Ce-K%U(EL$ClD5)RIj&(wz&mz{b%l3u;73ak*cw^hZFeycYcXVPY2|*>5UKg#m;b(;{KM%U1Z`fF(wE%<6mE0?8*2xv+VlR& F{{qWv-FyH5 literal 0 HcmV?d00001 diff --git a/ext/gd/tests/imagecreatefromtga_basic.phpt b/ext/gd/tests/imagecreatefromtga_basic.phpt new file mode 100644 index 0000000000..3025e522d5 --- /dev/null +++ b/ext/gd/tests/imagecreatefromtga_basic.phpt @@ -0,0 +1,17 @@ +--TEST-- +imagecreatefromtga() - basic functionality +--SKIPIF-- + +--FILE-- + +--EXPECT-- +The images are equal. diff --git a/ext/gd/tests/imagecreatefromtga_basic.tga b/ext/gd/tests/imagecreatefromtga_basic.tga new file mode 100644 index 0000000000000000000000000000000000000000..5f11f5a080f3424dff6ff368db6af140a5777e23 GIT binary patch literal 90444 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 literal 0 HcmV?d00001 diff --git a/ext/gd/tests/imagecreatefromtga_variation.phpt b/ext/gd/tests/imagecreatefromtga_variation.phpt new file mode 100644 index 0000000000..39dd4b0b59 --- /dev/null +++ b/ext/gd/tests/imagecreatefromtga_variation.phpt @@ -0,0 +1,17 @@ +--TEST-- +imagecreatefromtga() - RLE file reading +--SKIPIF-- + +--FILE-- + +--EXPECT-- +The images are equal. diff --git a/ext/gd/tests/imagecreatefromtga_variation.tga b/ext/gd/tests/imagecreatefromtga_variation.tga new file mode 100644 index 0000000000000000000000000000000000000000..ce845ad0c3da65205af25854d64568b1cf0921e3 GIT binary patch literal 9987 zcmeI2J!~9R5Xbkx ziiRRbk%9(oq!dtCIspYA&6UugGcC>X|IOQdZ+$+;#>5ek&eFVnJ3DVa{%>aX?a5Je zF>-%5qwk}eQT$4wzvw%Lr!o5$L%T1%_;U0&GrMhYD|*=1u+QBMI7bBz5GWAXUI?5o z4)=h152)YuP~W$``}B?1quuDQ!tKvI-d*GdmoNVj?N0AU(FV5-mWdwpH55x49>GD6 z=%BBmXlU4mV>@qJ8fX!=CL?@={ z0-|RLqE&j)8olUxtrw;AqBVNamHEBs60Ks5R&l9p6>VC@T4)u!Z+{gD%n-xb5tYDzPz)HDn9RtO}K-2&bfLTDa$ReF=%5-@43+;@(Xqh_Lqg5;e zg}THltzs{E>BBIs4hP5RP*Wqxy6Qz9`Y(v8pI6+HwtX$ra zy1k}`<+7Ep?x=h3^=RRT3_QRAG z_yH!{gxCD>ho1(boNM2tG;8-@MK-H=sqwzy_Dkd} zeC*AO?;PyiJI7egrh5aA*tASEv0P|sHWdv;37nkl7;GWQvslElsh1w>E)mVkrK5Wr zvyT~j8_(=*6BF=71Iw<4W?fOstUs?=BFaQ*Da#xiBX|}K8QkJdG}zFPqlKLAcr83* zWgQ+HzQdV{TOj;%(7%jzp+KJSs$|sS9Fk zi>8|_;%+MHn6)L%h}LxJYN%Lsjm=l2JEG}rgt!}vT81WTD?iXN22oo(>Q%FW$7$$! zt&?$T0IopDHZ|A}nmLfzok8W3vju;nlA35T-r~-!Mh%-@xp^A6E=V4LfMg^hw4o2J zZI)js`N&kV*g%#wDTZ~mcOy6~E}sky$N;c`=y|Ej2+1ZQ2f9i4w?h@e2{8NMT~!94nB@itGuLH} zXVpo_fLn+Ny=`_6ub%qVxz9IOHOQr&m-w|E<2CfOb2=CaIW-6=RoY?8DbvigNhHcJ zG#i_20Ls>TP|sG<1T!>Hm<6C_+a^z4YoiJ>5de05QI0M6IheVSK%5>}CEC#MwBHBI ziIa1Wpa&iZ_r@?tJkJ5|{-W{nZBP!8&Q$t}P*I~(hRwZ6%$Lp+>-V88rG8_ARaUB|->lMt--ZnEI zTJ7{U4;S{j2Ay9PTlySLkZpPkSyjD9xB@11Gqz?H&}bm6INZyXa|}y*$KYeSt=BT^ z9)n8f69who6DC3I4i6#*smWsw#8aACPLFDXvaYploY`rTzv^v6%`=fZ=~tM~+#d%*t zf%)V_G>Dlk3}01X6V9YA0}KH#x+MuyPXYm7$4BlC*YhI}#g|)Uh0-v*i7ggcv&@^C zjYO%ac80KpJfmhZkwXX$pH_*;t&cQIT_(xF6ht!Iic3UdT(%7ihfT|wtXWA&V1Sf; zU3WEU`G(*m{rfc5Lu-SUf;0gW_gTQ5!wKEEk(Qj)=S2;}8FVa^9uYEg=U`?TJS&;e zZ|IGrGhpnT4H$R>%fn7eg+%K9in1ezX3K%Y`r6i +--FILE-- + +--EXPECT-- +bool(true) -- 2.40.0