Remove some warnings when building
[openjpeg.git] / src / bin / jp2 / convertpng.c
1 /*
2  * The copyright in this software is being made available under the 2-clauses
3  * BSD License, included below. This software may be subject to other third
4  * party and contributor rights, including patent rights, and no such rights
5  * are granted under this license.
6  *
7  * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
8  * Copyright (c) 2002-2014, Professor Benoit Macq
9  * Copyright (c) 2001-2003, David Janssens
10  * Copyright (c) 2002-2003, Yannick Verschueren
11  * Copyright (c) 2003-2007, Francois-Olivier Devaux
12  * Copyright (c) 2003-2014, Antonin Descampe
13  * Copyright (c) 2005, Herve Drolon, FreeImage Team
14  * Copyright (c) 2006-2007, Parvatha Elangovan
15  * Copyright (c) 2015, Matthieu Darbois
16  * All rights reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 #include "opj_apps_config.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45
46 #include <zlib.h>
47 #include <png.h>
48
49 #include "openjpeg.h"
50 #include "convert.h"
51
52 #define PNG_MAGIC "\x89PNG\x0d\x0a\x1a\x0a"
53 #define MAGIC_SIZE 8
54 /* PNG allows bits per sample: 1, 2, 4, 8, 16 */
55
56 typedef void (* convert_32s_CXPX)(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length);
57 static void convert_32s_C1P1(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length)
58 {
59         memcpy(pDst[0], pSrc, length * sizeof(OPJ_INT32));
60 }
61 static void convert_32s_C2P2(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length)
62 {
63         OPJ_SIZE_T i;
64         OPJ_INT32* pDst0 = pDst[0];
65         OPJ_INT32* pDst1 = pDst[1];
66         
67         for (i = 0; i < length; i++) {
68                 pDst0[i] = pSrc[2*i+0];
69                 pDst1[i] = pSrc[2*i+1];
70         }
71 }
72 static void convert_32s_C3P3(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length)
73 {
74         OPJ_SIZE_T i;
75         OPJ_INT32* pDst0 = pDst[0];
76         OPJ_INT32* pDst1 = pDst[1];
77         OPJ_INT32* pDst2 = pDst[2];
78         
79         for (i = 0; i < length; i++) {
80                 pDst0[i] = pSrc[3*i+0];
81                 pDst1[i] = pSrc[3*i+1];
82                 pDst2[i] = pSrc[3*i+2];
83         }
84 }
85 static void convert_32s_C4P4(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length)
86 {
87         OPJ_SIZE_T i;
88         OPJ_INT32* pDst0 = pDst[0];
89         OPJ_INT32* pDst1 = pDst[1];
90         OPJ_INT32* pDst2 = pDst[2];
91         OPJ_INT32* pDst3 = pDst[3];
92         
93         for (i = 0; i < length; i++) {
94                 pDst0[i] = pSrc[4*i+0];
95                 pDst1[i] = pSrc[4*i+1];
96                 pDst2[i] = pSrc[4*i+2];
97                 pDst3[i] = pSrc[4*i+3];
98         }
99 }
100
101 typedef void (* convert_XXx32s_C1R)(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length);
102 static void convert_1u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length)
103 {
104         OPJ_SIZE_T i;
105         for (i = 0; i < (length & -(OPJ_SIZE_T)8U); i+=8U) {
106                 OPJ_UINT32 val = *pSrc++;
107                 pDst[i+0] = (OPJ_INT32)( val >> 7);
108                 pDst[i+1] = (OPJ_INT32)((val >> 6) & 0x1U);
109                 pDst[i+2] = (OPJ_INT32)((val >> 5) & 0x1U);
110                 pDst[i+3] = (OPJ_INT32)((val >> 4) & 0x1U);
111                 pDst[i+4] = (OPJ_INT32)((val >> 3) & 0x1U);
112                 pDst[i+5] = (OPJ_INT32)((val >> 2) & 0x1U);
113                 pDst[i+6] = (OPJ_INT32)((val >> 1) & 0x1U);
114                 pDst[i+7] = (OPJ_INT32)(val & 0x1U);
115         }
116         if (length & 7U) {
117                 OPJ_UINT32 val = *pSrc++;
118                 length = length & 7U;
119                 pDst[i+0] = (OPJ_INT32)(val >> 7);
120                 
121                 if (length > 1U) {
122                         pDst[i+1] = (OPJ_INT32)((val >> 6) & 0x1U);
123                         if (length > 2U) {
124                                 pDst[i+2] = (OPJ_INT32)((val >> 5) & 0x1U);
125                                 if (length > 3U) {
126                                         pDst[i+3] = (OPJ_INT32)((val >> 4) & 0x1U);
127                                         if (length > 4U) {
128                                                 pDst[i+4] = (OPJ_INT32)((val >> 3) & 0x1U);
129                                                 if (length > 5U) {
130                                                         pDst[i+5] = (OPJ_INT32)((val >> 2) & 0x1U);
131                                                         if (length > 6U) {
132                                                                 pDst[i+6] = (OPJ_INT32)((val >> 1) & 0x1U);
133                                                         }
134                                                 }
135                                         }
136                                 }
137                         }
138                 }
139         }
140 }
141 static void convert_2u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length)
142 {
143         OPJ_SIZE_T i;
144         for (i = 0; i < (length & -(OPJ_SIZE_T)4U); i+=4U) {
145                 OPJ_UINT32 val = *pSrc++;
146                 pDst[i+0] = (OPJ_INT32)( val >> 6);
147                 pDst[i+1] = (OPJ_INT32)((val >> 4) & 0x3U);
148                 pDst[i+2] = (OPJ_INT32)((val >> 2) & 0x3U);
149                 pDst[i+3] = (OPJ_INT32)(val & 0x3U);
150         }
151         if (length & 3U) {
152                 OPJ_UINT32 val = *pSrc++;
153                 length = length & 3U;
154                 pDst[i+0] =  (OPJ_INT32)(val >> 6);
155                 
156                 if (length > 1U) {
157                         pDst[i+1] = (OPJ_INT32)((val >> 4) & 0x3U);
158                         if (length > 2U) {
159                                 pDst[i+2] = (OPJ_INT32)((val >> 2) & 0x3U);
160                                 
161                         }
162                 }
163         }
164 }
165 static void convert_4u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length)
166 {
167         OPJ_SIZE_T i;
168         for (i = 0; i < (length & -(OPJ_SIZE_T)2U); i+=2U) {
169                 OPJ_UINT32 val = *pSrc++;
170                 pDst[i+0] = (OPJ_INT32)(val >> 4);
171                 pDst[i+1] = (OPJ_INT32)(val & 0xFU);
172         }
173         if (length & 1U) {
174                 OPJ_UINT8 val = *pSrc++;
175                 pDst[i+0] = (OPJ_INT32)(val >> 4);
176         }
177 }
178 static void convert_8u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length)
179 {
180         OPJ_SIZE_T i;
181         for (i = 0; i < length; i++) {
182                 pDst[i] = pSrc[i];
183         }
184 }
185 static void convert_16u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length)
186 {
187         OPJ_SIZE_T i;
188         for (i = 0; i < length; i++) {
189                 OPJ_INT32 val0 = *pSrc++;
190                 OPJ_INT32 val1 = *pSrc++;
191                 pDst[i] = val0 << 8 | val1;
192         }
193 }
194
195 opj_image_t *pngtoimage(const char *read_idf, opj_cparameters_t * params)
196 {
197         png_structp  png;
198         png_infop    info;
199         double gamma;
200         int bit_depth, interlace_type,compression_type, filter_type;
201         OPJ_UINT32 i;
202         png_uint_32  width, height;
203         int color_type;
204         FILE *reader = NULL;
205         OPJ_BYTE** rows = NULL;
206         OPJ_INT32* row32s = NULL;
207         /* j2k: */
208         opj_image_t *image = NULL;
209         opj_image_cmptparm_t cmptparm[4];
210         OPJ_UINT32 nr_comp;
211         OPJ_BYTE sigbuf[8];
212         convert_XXx32s_C1R cvtXXTo32s = NULL;
213         convert_32s_CXPX cvtCxToPx = NULL;
214         OPJ_INT32* planes[4];
215         
216         if((reader = fopen(read_idf, "rb")) == NULL)
217         {
218                 fprintf(stderr,"pngtoimage: can not open %s\n",read_idf);
219                 return NULL;
220         }
221         
222         if(fread(sigbuf, 1, MAGIC_SIZE, reader) != MAGIC_SIZE
223                  || memcmp(sigbuf, PNG_MAGIC, MAGIC_SIZE) != 0)
224         {
225                 fprintf(stderr,"pngtoimage: %s is no valid PNG file\n",read_idf);
226                 goto fin;
227         }
228         
229         if((png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
230                                                                                                                                          NULL, NULL, NULL)) == NULL)
231                 goto fin;
232         if((info = png_create_info_struct(png)) == NULL)
233                 goto fin;
234         
235         if(setjmp(png_jmpbuf(png)))
236                 goto fin;
237         
238         png_init_io(png, reader);
239         png_set_sig_bytes(png, MAGIC_SIZE);
240         
241         png_read_info(png, info);
242         
243         if(png_get_IHDR(png, info, &width, &height,
244                                                                         &bit_depth, &color_type, &interlace_type,
245                                                                         &compression_type, &filter_type) == 0)
246                 goto fin;
247         
248         /* png_set_expand():
249          * expand paletted images to RGB, expand grayscale images of
250          * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
251          * to alpha channels.
252          */
253         if(color_type == PNG_COLOR_TYPE_PALETTE) {
254                 png_set_expand(png);
255         }
256         
257         if(png_get_valid(png, info, PNG_INFO_tRNS)) {
258                 png_set_expand(png);
259         }
260         /* We might wan't to expand background */
261         /*
262         if(png_get_valid(png, info, PNG_INFO_bKGD)) {
263                 png_color_16p bgnd;
264                 png_get_bKGD(png, info, &bgnd);
265                 png_set_background(png, bgnd, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
266         }
267         */
268         
269         if( !png_get_gAMA(png, info, &gamma))
270                 gamma = 1.0;
271         
272         /* we're not displaying but converting, screen gamma == 1.0 */
273         png_set_gamma(png, 1.0, gamma);
274         
275         png_read_update_info(png, info);
276         
277         color_type = png_get_color_type(png, info);
278         
279         switch (color_type) {
280                 case PNG_COLOR_TYPE_GRAY:
281                         nr_comp = 1;
282                         cvtCxToPx = convert_32s_C1P1;
283                         break;
284                 case PNG_COLOR_TYPE_GRAY_ALPHA:
285                         nr_comp = 2;
286                         cvtCxToPx = convert_32s_C2P2;
287                         break;
288                 case PNG_COLOR_TYPE_RGB:
289                         nr_comp = 3;
290                         cvtCxToPx = convert_32s_C3P3;
291                         break;
292                 case PNG_COLOR_TYPE_RGB_ALPHA:
293                         nr_comp = 4;
294                         cvtCxToPx = convert_32s_C4P4;
295                         break;
296                 default:
297                         fprintf(stderr,"pngtoimage: colortype %d is not supported\n", color_type);
298                         goto fin;
299         }
300         bit_depth = png_get_bit_depth(png, info);
301         
302         switch (bit_depth) {
303                 case 1:
304                         cvtXXTo32s = convert_1u32s_C1R;
305                         break;
306                 case 2:
307                         cvtXXTo32s = convert_2u32s_C1R;
308                         break;
309                 case 4:
310                         cvtXXTo32s = convert_4u32s_C1R;
311                         break;
312                 case 8:
313                         cvtXXTo32s = convert_8u32s_C1R;
314                         break;
315                 case 16:
316                         cvtXXTo32s = convert_16u32s_C1R;
317                         break;
318                 default:
319                         fprintf(stderr,"pngtoimage: bit depth %d is not supported\n", bit_depth);
320                         goto fin;
321         }
322
323         
324         rows = (OPJ_BYTE**)calloc(height+1, sizeof(OPJ_BYTE*));
325         for(i = 0; i < height; ++i)
326                 rows[i] = (OPJ_BYTE*)malloc(png_get_rowbytes(png,info));
327         
328         png_read_image(png, rows);
329         
330         /* Create image */
331         memset(cmptparm, 0, sizeof(cmptparm));
332         for(i = 0; i < nr_comp; ++i)
333         {
334                 cmptparm[i].prec = (OPJ_UINT32)bit_depth;
335                 /* bits_per_pixel: 8 or 16 */
336                 cmptparm[i].bpp = (OPJ_UINT32)bit_depth;
337                 cmptparm[i].sgnd = 0;
338                 cmptparm[i].dx = (OPJ_UINT32)params->subsampling_dx;
339                 cmptparm[i].dy = (OPJ_UINT32)params->subsampling_dy;
340                 cmptparm[i].w = (OPJ_UINT32)width;
341                 cmptparm[i].h = (OPJ_UINT32)height;
342         }
343         
344         image = opj_image_create(nr_comp, &cmptparm[0], (nr_comp > 2U) ? OPJ_CLRSPC_SRGB : OPJ_CLRSPC_GRAY);
345         if(image == NULL) goto fin;
346         image->x0 = (OPJ_UINT32)params->image_offset_x0;
347         image->y0 = (OPJ_UINT32)params->image_offset_y0;
348         image->x1 = (OPJ_UINT32)(image->x0 + (width  - 1) * (OPJ_UINT32)params->subsampling_dx + 1 + image->x0);
349         image->y1 = (OPJ_UINT32)(image->y0 + (height - 1) * (OPJ_UINT32)params->subsampling_dy + 1 + image->y0);
350         
351         row32s = malloc((size_t)width * nr_comp * sizeof(OPJ_INT32));
352         if(row32s == NULL) goto fin;
353         
354         /* Set alpha channel */
355         image->comps[nr_comp-1U].alpha = 1U - (nr_comp & 1U);
356         
357         for(i = 0; i < nr_comp; i++)
358         {
359                 planes[i] = image->comps[i].data;
360         }
361         
362         for(i = 0; i < height; ++i)
363         {
364                 cvtXXTo32s(rows[i], row32s, (OPJ_SIZE_T)width * nr_comp);
365                 cvtCxToPx(row32s, planes, width);
366                 planes[0] += width;
367                 planes[1] += width;
368                 planes[2] += width;
369                 planes[3] += width;
370         }
371 fin:
372         if(rows)
373         {
374                 for(i = 0; i < height; ++i)
375                         free(rows[i]);
376                 free(rows);
377         }
378         if (row32s) {
379                 free(row32s);
380         }
381         if(png)
382                 png_destroy_read_struct(&png, &info, NULL);
383         
384         fclose(reader);
385         
386         return image;
387         
388 }/* pngtoimage() */
389
390 int imagetopng(opj_image_t * image, const char *write_idf)
391 {
392         FILE *writer;
393         png_structp png;
394         png_infop info;
395         int *red, *green, *blue, *alpha;
396         unsigned char *row_buf, *d;
397         int has_alpha, width, height, nr_comp, color_type;
398         int adjustR, adjustG, adjustB, adjustA, x, y, fails;
399         int prec, ushift, dshift, is16, force16, force8;
400         unsigned short mask = 0xffff;
401         png_color_8 sig_bit;
402         
403         is16 = force16 = force8 = ushift = dshift = 0; fails = 1;
404         prec = (int)image->comps[0].prec;
405         nr_comp = (int)image->numcomps;
406         
407         if(prec > 8 && prec < 16)
408         {
409                 ushift = 16 - prec; dshift = prec - ushift;
410                 prec = 16; force16 = 1;
411         }
412         else
413                 if(prec < 8 && nr_comp > 1)/* GRAY_ALPHA, RGB, RGB_ALPHA */
414                 {
415                         ushift = 8 - prec; dshift = 8 - ushift;
416                         prec = 8; force8 = 1;
417                 }
418         
419         if(prec != 1 && prec != 2 && prec != 4 && prec != 8 && prec != 16)
420         {
421                 fprintf(stderr,"imagetopng: can not create %s"
422                                                 "\n\twrong bit_depth %d\n", write_idf, prec);
423                 return fails;
424         }
425         writer = fopen(write_idf, "wb");
426         
427         if(writer == NULL) return fails;
428         
429         info = NULL; has_alpha = 0;
430         
431         /* Create and initialize the png_struct with the desired error handler
432          * functions.  If you want to use the default stderr and longjump method,
433          * you can supply NULL for the last three parameters.  We also check that
434          * the library version is compatible with the one used at compile time,
435          * in case we are using dynamically linked libraries.  REQUIRED.
436          */
437         png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
438                                                                                                                                 NULL, NULL, NULL);
439         /*png_voidp user_error_ptr, user_error_fn, user_warning_fn); */
440         
441         if(png == NULL) goto fin;
442         
443         /* Allocate/initialize the image information data.  REQUIRED
444          */
445         info = png_create_info_struct(png);
446         
447         if(info == NULL) goto fin;
448         
449         /* Set error handling.  REQUIRED if you are not supplying your own
450          * error handling functions in the png_create_write_struct() call.
451          */
452         if(setjmp(png_jmpbuf(png))) goto fin;
453         
454         /* I/O initialization functions is REQUIRED
455          */
456         png_init_io(png, writer);
457         
458         /* Set the image information here.  Width and height are up to 2^31,
459          * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
460          * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
461          * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
462          * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
463          * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
464          * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE.
465          * REQUIRED
466          *
467          * ERRORS:
468          *
469          * color_type == PNG_COLOR_TYPE_PALETTE && bit_depth > 8
470          * color_type == PNG_COLOR_TYPE_RGB && bit_depth < 8
471          * color_type == PNG_COLOR_TYPE_GRAY_ALPHA && bit_depth < 8
472          * color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8
473          *
474          */
475         png_set_compression_level(png, Z_BEST_COMPRESSION);
476         
477         if(prec == 16) mask = 0xffff;
478         else
479                 if(prec == 8) mask = 0x00ff;
480                 else
481                         if(prec == 4) mask = 0x000f;
482                         else
483                                 if(prec == 2) mask = 0x0003;
484                                 else
485                                         if(prec == 1) mask = 0x0001;
486         
487         if(nr_comp >= 3
488                  && image->comps[0].dx == image->comps[1].dx
489                  && image->comps[1].dx == image->comps[2].dx
490                  && image->comps[0].dy == image->comps[1].dy
491                  && image->comps[1].dy == image->comps[2].dy
492                  && image->comps[0].prec == image->comps[1].prec
493                  && image->comps[1].prec == image->comps[2].prec)
494         {
495                 int v;
496                 
497                 has_alpha = (nr_comp > 3);
498                 
499                 is16 = (prec == 16);
500                 
501                 width = (int)image->comps[0].w;
502                 height = (int)image->comps[0].h;
503                 
504                 red = image->comps[0].data;
505                 green = image->comps[1].data;
506                 blue = image->comps[2].data;
507                 
508                 sig_bit.red = sig_bit.green = sig_bit.blue = (png_byte)prec;
509                 
510                 if(has_alpha)
511                 {
512                         sig_bit.alpha = (png_byte)prec;
513                         alpha = image->comps[3].data;
514                         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
515                         adjustA = (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
516                 }
517                 else
518                 {
519                         sig_bit.alpha = 0; alpha = NULL;
520                         color_type = PNG_COLOR_TYPE_RGB;
521                         adjustA = 0;
522                 }
523                 png_set_sBIT(png, info, &sig_bit);
524                 
525                 png_set_IHDR(png, info, (png_uint_32)width, (png_uint_32)height, prec,
526                                                                  color_type,
527                                                                  PNG_INTERLACE_NONE,
528                                                                  PNG_COMPRESSION_TYPE_BASE,  PNG_FILTER_TYPE_BASE);
529                 
530                 png_set_gamma(png, 2.2, 1./2.2);
531                 png_set_sRGB(png, info, PNG_sRGB_INTENT_PERCEPTUAL);
532                 /*=============================*/
533                 png_write_info(png, info);
534                 /*=============================*/
535                 if(prec < 8)
536                 {
537                         png_set_packing(png);
538                 }
539                 /*
540                 printf("%s:%d:sgnd(%d,%d,%d) w(%d) h(%d) alpha(%d)\n",__FILE__,__LINE__,
541                 image->comps[0].sgnd,
542                 image->comps[1].sgnd,image->comps[2].sgnd,width,height,has_alpha);
543                 */
544                 
545                 adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
546                 adjustG = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
547                 adjustB = (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
548                 
549                 row_buf = (unsigned char*)malloc((size_t)width * (size_t)nr_comp * 2);
550                 
551                 for(y = 0; y < height; ++y)
552                 {
553                         d = row_buf;
554                         
555                         for(x = 0; x < width; ++x)
556                         {
557                                 if(is16)
558                                 {
559                                         v = *red + adjustR; ++red;
560                                         if(v > 65535) v = 65535; else if(v < 0) v = 0;
561                                         
562                                         if(force16) { v = (v<<ushift) + (v>>dshift); }
563                                         
564                                         *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v;
565                                         
566                                         v = *green + adjustG; ++green;
567                                         if(v > 65535) v = 65535; else if(v < 0) v = 0;
568                                         
569                                         if(force16) { v = (v<<ushift) + (v>>dshift); }
570                                         
571                                         *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v;
572                                         
573                                         v =  *blue + adjustB; ++blue;
574                                         if(v > 65535) v = 65535; else if(v < 0) v = 0;
575                                         
576                                         if(force16) { v = (v<<ushift) + (v>>dshift); }
577                                         
578                                         *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v;
579                                         
580                                         if(has_alpha)
581                                         {
582                                                 v = *alpha + adjustA; ++alpha;
583                                                 if(v > 65535) v = 65535; else if(v < 0) v = 0;
584                                                 
585                                                 if(force16) { v = (v<<ushift) + (v>>dshift); }
586                                                 
587                                                 *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v;
588                                         }
589                                         continue;
590                                 }/* if(is16) */
591                                 
592                                 v = *red + adjustR; ++red;
593                                 if(v > 255) v = 255; else if(v < 0) v = 0;
594                                 
595                                 if(force8) { v = (v<<ushift) + (v>>dshift); }
596                                 
597                                 *d++ = (unsigned char)(v & mask);
598                                 
599                                 v = *green + adjustG; ++green;
600                                 if(v > 255) v = 255; else if(v < 0) v = 0;
601                                 
602                                 if(force8) { v = (v<<ushift) + (v>>dshift); }
603                                 
604                                 *d++ = (unsigned char)(v & mask);
605                                 
606                                 v = *blue + adjustB; ++blue;
607                                 if(v > 255) v = 255; else if(v < 0) v = 0;
608                                 
609                                 if(force8) { v = (v<<ushift) + (v>>dshift); }
610                                 
611                                 *d++ = (unsigned char)(v & mask);
612                                 
613                                 if(has_alpha)
614                                 {
615                                         v = *alpha + adjustA; ++alpha;
616                                         if(v > 255) v = 255; else if(v < 0) v = 0;
617                                         
618                                         if(force8) { v = (v<<ushift) + (v>>dshift); }
619                                         
620                                         *d++ = (unsigned char)(v & mask);
621                                 }
622                         }       /* for(x) */
623                         
624                         png_write_row(png, row_buf);
625                         
626                 }       /* for(y) */
627                 free(row_buf);
628                 
629         }/* nr_comp >= 3 */
630         else
631                 if(nr_comp == 1 /* GRAY */
632                          || (   nr_comp == 2 /* GRAY_ALPHA */
633                                          && image->comps[0].dx == image->comps[1].dx
634                                          && image->comps[0].dy == image->comps[1].dy
635                                          && image->comps[0].prec == image->comps[1].prec))
636                 {
637                         int v;
638                         
639                         red = image->comps[0].data;
640                         
641                         sig_bit.gray = (png_byte)prec;
642                         sig_bit.red = sig_bit.green = sig_bit.blue = sig_bit.alpha = 0;
643                         alpha = NULL; adjustA = 0;
644                         color_type = PNG_COLOR_TYPE_GRAY;
645                         
646                         if(nr_comp == 2)
647                         {
648                                 has_alpha = 1; sig_bit.alpha = (png_byte)prec;
649                                 alpha = image->comps[1].data;
650                                 color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
651                                 adjustA = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
652                         }
653                         width = (int)image->comps[0].w;
654                         height = (int)image->comps[0].h;
655                         
656                         png_set_IHDR(png, info, (png_uint_32)width, (png_uint_32)height, sig_bit.gray,
657                                                                          color_type,
658                                                                          PNG_INTERLACE_NONE,
659                                                                          PNG_COMPRESSION_TYPE_BASE,  PNG_FILTER_TYPE_BASE);
660                         
661                         png_set_sBIT(png, info, &sig_bit);
662                         
663                         png_set_gamma(png, 2.2, 1./2.2);
664                         png_set_sRGB(png, info, PNG_sRGB_INTENT_PERCEPTUAL);
665                         /*=============================*/
666                         png_write_info(png, info);
667                         /*=============================*/
668                         adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
669                         
670                         if(prec < 8)
671                         {
672                                 png_set_packing(png);
673                         }
674                         
675                         if(prec > 8)
676                         {
677                                 row_buf = (unsigned char*)
678                                 malloc((size_t)width * (size_t)nr_comp * sizeof(unsigned short));
679                                 
680                                 for(y = 0; y < height; ++y)
681                                 {
682                                         d = row_buf;
683                                         
684                                         for(x = 0; x < width; ++x)
685                                         {
686                                                 v = *red + adjustR; ++red;
687                                                 if(v > 65535) v = 65535; else if(v < 0) v = 0;
688                                                 
689                                                 if(force16) { v = (v<<ushift) + (v>>dshift); }
690                                                 
691                                                 *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v;
692                                                 
693                                                 if(has_alpha)
694                                                 {
695                                                         v = *alpha++;
696                                                         if(v > 65535) v = 65535; else if(v < 0) v = 0;
697                                                         
698                                                         if(force16) { v = (v<<ushift) + (v>>dshift); }
699                                                         
700                                                         *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v;
701                                                 }
702                                         }/* for(x) */
703                                         png_write_row(png, row_buf);
704                                         
705                                 }       /* for(y) */
706                                 free(row_buf);
707                         }
708                         else /* prec <= 8 */
709                         {
710                                 row_buf = (unsigned char*)calloc((size_t)width, (size_t)nr_comp * 2);
711                                 
712                                 for(y = 0; y < height; ++y)
713                                 {
714                                         d = row_buf;
715                                         
716                                         for(x = 0; x < width; ++x)
717                                         {
718                                                 v = *red + adjustR; ++red;
719                                                 if(v > 255) v = 255; else if(v < 0) v = 0;
720                                                 
721                                                 if(force8) { v = (v<<ushift) + (v>>dshift); }
722                                                 
723                                                 *d++ = (unsigned char)(v & mask);
724                                                 
725                                                 if(has_alpha)
726                                                 {
727                                                         v = *alpha + adjustA; ++alpha;
728                                                         if(v > 255) v = 255; else if(v < 0) v = 0;
729                                                         
730                                                         if(force8) { v = (v<<ushift) + (v>>dshift); }
731                                                         
732                                                         *d++ = (unsigned char)(v & mask);
733                                                 }
734                                         }/* for(x) */
735                                         
736                                         png_write_row(png, row_buf);
737                                         
738                                 }       /* for(y) */
739                                 free(row_buf);
740                         }
741                 }
742                 else
743                 {
744                         fprintf(stderr,"imagetopng: can not create %s\n",write_idf);
745                         goto fin;
746                 }
747         png_write_end(png, info);
748         
749         fails = 0;
750         
751 fin:
752         
753         if(png)
754         {
755                 png_destroy_write_struct(&png, &info);
756         }
757         fclose(writer);
758         
759         if(fails) remove(write_idf);
760         
761         return fails;
762 }/* imagetopng() */
763