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