xref: /plan9/sys/src/cmd/gs/jpeg/wrtarga.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
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