1 /*-------------------------------------------------------------------------
2  * drawElements Image Library
3  * --------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Targa file operations.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "deImage.h"
25 #include "deMemory.h"
26 #include "deInt32.h"
27 
28 #include <stdio.h>
29 
deImage_loadTarga(const char * fileName)30 deImage* deImage_loadTarga (const char* fileName)
31 {
32 	deImage*	image = DE_NULL;
33 	FILE*		file;
34 
35 	file = fopen(fileName, "rb");
36 
37 	if (file != DE_NULL)
38 	{
39 		int				bytesRead;
40 		int				width;
41 		int				height;
42 		int				bufSize;
43 		int				stride;
44 		int				bitsPerPixel;
45 		deUint8*		buffer;
46 		deImageFormat	format;
47 		deBool			yFlipped;
48 
49 		deUint8 tgaHeader[18];
50 
51 		bytesRead = (int)fread(&tgaHeader, 1, 18, file);
52 		DE_TEST_ASSERT(bytesRead == 18);
53 		DE_TEST_ASSERT(tgaHeader[2] == 2);								/* truecolor, no encoding */
54 		DE_TEST_ASSERT(tgaHeader[17] == 0x00 || tgaHeader[17] == 0x20);	/* both y-directions supported, non-interlaced */
55 
56 		yFlipped = (tgaHeader[17] & 0x20) == 0;
57 
58 		/* Decode header. */
59 		width			= (int)(tgaHeader[12]) | ((int)(tgaHeader[13]) << 8);
60 		height			= (int)(tgaHeader[14]) | ((int)(tgaHeader[15]) << 8);
61 		bitsPerPixel	= tgaHeader[16];
62 		stride			= width * bitsPerPixel / 8;
63 
64 		/* Allocate buffer. */
65 		bufSize	= stride;
66 		buffer	= deMalloc(bufSize);
67 		DE_TEST_ASSERT(buffer);
68 
69 		/* Figure out format. */
70 		DE_TEST_ASSERT(bitsPerPixel == 24 || bitsPerPixel == 32);
71 		format = (bitsPerPixel == 32) ? DE_IMAGEFORMAT_ARGB8888 : DE_IMAGEFORMAT_XRGB8888;
72 
73 		/* Create image. */
74 		image = deImage_create(width, height, format);
75 		DE_TEST_ASSERT(image);
76 
77 		/* Copy pixel data. */
78 		{
79 			int	bpp = 4;
80 			int	x, y;
81 
82 			for (y = 0; y < height; y++)
83 			{
84 				const deUint8*	src		= buffer;
85 				int				dstY	= yFlipped ? (height-1 - y) : y;
86 				deARGB*			dst		= (deUint32*)((deUint8*)image->pixels + dstY*image->width*bpp);
87 				fread(buffer, 1, bufSize, file);
88 
89 				if (bitsPerPixel == 24)
90 				{
91 					for (x = 0; x < width; x++)
92 					{
93 						deUint8 b = *src++;
94 						deUint8 g = *src++;
95 						deUint8 r = *src++;
96 						*dst++ = deARGB_set(r, g, b, 0xFF);
97 					}
98 				}
99 				else
100 				{
101 					/* \todo [petri] Component order? */
102 					deUint8 a = *src++;
103 					deUint8 b = *src++;
104 					deUint8 g = *src++;
105 					deUint8 r = *src++;
106 					DE_ASSERT(bitsPerPixel == 32);
107 					*dst++ = deARGB_set(r, g, b, a);
108 				}
109 			}
110 		}
111 
112 		deFree(buffer);
113 		fclose(file);
114 	}
115 
116 	return image;
117 }
118 
deImage_saveTarga(const deImage * image,const char * fileName)119 deBool deImage_saveTarga (const deImage* image, const char* fileName)
120 {
121 	deImage*	imageCopy	= DE_NULL;
122 	int			width		= image->width;
123 	int			height		= image->height;
124 	char		tgaHeader[18];
125 	FILE*		file;
126 
127 	/* \todo [petri] Handle non-alpha images. */
128 	if (image->format != DE_IMAGEFORMAT_ARGB8888)
129 	{
130 		imageCopy = deImage_convertFormat(image, DE_IMAGEFORMAT_ARGB8888);
131 		if (!imageCopy)
132 			return DE_FALSE;
133 
134 		image = imageCopy;
135 	}
136 
137 	file = fopen(fileName, "wb");
138 	if (!file)
139 		return DE_FALSE;
140 
141 	/* Set unused fields of header to 0 */
142 	memset(tgaHeader, 0, sizeof(tgaHeader));
143 
144 	tgaHeader[1] = 0;	/* no palette */
145 	tgaHeader[2] = 2;	/* uncompressed RGB */
146 
147 	tgaHeader[12] = (char)(width & 0xFF);
148 	tgaHeader[13] = (char)(width >> 8);
149 	tgaHeader[14] = (char)(height & 0xFF);
150 	tgaHeader[15] = (char)(height >> 8);
151 	tgaHeader[16] = 24;		/* bytes per pixel */
152 	tgaHeader[17] = 0x20;	/* Top-down, non-interlaced */
153 
154 	fwrite(tgaHeader, 1, 18, file);
155 
156 	/* Store pixels. */
157 	{
158 		const deUint32*	pixels	= image->pixels;
159 		int				ndx;
160 
161 		for (ndx = 0; ndx < width * height; ndx++)
162 		{
163 			deUint32 c = pixels[ndx];
164 			fputc((deUint8)(c>>0), file);
165 			fputc((deUint8)(c>>8), file);
166 			fputc((deUint8)(c>>16), file);
167 		}
168 	}
169 
170 	/* Cleanup and return. */
171 	fclose(file);
172 	if (imageCopy)
173 		deImage_destroy(imageCopy);
174 
175 	return DE_TRUE;
176 }
177