xref: /reactos/dll/3rdparty/libjpeg/wrtarga.c (revision 1d574191)
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