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
30deImage* 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
119deBool 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