xref: /PHP-8.3/ext/gd/libgd/gd_tga.c (revision 2f0dcf2a)
1 /**
2  * File: TGA Input
3  *
4  * Read TGA images.
5  */
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif /* HAVE_CONFIG_H */
10 
11 #include <stdio.h>
12 #include <stddef.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "gd_tga.h"
17 #include "gd.h"
18 #include "gd_errors.h"
19 #include "gdhelpers.h"
20 
21 /*
22 	Function: gdImageCreateFromTga
23 
24 	Creates a gdImage from a TGA file
25 
26 	Parameters:
27 
28 		infile - Pointer to TGA binary file
29  */
gdImageCreateFromTga(FILE * fp)30 gdImagePtr gdImageCreateFromTga(FILE *fp)
31 {
32 	gdImagePtr image;
33 	gdIOCtx* in = gdNewFileCtx(fp);
34 	if (in == NULL) return NULL;
35 	image = gdImageCreateFromTgaCtx(in);
36 	in->gd_free( in );
37 	return image;
38 }
39 
40 /*
41 	Function: gdImageCreateFromTgaPtr
42 */
gdImageCreateFromTgaPtr(int size,void * data)43 gdImagePtr gdImageCreateFromTgaPtr(int size, void *data)
44 {
45 	gdImagePtr im;
46 	gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
47 	if (in == NULL) return NULL;
48 	im = gdImageCreateFromTgaCtx(in);
49 	in->gd_free(in);
50 	return im;
51 }
52 
53 
54 /*
55 	Function: gdImageCreateFromTgaCtx
56 
57 	Creates a gdImage from a gdIOCtx referencing a TGA binary file.
58 
59 	Parameters:
60 		ctx - Pointer to a gdIOCtx structure
61  */
gdImageCreateFromTgaCtx(gdIOCtx * ctx)62 gdImagePtr gdImageCreateFromTgaCtx(gdIOCtx* ctx)
63 {
64 	int bitmap_caret = 0;
65 	oTga *tga = NULL;
66 	/*	int pixel_block_size = 0;
67 		int image_block_size = 0; */
68 	volatile gdImagePtr image = NULL;
69 	int x = 0;
70 	int y = 0;
71 
72 	tga = (oTga *) gdMalloc(sizeof(oTga));
73 	if (!tga) {
74 		return NULL;
75 	}
76 
77 	tga->bitmap = NULL;
78 	tga->ident = NULL;
79 
80 	if (read_header_tga(ctx, tga) < 0) {
81 		free_tga(tga);
82 		return NULL;
83 	}
84 
85 	/*TODO: Will this be used?
86 		pixel_block_size = tga->bits / 8;
87 		image_block_size = (tga->width * tga->height) * pixel_block_size;
88 	*/
89 
90 	if (read_image_tga(ctx, tga) < 0) {
91 		free_tga(tga);
92 		return NULL;
93 	}
94 
95 	image = gdImageCreateTrueColor((int)tga->width, (int)tga->height );
96 
97 	if (image == 0) {
98 		free_tga( tga );
99 		return NULL;
100 	}
101 
102 	/*!	\brief Populate GD image object
103 	 *  Copy the pixel data from our tga bitmap buffer into the GD image
104 	 *  Disable blending and save the alpha channel per default
105 	 */
106 	if (tga->alphabits) {
107 		gdImageAlphaBlending(image, 0);
108 		gdImageSaveAlpha(image, 1);
109 	}
110 
111 	/* TODO: use alphabits as soon as we support 24bit and other alpha bps (ie != 8bits) */
112 	for (y = 0; y < tga->height; y++) {
113 		register int *tpix = image->tpixels[y];
114 		for ( x = 0; x < tga->width; x++, tpix++) {
115 			if (tga->bits == TGA_BPP_24) {
116 				*tpix = gdTrueColor(tga->bitmap[bitmap_caret + 2], tga->bitmap[bitmap_caret + 1], tga->bitmap[bitmap_caret]);
117 				bitmap_caret += 3;
118 			} else if (tga->bits == TGA_BPP_32 && tga->alphabits) {
119 				register int a = tga->bitmap[bitmap_caret + 3];
120 
121 				*tpix = gdTrueColorAlpha(tga->bitmap[bitmap_caret + 2], tga->bitmap[bitmap_caret + 1], tga->bitmap[bitmap_caret], gdAlphaMax - (a >> 1));
122 				bitmap_caret += 4;
123 			}
124 		}
125 	}
126 
127 	if (tga->flipv && tga->fliph) {
128 		gdImageFlipBoth(image);
129 	} else if (tga->flipv) {
130 		gdImageFlipVertical(image);
131 	} else if (tga->fliph) {
132 		gdImageFlipHorizontal(image);
133 	}
134 
135 	free_tga(tga);
136 
137 	return image;
138 }
139 
140 /*!	\brief Reads a TGA header.
141  *	Reads the header block from a binary TGA file populating the referenced TGA structure.
142  *	\param ctx Pointer to TGA binary file
143  *	\param tga Pointer to TGA structure
144  *	\return int 1 on success, -1 on failure
145  */
read_header_tga(gdIOCtx * ctx,oTga * tga)146 int read_header_tga(gdIOCtx *ctx, oTga *tga)
147 {
148 
149 	unsigned char header[18];
150 
151 	if (gdGetBuf(header, sizeof(header), ctx) < 18) {
152 		gd_error("Fail to read header");
153 		return -1;
154 	}
155 
156 	tga->identsize = header[0];
157 	tga->colormaptype = header[1];
158 	tga->imagetype = header[2];
159 	tga->colormapstart = header[3] + (header[4] << 8);
160 	tga->colormaplength = header[5] + (header[6] << 8);
161 	tga->colormapbits = header[7];
162 	tga->xstart = header[8] + (header[9] << 8);
163 	tga->ystart = header[10] + (header[11] << 8);
164 	tga->width = header[12] + (header[13] << 8);
165 	tga->height = header[14] + (header[15] << 8);
166 	tga->bits = header[16];
167 	tga->alphabits = header[17] & 0x0f;
168 	tga->fliph = (header[17] & 0x10) ? 1 : 0;
169 	tga->flipv = (header[17] & 0x20) ? 0 : 1;
170 
171 #ifdef DEBUG
172 	printf("format bps: %i\n", tga->bits);
173 	printf("flip h/v: %i / %i\n", tga->fliph, tga->flipv);
174 	printf("alpha: %i\n", tga->alphabits);
175 	printf("wxh: %i %i\n", tga->width, tga->height);
176 #endif
177 
178 	if (!((tga->bits == TGA_BPP_24 && tga->alphabits == 0)
179 		|| (tga->bits == TGA_BPP_32 && tga->alphabits == 8)))
180 	{
181 		gd_error_ex(GD_WARNING, "gd-tga: %u bits per pixel with %u alpha bits not supported\n",
182 			tga->bits, tga->alphabits);
183 		return -1;
184 	}
185 
186 	tga->ident = NULL;
187 
188 	if (tga->identsize > 0) {
189 		tga->ident = (char *) gdMalloc(tga->identsize * sizeof(char));
190 		if(tga->ident == NULL) {
191 			return -1;
192 		}
193 
194 		gdGetBuf(tga->ident, tga->identsize, ctx);
195 	}
196 
197 	return 1;
198 }
199 
200 /*!	\brief Reads a TGA image data into buffer.
201  *	Reads the image data block from a binary TGA file populating the referenced TGA structure.
202  *	\param ctx Pointer to TGA binary file
203  *	\param tga Pointer to TGA structure
204  *	\return int 0 on success, -1 on failure
205  */
read_image_tga(gdIOCtx * ctx,oTga * tga)206 int read_image_tga( gdIOCtx *ctx, oTga *tga )
207 {
208 	int pixel_block_size = (tga->bits / 8);
209 	int image_block_size;
210 	int* decompression_buffer = NULL;
211 	unsigned char* conversion_buffer = NULL;
212 	int buffer_caret = 0;
213 	int bitmap_caret = 0;
214 	int i = 0;
215 	int encoded_pixels;
216 	int rle_size;
217 
218 	if(overflow2(tga->width, tga->height)) {
219 		return -1;
220 	}
221 
222 	if(overflow2(tga->width * tga->height, pixel_block_size)) {
223 		return -1;
224 	}
225 
226 	image_block_size = (tga->width * tga->height) * pixel_block_size;
227 	if(overflow2(image_block_size, sizeof(int))) {
228 		return -1;
229 	}
230 
231 	/*! \todo Add more image type support.
232 	 */
233 	if (tga->imagetype != TGA_TYPE_RGB && tga->imagetype != TGA_TYPE_RGB_RLE)
234 		return -1;
235 
236 	/*!	\brief Allocate memmory for image block
237 	 *  Allocate a chunk of memory for the image block to be passed into.
238 	 */
239 	tga->bitmap = (int *) gdMalloc(image_block_size * sizeof(int));
240 	if (tga->bitmap == NULL)
241 		return -1;
242 
243 	switch (tga->imagetype) {
244 	case TGA_TYPE_RGB:
245 		/*! \brief Read in uncompressed RGB TGA
246 		 *  Chunk load the pixel data from an uncompressed RGB type TGA.
247 		 */
248 		conversion_buffer = (unsigned char *) gdMalloc(image_block_size * sizeof(unsigned char));
249 		if (conversion_buffer == NULL) {
250 			return -1;
251 		}
252 
253 		if (gdGetBuf(conversion_buffer, image_block_size, ctx) != image_block_size) {
254 			gd_error("gd-tga: premature end of image data\n");
255 			gdFree(conversion_buffer);
256 			return -1;
257 		}
258 
259 		while (buffer_caret < image_block_size) {
260 			tga->bitmap[buffer_caret] = (int) conversion_buffer[buffer_caret];
261 			buffer_caret++;
262 		}
263 
264 		gdFree(conversion_buffer);
265 		break;
266 
267 	case TGA_TYPE_RGB_RLE:
268 		/*! \brief Read in RLE compressed RGB TGA
269 		 *  Chunk load the pixel data from an RLE compressed RGB type TGA.
270 		 */
271 		decompression_buffer = (int*) gdMalloc(image_block_size * sizeof(int));
272 		if (decompression_buffer == NULL) {
273 			return -1;
274 		}
275 		conversion_buffer = (unsigned char *) gdMalloc(image_block_size * sizeof(unsigned char));
276 		if (conversion_buffer == NULL) {
277 			gd_error("gd-tga: premature end of image data\n");
278 			gdFree( decompression_buffer );
279 			return -1;
280 		}
281 
282 		rle_size = gdGetBuf(conversion_buffer, image_block_size, ctx);
283 		if (rle_size <= 0) {
284 			gdFree(conversion_buffer);
285 			gdFree(decompression_buffer);
286 			return -1;
287 		}
288 
289 		buffer_caret = 0;
290 
291 		while( buffer_caret < rle_size) {
292 			decompression_buffer[buffer_caret] = (int)conversion_buffer[buffer_caret];
293 			buffer_caret++;
294 		}
295 
296 		buffer_caret = 0;
297 
298 		while( bitmap_caret < image_block_size ) {
299 
300 			if (buffer_caret + pixel_block_size > rle_size) {
301 				gdFree( decompression_buffer );
302 				gdFree( conversion_buffer );
303 				return -1;
304 			}
305 
306 			if ((decompression_buffer[buffer_caret] & TGA_RLE_FLAG) == TGA_RLE_FLAG) {
307 				encoded_pixels = ( ( decompression_buffer[ buffer_caret ] & ~TGA_RLE_FLAG ) + 1 );
308 				buffer_caret++;
309 
310 				if ((bitmap_caret + (encoded_pixels * pixel_block_size)) > image_block_size
311 						|| buffer_caret + pixel_block_size > rle_size) {
312 					gdFree( decompression_buffer );
313 					gdFree( conversion_buffer );
314 					return -1;
315 				}
316 
317 				for (i = 0; i < encoded_pixels; i++) {
318 					memcpy(tga->bitmap + bitmap_caret, decompression_buffer + buffer_caret, pixel_block_size * sizeof(int));
319 					bitmap_caret += pixel_block_size;
320 				}
321 				buffer_caret += pixel_block_size;
322 
323 			} else {
324 				encoded_pixels = decompression_buffer[ buffer_caret ] + 1;
325 				buffer_caret++;
326 
327 				if ((bitmap_caret + (encoded_pixels * pixel_block_size)) > image_block_size
328 						|| buffer_caret + (encoded_pixels * pixel_block_size) > rle_size) {
329 					gdFree( decompression_buffer );
330 					gdFree( conversion_buffer );
331 					return -1;
332 				}
333 
334 				memcpy(tga->bitmap + bitmap_caret, decompression_buffer + buffer_caret, encoded_pixels * pixel_block_size * sizeof(int));
335 				bitmap_caret += (encoded_pixels * pixel_block_size);
336 				buffer_caret += (encoded_pixels * pixel_block_size);
337 			}
338 		}
339 		gdFree( decompression_buffer );
340 		gdFree( conversion_buffer );
341 		break;
342 	}
343 
344 	return 1;
345 }
346 
347 /*!	\brief Cleans up a TGA structure.
348  *	Dereferences the bitmap referenced in a TGA structure, then the structure itself
349  *	\param tga Pointer to TGA structure
350  */
free_tga(oTga * tga)351 void free_tga(oTga * tga)
352 {
353 	if (tga) {
354 		if (tga->ident)
355 			gdFree(tga->ident);
356 		if (tga->bitmap)
357 			gdFree(tga->bitmap);
358 		gdFree(tga);
359 	}
360 }
361