blob: cf104d2debd0ffbbfc67bbe00b332dc8ad77980d [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
2 * wrtarga.c
3 *
4 * Copyright (C) 1991-1996, Thomas G. Lane.
5 * This file is part of the Independent JPEG Group's software.
6 * For conditions of distribution and use, see the accompanying README file.
7 *
8 * This file contains routines to write output images in Targa format.
9 *
10 * These routines may need modification for non-Unix environments or
11 * specialized applications. As they stand, they assume output to
12 * an ordinary stdio stream.
13 *
14 * Based on code contributed by Lee Daniel Crocker.
15 */
16
17#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
18
19#ifdef TARGA_SUPPORTED
20
21
22/*
23 * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
24 * This is not yet implemented.
25 */
26
27#if BITS_IN_JSAMPLE != 8
28 Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
29#endif
30
31/*
32 * The output buffer needs to be writable by fwrite(). On PCs, we must
33 * allocate the buffer in near data space, because we are assuming small-data
34 * memory model, wherein fwrite() can't reach far memory. If you need to
35 * process very wide images on a PC, you might have to compile in large-memory
36 * model, or else replace fwrite() with a putc() loop --- which will be much
37 * slower.
38 */
39
40
41/* Private version of data destination object */
42
43typedef struct {
44 struct djpeg_dest_struct pub; /* public fields */
45
46 char *iobuffer; /* physical I/O buffer */
47 JDIMENSION buffer_width; /* width of one row */
48} tga_dest_struct;
49
50typedef tga_dest_struct * tga_dest_ptr;
51
52
53LOCAL(void)
54write_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors)
55/* Create and write a Targa header */
56{
57 char targaheader[18];
58
59 /* Set unused fields of header to 0 */
60 MEMZERO(targaheader, SIZEOF(targaheader));
61
62 if (num_colors > 0) {
63 targaheader[1] = 1; /* color map type 1 */
64 targaheader[5] = (char) (num_colors & 0xFF);
65 targaheader[6] = (char) (num_colors >> 8);
66 targaheader[7] = 24; /* 24 bits per cmap entry */
67 }
68
69 targaheader[12] = (char) (cinfo->output_width & 0xFF);
70 targaheader[13] = (char) (cinfo->output_width >> 8);
71 targaheader[14] = (char) (cinfo->output_height & 0xFF);
72 targaheader[15] = (char) (cinfo->output_height >> 8);
73 targaheader[17] = 0x20; /* Top-down, non-interlaced */
74
75 if (cinfo->out_color_space == JCS_GRAYSCALE) {
76 targaheader[2] = 3; /* image type = uncompressed gray-scale */
77 targaheader[16] = 8; /* bits per pixel */
78 } else { /* must be RGB */
79 if (num_colors > 0) {
80 targaheader[2] = 1; /* image type = colormapped RGB */
81 targaheader[16] = 8;
82 } else {
83 targaheader[2] = 2; /* image type = uncompressed RGB */
84 targaheader[16] = 24;
85 }
86 }
87
88 if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18)
89 ERREXIT(cinfo, JERR_FILE_WRITE);
90}
91
92
93/*
94 * Write some pixel data.
95 * In this module rows_supplied will always be 1.
96 */
97
98METHODDEF(void)
99put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
100 JDIMENSION rows_supplied)
101/* used for unquantized full-color output */
102{
103 tga_dest_ptr dest = (tga_dest_ptr) dinfo;
104 register JSAMPROW inptr;
105 register char * outptr;
106 register JDIMENSION col;
107
108 inptr = dest->pub.buffer[0];
109 outptr = dest->iobuffer;
110 for (col = cinfo->output_width; col > 0; col--) {
111 outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */
112 outptr[1] = (char) GETJSAMPLE(inptr[1]);
113 outptr[2] = (char) GETJSAMPLE(inptr[0]);
114 inptr += 3, outptr += 3;
115 }
116 (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
117}
118
119METHODDEF(void)
120put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
121 JDIMENSION rows_supplied)
122/* used for grayscale OR quantized color output */
123{
124 tga_dest_ptr dest = (tga_dest_ptr) dinfo;
125 register JSAMPROW inptr;
126 register char * outptr;
127 register JDIMENSION col;
128
129 inptr = dest->pub.buffer[0];
130 outptr = dest->iobuffer;
131 for (col = cinfo->output_width; col > 0; col--) {
132 *outptr++ = (char) GETJSAMPLE(*inptr++);
133 }
134 (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
135}
136
137
138/*
139 * Write some demapped pixel data when color quantization is in effect.
140 * For Targa, this is only applied to grayscale data.
141 */
142
143METHODDEF(void)
144put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
145 JDIMENSION rows_supplied)
146{
147 tga_dest_ptr dest = (tga_dest_ptr) dinfo;
148 register JSAMPROW inptr;
149 register char * outptr;
150 register JSAMPROW color_map0 = cinfo->colormap[0];
151 register JDIMENSION col;
152
153 inptr = dest->pub.buffer[0];
154 outptr = dest->iobuffer;
155 for (col = cinfo->output_width; col > 0; col--) {
156 *outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]);
157 }
158 (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
159}
160
161
162/*
163 * Startup: write the file header.
164 */
165
166METHODDEF(void)
167start_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
168{
169 tga_dest_ptr dest = (tga_dest_ptr) dinfo;
170 int num_colors, i;
171 FILE *outfile;
172
173 if (cinfo->out_color_space == JCS_GRAYSCALE) {
174 /* Targa doesn't have a mapped grayscale format, so we will */
175 /* demap quantized gray output. Never emit a colormap. */
176 write_header(cinfo, dinfo, 0);
177 if (cinfo->quantize_colors)
178 dest->pub.put_pixel_rows = put_demapped_gray;
179 else
180 dest->pub.put_pixel_rows = put_gray_rows;
181 } else if (cinfo->out_color_space == JCS_RGB) {
182 if (cinfo->quantize_colors) {
183 /* We only support 8-bit colormap indexes, so only 256 colors */
184 num_colors = cinfo->actual_number_of_colors;
185 if (num_colors > 256)
186 ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors);
187 write_header(cinfo, dinfo, num_colors);
188 /* Write the colormap. Note Targa uses BGR byte order */
189 outfile = dest->pub.output_file;
190 for (i = 0; i < num_colors; i++) {
191 putc(GETJSAMPLE(cinfo->colormap[2][i]), outfile);
192 putc(GETJSAMPLE(cinfo->colormap[1][i]), outfile);
193 putc(GETJSAMPLE(cinfo->colormap[0][i]), outfile);
194 }
195 dest->pub.put_pixel_rows = put_gray_rows;
196 } else {
197 write_header(cinfo, dinfo, 0);
198 dest->pub.put_pixel_rows = put_pixel_rows;
199 }
200 } else {
201 ERREXIT(cinfo, JERR_TGA_COLORSPACE);
202 }
203}
204
205
206/*
207 * Finish up at the end of the file.
208 */
209
210METHODDEF(void)
211finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
212{
213 /* Make sure we wrote the output file OK */
214 fflush(dinfo->output_file);
215 if (ferror(dinfo->output_file))
216 ERREXIT(cinfo, JERR_FILE_WRITE);
217}
218
219
220/*
221 * The module selection routine for Targa format output.
222 */
223
224GLOBAL(djpeg_dest_ptr)
225jinit_write_targa (j_decompress_ptr cinfo)
226{
227 tga_dest_ptr dest;
228
229 /* Create module interface object, fill in method pointers */
230 dest = (tga_dest_ptr)
231 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
232 SIZEOF(tga_dest_struct));
233 dest->pub.start_output = start_output_tga;
234 dest->pub.finish_output = finish_output_tga;
235
236 /* Calculate output image dimensions so we can allocate space */
237 jpeg_calc_output_dimensions(cinfo);
238
239 /* Create I/O buffer. Note we make this near on a PC. */
240 dest->buffer_width = cinfo->output_width * cinfo->output_components;
241 dest->iobuffer = (char *)
242 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
243 (size_t) (dest->buffer_width * SIZEOF(char)));
244
245 /* Create decompressor output buffer. */
246 dest->pub.buffer = (*cinfo->mem->alloc_sarray)
247 ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1);
248 dest->pub.buffer_height = 1;
249
250 return (djpeg_dest_ptr) dest;
251}
252
253#endif /* TARGA_SUPPORTED */