]> Creatis software - gdcm.git/blob - src/gdcmjasper/src/libjasper/jpg/jpg_enc.c
ENH: Ok since OJ warnings are not going to be fixed anytime soon remove them
[gdcm.git] / src / gdcmjasper / src / libjasper / jpg / jpg_enc.c
1 /*
2  * Copyright (c) 2001-2003 Michael David Adams.
3  * All rights reserved.
4  */
5
6 /* __START_OF_JASPER_LICENSE__
7  * 
8  * JasPer License Version 2.0
9  * 
10  * Copyright (c) 1999-2000 Image Power, Inc.
11  * Copyright (c) 1999-2000 The University of British Columbia
12  * Copyright (c) 2001-2003 Michael David Adams
13  * 
14  * All rights reserved.
15  * 
16  * Permission is hereby granted, free of charge, to any person (the
17  * "User") obtaining a copy of this software and associated documentation
18  * files (the "Software"), to deal in the Software without restriction,
19  * including without limitation the rights to use, copy, modify, merge,
20  * publish, distribute, and/or sell copies of the Software, and to permit
21  * persons to whom the Software is furnished to do so, subject to the
22  * following conditions:
23  * 
24  * 1.  The above copyright notices and this permission notice (which
25  * includes the disclaimer below) shall be included in all copies or
26  * substantial portions of the Software.
27  * 
28  * 2.  The name of a copyright holder shall not be used to endorse or
29  * promote products derived from the Software without specific prior
30  * written permission.
31  * 
32  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
33  * LICENSE.  NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
34  * THIS DISCLAIMER.  THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
35  * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
37  * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO
38  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
39  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
40  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
41  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
42  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  NO ASSURANCES ARE
43  * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
44  * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
45  * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
46  * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
47  * PROPERTY RIGHTS OR OTHERWISE.  AS A CONDITION TO EXERCISING THE RIGHTS
48  * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
49  * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY.  THE SOFTWARE
50  * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
51  * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
52  * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
53  * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
54  * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
55  * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
56  * RISK ACTIVITIES").  THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
57  * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
58  * 
59  * __END_OF_JASPER_LICENSE__
60  */
61
62 /******************************************************************************\
63 * Includes.
64 \******************************************************************************/
65
66 #include <assert.h>
67 #include "jasper/jas_types.h"
68
69 #include "jasper/jas_tvp.h"
70 #include "jasper/jas_stream.h"
71 #include "jasper/jas_image.h"
72 #include "jasper/jas_string.h"
73 #include "jasper/jas_debug.h"
74
75 #include "jpg_jpeglib.h"
76 #include "jpg_cod.h"
77 #include "jpg_enc.h"
78
79 /******************************************************************************\
80 * Types.
81 \******************************************************************************/
82
83 typedef struct jpg_src_s {
84
85   /* Output buffer. */
86   JSAMPARRAY buffer;
87
88   /* Height of output buffer. */
89   JDIMENSION buffer_height;
90
91   /* The current row. */
92   JDIMENSION row;
93
94   /* The image used to hold the decompressed sample data. */
95   jas_image_t *image;
96
97   /* The row buffer. */
98   jas_matrix_t *data;
99
100   /* The error indicator.  If this is nonzero, something has gone wrong
101     during decompression. */
102   int error;
103
104   jpg_enc_t *enc;
105
106 } jpg_src_t;
107
108 typedef struct {
109   int qual;
110 } jpg_encopts_t;
111
112 typedef enum {
113   OPT_QUAL
114 } jpg_optid_t;
115
116 jas_taginfo_t jpg_opttab[] = {
117   {OPT_QUAL, "quality"},
118   {-1, 0}
119 };
120
121 /******************************************************************************\
122 * Local prototypes.
123 \******************************************************************************/
124
125 static int jpg_copyfiletostream(jas_stream_t *out, FILE *in);
126 static void jpg_start_input(j_compress_ptr cinfo, struct jpg_src_s *sinfo);
127 static JDIMENSION jpg_get_pixel_rows(j_compress_ptr cinfo, struct jpg_src_s *sinfo);
128 static void jpg_finish_input(j_compress_ptr cinfo, struct jpg_src_s *sinfo);
129 static int tojpgcs(int colorspace);
130 static int jpg_parseencopts(char *optstr, jpg_encopts_t *encopts);
131
132 /******************************************************************************\
133 *
134 \******************************************************************************/
135
136 static int jpg_copyfiletostream(jas_stream_t *out, FILE *in)
137 {
138   int c;
139   while ((c = fgetc(in)) != EOF) {
140     if (jas_stream_putc(out, c) == EOF) {
141       return -1;
142     }
143   }
144   return 0;
145 }
146
147 static void jpg_start_input(j_compress_ptr cinfo, struct jpg_src_s *sinfo)
148 {
149   /* Avoid compiler warnings about unused parameters. */
150   cinfo = 0;
151
152   sinfo->row = 0;
153 }
154
155 static JDIMENSION jpg_get_pixel_rows(j_compress_ptr cinfo, struct jpg_src_s *sinfo)
156 {
157   JSAMPLE *bufptr;
158   int i;
159   int cmptno;
160   int width;
161   int *cmpts;
162
163   cmpts = sinfo->enc->cmpts;
164
165   width = jas_image_width(sinfo->image);
166
167   if (sinfo->error) {
168     return 0;
169   }
170   for (cmptno = 0; cmptno < cinfo->input_components; ++cmptno) {
171     if (jas_image_readcmpt(sinfo->image, cmpts[cmptno], 0, sinfo->row, width, 1, sinfo->data)) {
172       ;
173     }
174     bufptr = (sinfo->buffer[0]) + cmptno;
175     for (i = 0; i < width; ++i) {
176       *bufptr = jas_matrix_get(sinfo->data, 0, i);
177       bufptr += cinfo->input_components;
178     }
179   }
180   ++sinfo->row;
181   return 1;
182 }
183
184 static void jpg_finish_input(j_compress_ptr cinfo, struct jpg_src_s *sinfo)
185 {
186   /* Avoid compiler warnings about unused parameters. */
187   cinfo = 0;
188   sinfo = 0;
189 }
190
191 /******************************************************************************\
192 * Code for save operation.
193 \******************************************************************************/
194
195 /* Save an image to a stream in the the JPG format. */
196
197 int jpg_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
198 {
199   JDIMENSION numscanlines;
200   struct jpeg_compress_struct cinfo;
201   struct jpeg_error_mgr jerr;
202   jas_image_coord_t width;
203   jas_image_coord_t height;
204   jpg_src_t src_mgr_buf;
205   jpg_src_t *src_mgr = &src_mgr_buf;
206   FILE *output_file;
207   int cmptno;
208   jpg_enc_t encbuf;
209   jpg_enc_t *enc = &encbuf;
210   jpg_encopts_t encopts;
211
212   output_file = 0;
213
214   if (jpg_parseencopts(optstr, &encopts))
215     goto error;
216
217   switch (jas_clrspc_fam(jas_image_clrspc(image))) {
218   case JAS_CLRSPC_FAM_RGB:
219     if (jas_image_clrspc(image) != JAS_CLRSPC_SRGB)
220       jas_eprintf("warning: inaccurate color\n");
221     enc->numcmpts = 3;
222     if ((enc->cmpts[0] = jas_image_getcmptbytype(image,
223       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
224       (enc->cmpts[1] = jas_image_getcmptbytype(image,
225       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
226       (enc->cmpts[2] = jas_image_getcmptbytype(image,
227       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
228       jas_eprintf("error: missing color component\n");
229       goto error;
230     }
231     break;
232   case JAS_CLRSPC_FAM_YCBCR:
233     if (jas_image_clrspc(image) != JAS_CLRSPC_SYCBCR)
234       jas_eprintf("warning: inaccurate color\n");
235     enc->numcmpts = 3;
236     if ((enc->cmpts[0] = jas_image_getcmptbytype(image,
237       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_Y))) < 0 ||
238       (enc->cmpts[1] = jas_image_getcmptbytype(image,
239       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_CB))) < 0 ||
240       (enc->cmpts[2] = jas_image_getcmptbytype(image,
241       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_CR))) < 0) {
242       jas_eprintf("error: missing color component\n");
243       goto error;
244     }
245     break;
246   case JAS_CLRSPC_FAM_GRAY:
247     if (jas_image_clrspc(image) != JAS_CLRSPC_SGRAY)
248       jas_eprintf("warning: inaccurate color\n");
249     enc->numcmpts = 1;
250     if ((enc->cmpts[0] = jas_image_getcmptbytype(image,
251       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y))) < 0) {
252       jas_eprintf("error: missing color component\n");
253       goto error;
254     }
255     break;
256   default:
257     jas_eprintf("error: JPG format does not support color space\n");
258     goto error;
259     break;
260   }
261
262   width = jas_image_width(image);
263   height = jas_image_height(image);
264
265   for (cmptno = 0; cmptno < enc->numcmpts; ++cmptno) {
266     if (jas_image_cmptwidth(image, enc->cmpts[cmptno]) != width ||
267       jas_image_cmptheight(image, enc->cmpts[cmptno]) != height ||
268       jas_image_cmpttlx(image, enc->cmpts[cmptno]) != 0 ||
269       jas_image_cmpttly(image, enc->cmpts[cmptno]) != 0 ||
270       jas_image_cmpthstep(image, enc->cmpts[cmptno]) != 1 ||
271       jas_image_cmptvstep(image, enc->cmpts[cmptno]) != 1 ||
272       jas_image_cmptprec(image, enc->cmpts[cmptno]) != 8 ||
273       jas_image_cmptsgnd(image, enc->cmpts[cmptno]) != false) {
274       jas_eprintf("error: The JPG encoder cannot handle an image with this geometry.\n");
275       goto error;
276     }
277   }
278
279   if (!(output_file = tmpfile())) {
280     goto error;
281   }
282
283   /* Create a JPEG compression object. */
284   cinfo.err = jpeg_std_error(&jerr);
285   jpeg_create_compress(&cinfo);
286
287   /* Specify data destination for compression */
288   jpeg_stdio_dest(&cinfo, output_file);
289
290   cinfo.in_color_space = tojpgcs(jas_image_clrspc(image));
291   cinfo.image_width = width;
292   cinfo.image_height = height;
293   cinfo.input_components = enc->numcmpts;
294   jpeg_set_defaults(&cinfo);
295
296   src_mgr->error = 0;
297   src_mgr->image = image;
298   src_mgr->data = jas_matrix_create(1, width);
299   src_mgr->buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo,
300     JPOOL_IMAGE, (JDIMENSION) width * cinfo.input_components,
301     (JDIMENSION) 1);
302   src_mgr->buffer_height = 1;
303   src_mgr->enc = enc;
304
305   /* Read the input file header to obtain file size & colorspace. */
306   jpg_start_input(&cinfo, src_mgr);
307
308   if (encopts.qual >= 0) {
309     jpeg_set_quality(&cinfo, encopts.qual, TRUE);
310   }
311
312   /* Now that we know input colorspace, fix colorspace-dependent defaults */
313   jpeg_default_colorspace(&cinfo);
314
315   /* Start compressor */
316   jpeg_start_compress(&cinfo, TRUE);
317
318   /* Process data */
319   while (cinfo.next_scanline < cinfo.image_height) {
320     if ((numscanlines = jpg_get_pixel_rows(&cinfo, src_mgr)) <= 0) {
321       break;
322     }
323     jpeg_write_scanlines(&cinfo, src_mgr->buffer, numscanlines);
324   }
325
326   /* Finish compression and release memory */
327   jpg_finish_input(&cinfo, src_mgr);
328   jpeg_finish_compress(&cinfo);
329   jpeg_destroy_compress(&cinfo);
330
331   rewind(output_file);
332   jpg_copyfiletostream(out, output_file);
333   fclose(output_file);
334   output_file = 0;
335
336   return 0;
337
338 error:
339   if (output_file) {
340     fclose(output_file);
341   }
342   return -1;
343 }
344
345 static int tojpgcs(int colorspace)
346 {
347   switch (jas_clrspc_fam(colorspace)) {
348   case JAS_CLRSPC_FAM_RGB:
349     return JCS_RGB;
350     break;
351   case JAS_CLRSPC_FAM_YCBCR:
352     return JCS_YCbCr;
353     break;
354   case JAS_CLRSPC_FAM_GRAY:
355     return JCS_GRAYSCALE;
356     break;
357   default:
358     abort();
359     break;
360   }
361 }
362
363 /* Parse the encoder options string. */
364 static int jpg_parseencopts(char *optstr, jpg_encopts_t *encopts)
365 {
366   jas_tvparser_t *tvp;
367   char *qual_str;
368   int ret;
369
370   tvp = 0;
371
372   /* Initialize default values for encoder options. */
373   encopts->qual = -1;
374
375   /* Create the tag-value parser. */
376   if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
377     goto error;
378   }
379
380   /* Get tag-value pairs, and process as necessary. */
381   while (!(ret = jas_tvparser_next(tvp))) {
382     switch (jas_taginfo_nonull(jas_taginfos_lookup(jpg_opttab,
383       jas_tvparser_gettag(tvp)))->id) {
384     case OPT_QUAL:
385       qual_str = jas_tvparser_getval(tvp);
386       if (sscanf(qual_str, "%d", &encopts->qual) != 1) {
387         fprintf(stderr,
388           "ignoring bad quality specifier %s\n",
389           jas_tvparser_getval(tvp));
390         encopts->qual = -1;
391       }
392       break;
393     default:
394       fprintf(stderr, "warning: ignoring invalid option %s\n",
395         jas_tvparser_gettag(tvp));
396       break;
397     }
398   }
399   if (ret < 0) {
400     goto error;
401   }
402
403   /* Destroy the tag-value parser. */
404   jas_tvparser_destroy(tvp);
405
406   return 0;
407
408 error:
409   if (tvp) {
410     jas_tvparser_destroy(tvp);
411   }
412   return -1;
413 }