[2.0] Backport all changes from trunk
[openjpeg.git] / src / lib / openjpip / jp2k_decoder.c
1 /*
2  * $Id$
3  *
4  * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
5  * Copyright (c) 2002-2011, Professor Benoit Macq
6  * Copyright (c) 2010-2011, Kaori Hagihara
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <assert.h>
35 #include <limits.h>
36 #include "jp2k_decoder.h"
37 #include "openjpeg.h"
38
39
40 static void error_callback(const char *msg, void *client_data);
41 static void warning_callback(const char *msg, void *client_data);
42 static void info_callback(const char *msg, void *client_data);
43
44 static Byte_t * imagetopnm(opj_image_t *image, ihdrbox_param_t **ihdrbox);
45
46 Byte_t * j2k_to_pnm( FILE *fp, ihdrbox_param_t **ihdrbox)
47 {
48   Byte_t *pnmstream = NULL;
49   opj_dparameters_t parameters; /* decompression parameters */
50   opj_image_t *image = NULL;
51   opj_codec_t *l_codec = NULL;  /* handle to a decompressor */
52   opj_stream_t *l_stream = NULL;
53
54   /* set decoding parameters to default values */
55   opj_set_default_decoder_parameters(&parameters);
56
57   /* set a byte stream */
58   l_stream = opj_stream_create_default_file_stream( fp, 1);
59   if (!l_stream){
60     fprintf(stderr, "ERROR -> failed to create the stream from the file\n");
61     return NULL;
62   }
63
64   /* decode the code-stream */
65   /* ---------------------- */
66
67   /* JPEG-2000 codestream */
68   /* get a decoder handle */
69   l_codec = opj_create_decompress(OPJ_CODEC_J2K);
70
71   /* catch events using our callbacks and give a local context */
72   opj_set_info_handler(l_codec, info_callback,00);
73   opj_set_warning_handler(l_codec, warning_callback,00);
74   opj_set_error_handler(l_codec, error_callback,00);
75
76   /* setup the decoder decoding parameters using user parameters */
77   if ( !opj_setup_decoder(l_codec, &parameters) ){
78     fprintf(stderr, "ERROR -> j2k_dump: failed to setup the decoder\n");
79     return NULL;
80   }
81
82   /* Read the main header of the codestream and if necessary the JP2 boxes*/
83   if(! opj_read_header( l_stream, l_codec, &image)){
84     fprintf(stderr, "ERROR -> j2k_to_image: failed to read the header\n");
85     opj_stream_destroy(l_stream);
86     opj_destroy_codec(l_codec);
87     opj_image_destroy(image);
88     return NULL;
89   }
90
91 #ifdef TODO /*decode area could be set from j2k_to_pnm call, modify the protocol between JPIP viewer and opj_dec_server*/
92   if (! opj_set_decode_area( l_codec, image, parameters.DA_x0, parameters.DA_y0, parameters.DA_x1, parameters.DA_y1)){
93     fprintf(stderr, "ERROR -> j2k_to_image: failed to set the decoded area\n");
94     opj_stream_destroy(l_stream);
95     opj_destroy_codec(l_codec);
96     opj_image_destroy(image);
97     return NULL;
98   }
99 #endif /*TODO*/
100
101   /* Get the decoded image */
102   if ( !( opj_decode(l_codec, l_stream, image) && opj_end_decompress(l_codec,l_stream) ) ) {
103     fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n");
104     opj_stream_destroy(l_stream);
105     opj_destroy_codec(l_codec);
106     opj_image_destroy(image);
107     return NULL;
108   }
109
110   fprintf(stderr, "image is decoded!\n");
111
112   /* close the byte stream */
113   opj_stream_destroy(l_stream);
114   
115   /* create output image */
116   /* ------------------- */
117   if( (pnmstream = imagetopnm( image, ihdrbox))==NULL)
118     fprintf( stderr, "PNM image not generated\n");
119
120   /* free remaining structures */
121   if(l_codec) {
122     opj_destroy_codec(l_codec);
123   }
124
125   /* free image data structure */
126   opj_image_destroy(image);
127   
128   return pnmstream;
129 }
130
131
132 /**
133    sample error callback expecting a FILE* client object
134 */
135 static void error_callback(const char *msg, void *client_data) {
136   FILE *stream = (FILE*)client_data;
137   fprintf(stream, "[ERROR] %s", msg);
138 }
139 /**
140    sample warning callback expecting a FILE* client object
141 */
142 static void warning_callback(const char *msg, void *client_data) {
143   FILE *stream = (FILE*)client_data;
144   fprintf(stream, "[WARNING] %s", msg);
145 }
146 /**
147    sample debug callback expecting no client object
148 */
149 static void info_callback(const char *msg, void *client_data) {
150   (void)client_data;
151   (void)msg;
152   /*  fprintf(stdout, "[INFO] %s", msg); */
153 }
154
155
156 static Byte_t * imagetopnm(opj_image_t *image, ihdrbox_param_t **ihdrbox)
157 {
158   OPJ_UINT32 adjustR, adjustG=0, adjustB=0;
159   OPJ_SIZE_T datasize;
160   Byte_t *pix=NULL, *ptr=NULL;
161   OPJ_UINT32 i;
162   
163   if(*ihdrbox){
164     if( (*ihdrbox)->nc != image->numcomps)
165       fprintf( stderr, "Exception: num of components not identical, codestream: %d, ihdrbox: %d\n", image->numcomps, (*ihdrbox)->nc);
166
167     if( (*ihdrbox)->width != image->comps[0].w)
168       (*ihdrbox)->width = image->comps[0].w;
169     
170     if( (*ihdrbox)->height != image->comps[0].h)
171       (*ihdrbox)->height = image->comps[0].h;
172
173     if( (*ihdrbox)->bpc != image->comps[0].prec)
174       fprintf( stderr, "Exception: bits per component not identical, codestream: %d, ihdrbox: %d\n", image->comps[0].prec, (*ihdrbox)->bpc);
175   }
176   else{
177     *ihdrbox = (ihdrbox_param_t *)malloc( sizeof(ihdrbox_param_t));
178     (*ihdrbox)->width  = image->comps[0].w;
179     (*ihdrbox)->height = image->comps[0].h;
180     assert( image->comps[0].prec < 256 );
181     (*ihdrbox)->bpc    = (Byte_t)image->comps[0].prec;
182     assert( image->numcomps < USHRT_MAX );
183     (*ihdrbox)->nc     = (Byte2_t)image->numcomps;
184   }
185   
186   datasize = (image->numcomps)*(image->comps[0].w)*(image->comps[0].h);
187   
188   if (image->comps[0].prec > 8) {
189     adjustR = image->comps[0].prec - 8;
190     printf("PNM CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec);
191   }
192   else
193     adjustR = 0;
194   
195   if( image->numcomps == 3){
196     if (image->comps[1].prec > 8) {
197       adjustG = image->comps[1].prec - 8;
198       printf("PNM CONVERSION: Truncating component 1 from %d bits to 8 bits\n", image->comps[1].prec);
199     }
200     else 
201       adjustG = 0;
202     
203     if (image->comps[2].prec > 8) {
204       adjustB = image->comps[2].prec - 8;
205       printf("PNM CONVERSION: Truncating component 2 from %d bits to 8 bits\n", image->comps[2].prec);
206     }
207     else 
208       adjustB = 0;
209   }
210
211   pix = (Byte_t *)malloc( datasize);
212   ptr = pix;
213
214   for( i = 0; i < image->comps[0].w * image->comps[0].h; i++){
215     int r, g, b;
216     r = image->comps[0].data[i];
217     r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
218     
219     /*    if( adjustR > 0) */
220     *(ptr++) = (Byte_t) ((r >> adjustR)+((r >> (adjustR-1))%2));
221
222     if( image->numcomps == 3){
223       g = image->comps[1].data[i];
224       g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
225       *(ptr++) = (Byte_t) ((g >> adjustG)+((g >> (adjustG-1))%2));
226       
227       b = image->comps[2].data[i];
228       b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
229       *(ptr++) = (Byte_t) ((b >> adjustB)+((b >> (adjustB-1))%2));
230     }
231   }
232
233   return pix;
234 }