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 uint8_t *buffer;
46 deImageFormat format;
47 bool yFlipped;
48
49 uint8_t 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 ||
55 tgaHeader[17] == 0x20); /* both y-directions supported, non-interlaced */
56
57 yFlipped = (tgaHeader[17] & 0x20) == 0;
58
59 /* Decode header. */
60 width = (int)(tgaHeader[12]) | ((int)(tgaHeader[13]) << 8);
61 height = (int)(tgaHeader[14]) | ((int)(tgaHeader[15]) << 8);
62 bitsPerPixel = tgaHeader[16];
63 stride = width * bitsPerPixel / 8;
64
65 /* Allocate buffer. */
66 bufSize = stride;
67 buffer = deMalloc(bufSize);
68 DE_TEST_ASSERT(buffer);
69
70 /* Figure out format. */
71 DE_TEST_ASSERT(bitsPerPixel == 24 || bitsPerPixel == 32);
72 format = (bitsPerPixel == 32) ? DE_IMAGEFORMAT_ARGB8888 : DE_IMAGEFORMAT_XRGB8888;
73
74 /* Create image. */
75 image = deImage_create(width, height, format);
76 DE_TEST_ASSERT(image);
77
78 /* Copy pixel data. */
79 {
80 int bpp = 4;
81 int x, y;
82
83 for (y = 0; y < height; y++)
84 {
85 const uint8_t *src = buffer;
86 int dstY = yFlipped ? (height - 1 - y) : y;
87 deARGB *dst = (uint32_t *)((uint8_t *)image->pixels + dstY * image->width * bpp);
88 fread(buffer, 1, bufSize, file);
89
90 if (bitsPerPixel == 24)
91 {
92 for (x = 0; x < width; x++)
93 {
94 uint8_t b = *src++;
95 uint8_t g = *src++;
96 uint8_t r = *src++;
97 *dst++ = deARGB_set(r, g, b, 0xFF);
98 }
99 }
100 else
101 {
102 /* \todo [petri] Component order? */
103 uint8_t a = *src++;
104 uint8_t b = *src++;
105 uint8_t g = *src++;
106 uint8_t r = *src++;
107 DE_ASSERT(bitsPerPixel == 32);
108 *dst++ = deARGB_set(r, g, b, a);
109 }
110 }
111 }
112
113 deFree(buffer);
114 fclose(file);
115 }
116
117 return image;
118 }
119
deImage_saveTarga(const deImage * image,const char * fileName)120 bool deImage_saveTarga(const deImage *image, const char *fileName)
121 {
122 deImage *imageCopy = DE_NULL;
123 int width = image->width;
124 int height = image->height;
125 char tgaHeader[18];
126 FILE *file;
127
128 /* \todo [petri] Handle non-alpha images. */
129 if (image->format != DE_IMAGEFORMAT_ARGB8888)
130 {
131 imageCopy = deImage_convertFormat(image, DE_IMAGEFORMAT_ARGB8888);
132 if (!imageCopy)
133 return false;
134
135 image = imageCopy;
136 }
137
138 file = fopen(fileName, "wb");
139 if (!file)
140 return false;
141
142 /* Set unused fields of header to 0 */
143 memset(tgaHeader, 0, sizeof(tgaHeader));
144
145 tgaHeader[1] = 0; /* no palette */
146 tgaHeader[2] = 2; /* uncompressed RGB */
147
148 tgaHeader[12] = (char)(width & 0xFF);
149 tgaHeader[13] = (char)(width >> 8);
150 tgaHeader[14] = (char)(height & 0xFF);
151 tgaHeader[15] = (char)(height >> 8);
152 tgaHeader[16] = 24; /* bytes per pixel */
153 tgaHeader[17] = 0x20; /* Top-down, non-interlaced */
154
155 fwrite(tgaHeader, 1, 18, file);
156
157 /* Store pixels. */
158 {
159 const uint32_t *pixels = image->pixels;
160 int ndx;
161
162 for (ndx = 0; ndx < width * height; ndx++)
163 {
164 uint32_t c = pixels[ndx];
165 fputc((uint8_t)(c >> 0), file);
166 fputc((uint8_t)(c >> 8), file);
167 fputc((uint8_t)(c >> 16), file);
168 }
169 }
170
171 /* Cleanup and return. */
172 fclose(file);
173 if (imageCopy)
174 deImage_destroy(imageCopy);
175
176 return true;
177 }
178