]> granicus.if.org Git - php/commitdiff
Support TGA reading
authorChristoph M. Becker <cmbecker69@gmx.de>
Thu, 20 Jun 2019 21:40:51 +0000 (23:40 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Thu, 20 Jun 2019 21:40:51 +0000 (23:40 +0200)
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.

15 files changed:
NEWS
UPGRADING
ext/gd/config.m4
ext/gd/config.w32
ext/gd/gd.c
ext/gd/libgd/gd.h
ext/gd/libgd/gd_tga.c [new file with mode: 0644]
ext/gd/libgd/gd_tga.h [new file with mode: 0644]
ext/gd/php_gd.h
ext/gd/tests/imagecreatefromtga.png [new file with mode: 0644]
ext/gd/tests/imagecreatefromtga_basic.phpt [new file with mode: 0644]
ext/gd/tests/imagecreatefromtga_basic.tga [new file with mode: 0644]
ext/gd/tests/imagecreatefromtga_variation.phpt [new file with mode: 0644]
ext/gd/tests/imagecreatefromtga_variation.tga [new file with mode: 0644]
ext/gd/tests/imagetypes_tga.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 50402e8411db4944fd7a2b20ea866e23455b6b3f..ef7507d08815d2b8cc3020a220fae9d3ced56b97 100644 (file)
--- 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)
index 4acfa3e7755bf40c0924daf9925d5d4e47c2d8fe..be14f0699be2710a8d65f5629dd2b0677af36a60 100644 (file)
--- 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
index a13313c8e86f1d4c8531f35e1c4786c0c1d7b73c..742ed412cdb983ee158e79f76018a769a57fe33e 100644 (file)
@@ -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
index bd73f572d3578d8487a54a2f88bb91173924d8c8..6695976d0e243a7e16da513949b7f13b8a567546 100644 (file)
@@ -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  \
index 1bdcba71fba461f5b321d3ca37103e74080bf5ca..96c0e23edf699fa0b564340c277188e256f7d3d8 100644 (file)
@@ -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)())
index 30f59b38f64c6773ad88c95d1ef3fa17c78d4340..461024f0f77d0c98d189e06504afb137815e9869 100644 (file)
@@ -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 (file)
index 0000000..67e77f7
--- /dev/null
@@ -0,0 +1,360 @@
+/**
+ * File: TGA Input
+ *
+ * Read TGA images.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 (file)
index 0000000..297f3dc
--- /dev/null
@@ -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
index 982decd064ec27f20103378de5341356bcdd2de9..e6db0c0ec0606e08c3f365c9d39516a317661594 100644 (file)
@@ -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 (file)
index 0000000..4a3060d
Binary files /dev/null and b/ext/gd/tests/imagecreatefromtga.png differ
diff --git a/ext/gd/tests/imagecreatefromtga_basic.phpt b/ext/gd/tests/imagecreatefromtga_basic.phpt
new file mode 100644 (file)
index 0000000..3025e52
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+imagecreatefromtga() - basic functionality
+--SKIPIF--
+<?php
+if (!extension_loaded('gd')) die('skip ext/gd required');
+if (!(imagetypes() & IMG_TGA)) die('skip TGA support required');
+?>
+--FILE--
+<?php
+// create an image from a TGA file
+$im = imagecreatefromtga(__DIR__ . '/imagecreatefromtga_basic.tga');
+
+include_once __DIR__ . '/func.inc';
+test_image_equals_file(__DIR__ . '/imagecreatefromtga.png', $im);
+?>
+--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 (file)
index 0000000..5f11f5a
Binary files /dev/null and b/ext/gd/tests/imagecreatefromtga_basic.tga differ
diff --git a/ext/gd/tests/imagecreatefromtga_variation.phpt b/ext/gd/tests/imagecreatefromtga_variation.phpt
new file mode 100644 (file)
index 0000000..39dd4b0
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+imagecreatefromtga() - RLE file reading
+--SKIPIF--
+<?php
+if (!extension_loaded('gd')) die('skip ext/gd required');
+if (!(imagetypes() & IMG_TGA)) die('skip TGA support required');
+?>
+--FILE--
+<?php
+// create an image from a TGA file
+$im = imagecreatefromtga(__DIR__ . '/imagecreatefromtga_variation.tga');
+
+include_once __DIR__ . '/func.inc';
+test_image_equals_file(__DIR__ . '/imagecreatefromtga.png', $im);
+?>
+--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 (file)
index 0000000..ce845ad
Binary files /dev/null and b/ext/gd/tests/imagecreatefromtga_variation.tga differ
diff --git a/ext/gd/tests/imagetypes_tga.phpt b/ext/gd/tests/imagetypes_tga.phpt
new file mode 100644 (file)
index 0000000..56d6b3c
--- /dev/null
@@ -0,0 +1,12 @@
+--TEST--
+imagetypes() - TGA support
+--SKIPIF--
+<?php
+if (!extension_loaded('gd')) die('skip ext/gd required');
+?>
+--FILE--
+<?php
+var_dump((imagetypes() & IMG_TGA) == function_exists('imagecreatefromtga'));
+?>
+--EXPECT--
+bool(true)