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