[trunk] Make sure to use 8bits buffer when applying the ICC profile.
[openjpeg.git] / src / bin / common / color.c
1 /*
2  * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
3  * Copyright (c) 2002-2007, Professor Benoit Macq
4  * Copyright (c) 2001-2003, David Janssens
5  * Copyright (c) 2002-2003, Yannick Verschueren
6  * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe
7  * Copyright (c) 2005, Herve Drolon, FreeImage Team
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <math.h>
36 #include <assert.h>
37
38 #include "opj_apps_config.h"
39 #include "openjpeg.h"
40 #include "color.h"
41
42 #ifdef OPJ_HAVE_LIBLCMS2
43 #include <lcms2.h>
44 #endif
45 #ifdef OPJ_HAVE_LIBLCMS1
46 #include <lcms.h>
47 #endif
48
49 #ifdef OPJ_USE_LEGACY
50 #define OPJ_CLRSPC_GRAY CLRSPC_GRAY
51 #define OPJ_CLRSPC_SRGB CLRSPC_SRGB
52 #endif
53
54 /*--------------------------------------------------------
55 Matrix for sYCC, Amendment 1 to IEC 61966-2-1
56
57 Y :   0.299   0.587    0.114   :R
58 Cb:  -0.1687 -0.3312   0.5     :G
59 Cr:   0.5    -0.4187  -0.0812  :B
60
61 Inverse:
62
63 R: 1        -3.68213e-05    1.40199      :Y
64 G: 1.00003  -0.344125      -0.714128     :Cb - 2^(prec - 1)
65 B: 0.999823  1.77204       -8.04142e-06  :Cr - 2^(prec - 1)
66
67 -----------------------------------------------------------*/
68 static void sycc_to_rgb(int offset, int upb, int y, int cb, int cr,
69         int *out_r, int *out_g, int *out_b)
70 {
71         int r, g, b;
72
73         cb -= offset; cr -= offset;
74         r = y + (int)(1.402 * (float)cr);
75         if(r < 0) r = 0; else if(r > upb) r = upb; *out_r = r;
76
77         g = y - (int)(0.344 * (float)cb + 0.714 * (float)cr);
78         if(g < 0) g = 0; else if(g > upb) g = upb; *out_g = g;
79
80         b = y + (int)(1.772 * (float)cb);
81         if(b < 0) b = 0; else if(b > upb) b = upb; *out_b = b;
82 }
83
84 static void sycc444_to_rgb(opj_image_t *img)
85 {
86         int *d0, *d1, *d2, *r, *g, *b;
87         const int *y, *cb, *cr;
88         int maxw, maxh, max, i, offset, upb;
89
90         i = (int)img->comps[0].prec;
91         offset = 1<<(i - 1); upb = (1<<i)-1;
92
93         maxw = (int)img->comps[0].w; maxh = (int)img->comps[0].h;
94         max = maxw * maxh;
95
96         y = img->comps[0].data;
97         cb = img->comps[1].data;
98         cr = img->comps[2].data;
99
100         d0 = r = (int*)malloc(sizeof(int) * (size_t)max);
101         d1 = g = (int*)malloc(sizeof(int) * (size_t)max);
102         d2 = b = (int*)malloc(sizeof(int) * (size_t)max);
103
104         for(i = 0; i < max; ++i)
105    {
106         sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);        
107
108         ++y; ++cb; ++cr; ++r; ++g; ++b;
109    }    
110         free(img->comps[0].data); img->comps[0].data = d0;
111         free(img->comps[1].data); img->comps[1].data = d1;
112         free(img->comps[2].data); img->comps[2].data = d2;
113
114 }/* sycc444_to_rgb() */
115
116 static void sycc422_to_rgb(opj_image_t *img)
117 {       
118         int *d0, *d1, *d2, *r, *g, *b;
119         const int *y, *cb, *cr;
120         int maxw, maxh, max, offset, upb;
121         int i, j;
122
123         i = (int)img->comps[0].prec;
124         offset = 1<<(i - 1); upb = (1<<i)-1;
125
126         maxw = (int)img->comps[0].w; maxh = (int)img->comps[0].h;
127         max = maxw * maxh;
128
129         y = img->comps[0].data;
130         cb = img->comps[1].data;
131         cr = img->comps[2].data;
132
133         d0 = r = (int*)malloc(sizeof(int) * (size_t)max);
134         d1 = g = (int*)malloc(sizeof(int) * (size_t)max);
135         d2 = b = (int*)malloc(sizeof(int) * (size_t)max);
136
137         for(i=0; i < maxh; ++i)
138    {
139         for(j=0; j < maxw; j += 2)
140   {
141         sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
142
143         ++y; ++r; ++g; ++b;
144
145         sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
146
147         ++y; ++r; ++g; ++b; ++cb; ++cr;
148   }
149    }
150         free(img->comps[0].data); img->comps[0].data = d0;
151         free(img->comps[1].data); img->comps[1].data = d1;
152         free(img->comps[2].data); img->comps[2].data = d2;
153
154 #if defined(USE_JPWL) || defined(USE_MJ2)
155         img->comps[1].w = maxw; img->comps[1].h = maxh;
156         img->comps[2].w = maxw; img->comps[2].h = maxh;
157 #else
158         img->comps[1].w = (OPJ_UINT32)maxw; img->comps[1].h = (OPJ_UINT32)maxh;
159         img->comps[2].w = (OPJ_UINT32)maxw; img->comps[2].h = (OPJ_UINT32)maxh;
160 #endif
161         img->comps[1].dx = img->comps[0].dx;
162         img->comps[2].dx = img->comps[0].dx;
163         img->comps[1].dy = img->comps[0].dy;
164         img->comps[2].dy = img->comps[0].dy;
165
166 }/* sycc422_to_rgb() */
167
168 static void sycc420_to_rgb(opj_image_t *img)
169 {
170         int *d0, *d1, *d2, *r, *g, *b, *nr, *ng, *nb;
171         const int *y, *cb, *cr, *ny;
172         int maxw, maxh, max, offset, upb;
173         int i, j;
174
175         i = (int)img->comps[0].prec;
176         offset = 1<<(i - 1); upb = (1<<i)-1;
177
178         maxw = (int)img->comps[0].w; maxh = (int)img->comps[0].h;
179         max = maxw * maxh;
180
181         y = img->comps[0].data;
182         cb = img->comps[1].data;
183         cr = img->comps[2].data;
184
185         d0 = r = (int*)malloc(sizeof(int) * (size_t)max);
186         d1 = g = (int*)malloc(sizeof(int) * (size_t)max);
187         d2 = b = (int*)malloc(sizeof(int) * (size_t)max);
188
189         for(i=0; i < maxh; i += 2)
190    {
191         ny = y + maxw;
192         nr = r + maxw; ng = g + maxw; nb = b + maxw;
193
194         for(j=0; j < maxw;  j += 2)
195   {
196         sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
197
198         ++y; ++r; ++g; ++b;
199
200         sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
201
202         ++y; ++r; ++g; ++b;
203
204         sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
205
206         ++ny; ++nr; ++ng; ++nb;
207
208         sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
209
210         ++ny; ++nr; ++ng; ++nb; ++cb; ++cr;
211   }
212         y += maxw; r += maxw; g += maxw; b += maxw;
213    }
214         free(img->comps[0].data); img->comps[0].data = d0;
215         free(img->comps[1].data); img->comps[1].data = d1;
216         free(img->comps[2].data); img->comps[2].data = d2;
217
218 #if defined(USE_JPWL) || defined(USE_MJ2)
219         img->comps[1].w = maxw; img->comps[1].h = maxh;
220         img->comps[2].w = maxw; img->comps[2].h = maxh;
221 #else
222         img->comps[1].w = (OPJ_UINT32)maxw; img->comps[1].h = (OPJ_UINT32)maxh;
223         img->comps[2].w = (OPJ_UINT32)maxw; img->comps[2].h = (OPJ_UINT32)maxh;
224 #endif
225         img->comps[1].dx = img->comps[0].dx;
226         img->comps[2].dx = img->comps[0].dx;
227         img->comps[1].dy = img->comps[0].dy;
228         img->comps[2].dy = img->comps[0].dy;
229
230 }/* sycc420_to_rgb() */
231
232 void color_sycc_to_rgb(opj_image_t *img)
233 {
234         if(img->numcomps < 3) 
235    {
236         img->color_space = OPJ_CLRSPC_GRAY;
237         return;
238    }
239
240         if((img->comps[0].dx == 1)
241         && (img->comps[1].dx == 2)
242         && (img->comps[2].dx == 2)
243         && (img->comps[0].dy == 1)
244         && (img->comps[1].dy == 2)
245         && (img->comps[2].dy == 2))/* horizontal and vertical sub-sample */
246   {
247         sycc420_to_rgb(img);
248   }
249         else
250         if((img->comps[0].dx == 1)
251         && (img->comps[1].dx == 2)
252         && (img->comps[2].dx == 2)
253         && (img->comps[0].dy == 1)
254         && (img->comps[1].dy == 1)
255         && (img->comps[2].dy == 1))/* horizontal sub-sample only */
256   {
257         sycc422_to_rgb(img);
258   }
259         else
260         if((img->comps[0].dx == 1)
261         && (img->comps[1].dx == 1)
262         && (img->comps[2].dx == 1)
263         && (img->comps[0].dy == 1)
264         && (img->comps[1].dy == 1)
265         && (img->comps[2].dy == 1))/* no sub-sample */
266   {
267         sycc444_to_rgb(img);
268   }
269         else
270   {
271         fprintf(stderr,"%s:%d:color_sycc_to_rgb\n\tCAN NOT CONVERT\n",
272          __FILE__,__LINE__);
273         return;
274   }
275         img->color_space = OPJ_CLRSPC_SRGB;
276
277 }/* color_sycc_to_rgb() */
278
279 #if defined(OPJ_HAVE_LIBLCMS2) || defined(OPJ_HAVE_LIBLCMS1)
280 #ifdef OPJ_HAVE_LIBLCMS1
281 /* Bob Friesenhahn proposed:*/
282 #define cmsSigXYZData   icSigXYZData
283 #define cmsSigLabData   icSigLabData
284 #define cmsSigCmykData  icSigCmykData
285 #define cmsSigYCbCrData icSigYCbCrData
286 #define cmsSigLuvData   icSigLuvData
287 #define cmsSigGrayData  icSigGrayData
288 #define cmsSigRgbData   icSigRgbData
289 #define cmsUInt32Number DWORD
290
291 #define cmsColorSpaceSignature icColorSpaceSignature
292 #define cmsGetHeaderRenderingIntent cmsTakeRenderingIntent
293
294 #endif /* OPJ_HAVE_LIBLCMS1 */
295
296 /*#define DEBUG_PROFILE*/
297 void color_apply_icc_profile(opj_image_t *image)
298 {
299         cmsHPROFILE in_prof, out_prof;
300         cmsHTRANSFORM transform;
301         cmsColorSpaceSignature in_space, out_space;
302         cmsUInt32Number intent, in_type, out_type, nr_samples;
303         int *r, *g, *b;
304         int prec, i, max, max_w, max_h;
305         OPJ_COLOR_SPACE oldspace;
306
307         in_prof = 
308          cmsOpenProfileFromMem(image->icc_profile_buf, image->icc_profile_len);
309 #ifdef DEBUG_PROFILE
310   FILE *icm = fopen("debug.icm","wb");
311   fwrite( image->icc_profile_buf,1, image->icc_profile_len,icm);
312   fclose(icm);
313 #endif
314
315         if(in_prof == NULL) return;
316
317         in_space = cmsGetPCS(in_prof);
318         out_space = cmsGetColorSpace(in_prof);
319         intent = cmsGetHeaderRenderingIntent(in_prof);
320
321         
322         max_w = (int)image->comps[0].w;
323   max_h = (int)image->comps[0].h;
324         prec = (int)image->comps[0].prec;
325         oldspace = image->color_space;
326
327         if(out_space == cmsSigRgbData) /* enumCS 16 */
328    {
329   if( prec <= 8 )
330 {
331         in_type = TYPE_RGB_8;
332         out_type = TYPE_RGB_8;
333 }
334 else
335 {
336         in_type = TYPE_RGB_16;
337         out_type = TYPE_RGB_16;
338 }
339         out_prof = cmsCreate_sRGBProfile();
340         image->color_space = OPJ_CLRSPC_SRGB;
341    }
342         else
343         if(out_space == cmsSigGrayData) /* enumCS 17 */
344    {
345         in_type = TYPE_GRAY_8;
346         out_type = TYPE_RGB_8;
347         out_prof = cmsCreate_sRGBProfile();
348         image->color_space = OPJ_CLRSPC_SRGB;
349    }
350         else
351         if(out_space == cmsSigYCbCrData) /* enumCS 18 */
352    {
353         in_type = TYPE_YCbCr_16;
354         out_type = TYPE_RGB_16;
355         out_prof = cmsCreate_sRGBProfile();
356         image->color_space = OPJ_CLRSPC_SRGB;
357    }
358         else
359    {
360 #ifdef DEBUG_PROFILE
361 fprintf(stderr,"%s:%d: color_apply_icc_profile\n\tICC Profile has unknown "
362 "output colorspace(%#x)(%c%c%c%c)\n\tICC Profile ignored.\n",
363 __FILE__,__LINE__,out_space,
364 (out_space>>24) & 0xff,(out_space>>16) & 0xff,
365 (out_space>>8) & 0xff, out_space & 0xff);
366 #endif
367         return;
368    }
369
370 #ifdef DEBUG_PROFILE
371 fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tchannels(%d) prec(%d) w(%d) h(%d)"
372 "\n\tprofile: in(%p) out(%p)\n",__FILE__,__LINE__,image->numcomps,prec,
373 max_w,max_h, (void*)in_prof,(void*)out_prof);
374
375 fprintf(stderr,"\trender_intent (%u)\n\t"
376 "color_space: in(%#x)(%c%c%c%c)   out:(%#x)(%c%c%c%c)\n\t"
377 "       type: in(%u)              out:(%u)\n",
378 intent,
379 in_space,
380 (in_space>>24) & 0xff,(in_space>>16) & 0xff,
381 (in_space>>8) & 0xff, in_space & 0xff,
382
383 out_space,
384 (out_space>>24) & 0xff,(out_space>>16) & 0xff,
385 (out_space>>8) & 0xff, out_space & 0xff,
386
387 in_type,out_type
388  );
389 #else
390   (void)prec;
391   (void)in_space;
392 #endif /* DEBUG_PROFILE */
393
394         transform = cmsCreateTransform(in_prof, in_type,
395          out_prof, out_type, intent, 0);
396
397 #ifdef OPJ_HAVE_LIBLCMS2
398 /* Possible for: LCMS_VERSION >= 2000 :*/
399         cmsCloseProfile(in_prof);
400         cmsCloseProfile(out_prof);
401 #endif
402
403         if(transform == NULL)
404    {
405 #ifdef DEBUG_PROFILE
406 fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. "
407 "ICC Profile ignored.\n",__FILE__,__LINE__);
408 #endif
409         image->color_space = oldspace;
410 #ifdef OPJ_HAVE_LIBLCMS1
411         cmsCloseProfile(in_prof);
412         cmsCloseProfile(out_prof);
413 #endif
414         return;
415    }
416
417         if(image->numcomps > 2)/* RGB, RGBA */
418    {
419   if( prec <= 8 )
420 {
421         unsigned char *inbuf, *outbuf, *in, *out;
422         max = max_w * max_h;
423   nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned char);
424         in = inbuf = (unsigned char*)malloc(nr_samples);
425         out = outbuf = (unsigned char*)malloc(nr_samples);
426
427         r = image->comps[0].data;
428         g = image->comps[1].data;
429         b = image->comps[2].data;
430
431         for(i = 0; i < max; ++i)
432   {
433         *in++ = (unsigned char)*r++;
434         *in++ = (unsigned char)*g++;
435         *in++ = (unsigned char)*b++;
436   }
437
438         cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
439
440         r = image->comps[0].data;
441         g = image->comps[1].data;
442         b = image->comps[2].data;
443
444         for(i = 0; i < max; ++i)
445   {
446         *r++ = (int)*out++;
447         *g++ = (int)*out++;
448         *b++ = (int)*out++;
449   }
450         free(inbuf); free(outbuf);
451 }
452 else
453 {
454         unsigned short *inbuf, *outbuf, *in, *out;
455         max = max_w * max_h;
456   nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned short);
457         in = inbuf = (unsigned short*)malloc(nr_samples);
458         out = outbuf = (unsigned short*)malloc(nr_samples);
459
460         r = image->comps[0].data;
461         g = image->comps[1].data;
462         b = image->comps[2].data;
463
464         for(i = 0; i < max; ++i)
465   {
466         *in++ = (unsigned short)*r++;
467         *in++ = (unsigned short)*g++;
468         *in++ = (unsigned short)*b++;
469   }
470
471         cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
472
473         r = image->comps[0].data;
474         g = image->comps[1].data;
475         b = image->comps[2].data;
476
477         for(i = 0; i < max; ++i)
478   {
479         *r++ = (int)*out++;
480         *g++ = (int)*out++;
481         *b++ = (int)*out++;
482   }
483         free(inbuf); free(outbuf);
484 }
485    }
486         else /* GRAY, GRAYA */
487    {
488         unsigned char *in, *inbuf, *out, *outbuf;
489   max = max_w * max_h;
490   nr_samples = (cmsUInt32Number)max * 3 * sizeof(unsigned char);
491         in = inbuf = (unsigned char*)malloc(nr_samples);
492         out = outbuf = (unsigned char*)malloc(nr_samples);
493
494         image->comps = (opj_image_comp_t*)
495          realloc(image->comps, (image->numcomps+2)*sizeof(opj_image_comp_t));
496
497         if(image->numcomps == 2)
498          image->comps[3] = image->comps[1];
499
500         image->comps[1] = image->comps[0];
501         image->comps[2] = image->comps[0];
502
503         image->comps[1].data = (int*)calloc((size_t)max, sizeof(int));
504         image->comps[2].data = (int*)calloc((size_t)max, sizeof(int));
505
506         image->numcomps += 2;
507
508         r = image->comps[0].data;
509
510         for(i = 0; i < max; ++i)
511   {
512         *in++ = (unsigned char)*r++;
513   }
514         cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
515
516         r = image->comps[0].data;
517         g = image->comps[1].data;
518         b = image->comps[2].data;
519
520         for(i = 0; i < max; ++i)
521   {
522         *r++ = (int)*out++; *g++ = (int)*out++; *b++ = (int)*out++;
523   }
524         free(inbuf); free(outbuf);
525
526    }/* if(image->numcomps */
527
528         cmsDeleteTransform(transform);
529
530 #ifdef OPJ_HAVE_LIBLCMS1
531         cmsCloseProfile(in_prof);
532         cmsCloseProfile(out_prof);
533 #endif
534 }/* color_apply_icc_profile() */
535
536 #endif /* OPJ_HAVE_LIBLCMS2 || OPJ_HAVE_LIBLCMS1 */
537