1 /*
2
3 rl2png -- PNG related functions
4
5 version 0.1, 2013 March 29
6
7 Author: Sandro Furieri a.furieri@lqt.it
8
9 -----------------------------------------------------------------------------
10
11 Version: MPL 1.1/GPL 2.0/LGPL 2.1
12
13 The contents of this file are subject to the Mozilla Public License Version
14 1.1 (the "License"); you may not use this file except in compliance with
15 the License. You may obtain a copy of the License at
16 http://www.mozilla.org/MPL/
17
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22
23 The Original Code is the SpatiaLite library
24
25 The Initial Developer of the Original Code is Alessandro Furieri
26
27 Portions created by the Initial Developer are Copyright (C) 2008-2013
28 the Initial Developer. All Rights Reserved.
29
30 Alternatively, the contents of this file may be used under the terms of
31 either the GNU General Public License Version 2 or later (the "GPL"), or
32 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 in which case the provisions of the GPL or the LGPL are applicable instead
34 of those above. If you wish to allow use of your version of this file only
35 under the terms of either the GPL or the LGPL, and not to allow others to
36 use your version of this file under the terms of the MPL, indicate your
37 decision by deleting the provisions above and replace them with the notice
38 and other provisions required by the GPL or the LGPL. If you do not delete
39 the provisions above, a recipient may use your version of this file under
40 the terms of any one of the MPL, the GPL or the LGPL.
41
42 */
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47
48 #include <png.h>
49
50 #include "config.h"
51
52 #ifdef LOADABLE_EXTENSION
53 #include "rasterlite2/sqlite.h"
54 #endif
55
56 #include "rasterlite2/rasterlite2.h"
57 #include "rasterlite2_private.h"
58
59 struct png_memory_buffer
60 {
61 unsigned char *buffer;
62 size_t size;
63 size_t off;
64 };
65
66 static void
rl2_png_read_data(png_structp png_ptr,png_bytep data,png_size_t length)67 rl2_png_read_data (png_structp png_ptr, png_bytep data, png_size_t length)
68 {
69 struct png_memory_buffer *p = png_get_io_ptr (png_ptr);
70 size_t rd = length;
71 if (p->off + length > p->size)
72 rd = p->size - p->off;
73 if (rd != 0)
74 {
75 /* copy bytes into buffer */
76 memcpy (data, p->buffer + p->off, rd);
77 p->off += rd;
78 }
79 if (rd != length)
80 png_error (png_ptr, "Read Error: truncated data");
81 }
82
83 static void
rl2_png_write_data(png_structp png_ptr,png_bytep data,png_size_t length)84 rl2_png_write_data (png_structp png_ptr, png_bytep data, png_size_t length)
85 {
86 struct png_memory_buffer *p = png_get_io_ptr (png_ptr);
87 size_t nsize = p->size + length;
88
89 /* allocate or grow buffer */
90 if (p->buffer)
91 p->buffer = realloc (p->buffer, nsize);
92 else
93 p->buffer = malloc (nsize);
94
95 if (!p->buffer)
96 png_error (png_ptr, "Write Error");
97
98 /* copy new bytes to end of buffer */
99 memcpy (p->buffer + p->size, data, length);
100 p->size += length;
101 }
102
103 static void
rl2_png_flush(png_structp png_ptr)104 rl2_png_flush (png_structp png_ptr)
105 {
106 /* just silencing stupid compiler warnings */
107 if (png_ptr == NULL)
108 png_ptr = NULL;
109 }
110
111 static int
compress_palette_png(const unsigned char * pixels,unsigned int width,unsigned int height,rl2PalettePtr plt,unsigned char sample_type,unsigned char ** png,int * png_size)112 compress_palette_png (const unsigned char *pixels, unsigned int width,
113 unsigned int height, rl2PalettePtr plt,
114 unsigned char sample_type, unsigned char **png,
115 int *png_size)
116 {
117 /* compressing a PNG image of the PALETTE type */
118 png_structp png_ptr;
119 png_infop info_ptr;
120 int bit_depth;
121 png_bytep *row_pointers = NULL;
122 png_bytep p_out;
123 unsigned int row;
124 unsigned int col;
125 png_color palette[256];
126 unsigned short num_entries;
127 unsigned char *red = NULL;
128 unsigned char *green = NULL;
129 unsigned char *blue = NULL;
130 int i;
131 const unsigned char *p_in;
132 struct png_memory_buffer membuf;
133 membuf.buffer = NULL;
134 membuf.size = 0;
135
136 png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
137 if (!png_ptr)
138 return RL2_ERROR;
139 info_ptr = png_create_info_struct (png_ptr);
140 if (!info_ptr)
141 {
142 png_destroy_write_struct (&png_ptr, NULL);
143 return RL2_ERROR;
144 }
145 if (setjmp (png_jmpbuf (png_ptr)))
146 {
147 goto error;
148 }
149
150 png_set_write_fn (png_ptr, &membuf, rl2_png_write_data, rl2_png_flush);
151 switch (sample_type)
152 {
153 case RL2_SAMPLE_1_BIT:
154 bit_depth = 1;
155 break;
156 case RL2_SAMPLE_2_BIT:
157 bit_depth = 2;
158 break;
159 case RL2_SAMPLE_4_BIT:
160 bit_depth = 4;
161 break;
162 case RL2_SAMPLE_UINT8:
163 bit_depth = 8;
164 break;
165 };
166 png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth,
167 PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
168 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
169 /* setting the palette */
170 if (plt == NULL)
171 goto error;
172 if (rl2_get_palette_colors (plt, &num_entries, &red, &green, &blue)
173 != RL2_OK)
174 goto error;
175 for (i = 0; i < num_entries; i++)
176 {
177 palette[i].red = *(red + i);
178 palette[i].green = *(green + i);
179 palette[i].blue = *(blue + i);
180 }
181 png_set_PLTE (png_ptr, info_ptr, palette, num_entries);
182 png_write_info (png_ptr, info_ptr);
183 png_set_packing (png_ptr);
184 row_pointers = malloc (sizeof (png_bytep) * height);
185 if (row_pointers == NULL)
186 goto error;
187 for (row = 0; row < height; ++row)
188 row_pointers[row] = NULL;
189 p_in = pixels;
190 for (row = 0; row < height; row++)
191 {
192 if ((row_pointers[row] = malloc (width)) == NULL)
193 goto error;
194 p_out = row_pointers[row];
195 for (col = 0; col < width; col++)
196 *p_out++ = *p_in++;
197 }
198 png_write_image (png_ptr, row_pointers);
199 png_write_end (png_ptr, info_ptr);
200 for (row = 0; row < height; ++row)
201 free (row_pointers[row]);
202 free (row_pointers);
203 png_destroy_write_struct (&png_ptr, &info_ptr);
204 if (red != NULL)
205 rl2_free (red);
206 if (green != NULL)
207 rl2_free (green);
208 if (blue != NULL)
209 rl2_free (blue);
210 *png = membuf.buffer;
211 *png_size = membuf.size;
212 return RL2_OK;
213
214 error:
215 png_destroy_write_struct (&png_ptr, &info_ptr);
216 for (row = 0; row < height; ++row)
217 free (row_pointers[row]);
218 free (row_pointers);
219 if (membuf.buffer != NULL)
220 free (membuf.buffer);
221 if (red != NULL)
222 rl2_free (red);
223 if (green != NULL)
224 rl2_free (green);
225 if (blue != NULL)
226 rl2_free (blue);
227 return RL2_ERROR;
228 }
229
230 static int
compress_grayscale_png(const unsigned char * pixels,const unsigned char * mask,double opacity,unsigned int width,unsigned int height,unsigned char sample_type,unsigned char pixel_type,unsigned char ** png,int * png_size)231 compress_grayscale_png (const unsigned char *pixels, const unsigned char *mask,
232 double opacity, unsigned int width,
233 unsigned int height, unsigned char sample_type,
234 unsigned char pixel_type, unsigned char **png,
235 int *png_size)
236 {
237 /* compressing a PNG image of the GRAYSCALE type */
238 png_structp png_ptr;
239 png_infop info_ptr;
240 int bit_depth;
241 png_bytep *row_pointers = NULL;
242 png_bytep p_out;
243 unsigned int row;
244 unsigned int col;
245 const unsigned char *p_in;
246 const unsigned char *p_mask;
247 int nBands;
248 int type;
249 int is_monochrome = 0;
250 unsigned char alpha = 255;
251 struct png_memory_buffer membuf;
252 membuf.buffer = NULL;
253 membuf.size = 0;
254
255 if (opacity < 0.0)
256 opacity = 0.0;
257 if (opacity > 1.0)
258 opacity = 1.0;
259 if (opacity < 1.0)
260 alpha = (unsigned char) (255.0 * opacity);
261
262 if (pixel_type == RL2_PIXEL_MONOCHROME)
263 is_monochrome = 1;
264
265 png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
266 if (!png_ptr)
267 return RL2_ERROR;
268 info_ptr = png_create_info_struct (png_ptr);
269 if (!info_ptr)
270 {
271 png_destroy_write_struct (&png_ptr, NULL);
272 return RL2_ERROR;
273 }
274 if (setjmp (png_jmpbuf (png_ptr)))
275 {
276 goto error;
277 }
278
279 png_set_write_fn (png_ptr, &membuf, rl2_png_write_data, rl2_png_flush);
280 switch (sample_type)
281 {
282 case RL2_SAMPLE_1_BIT:
283 bit_depth = 1;
284 break;
285 case RL2_SAMPLE_2_BIT:
286 bit_depth = 2;
287 break;
288 case RL2_SAMPLE_4_BIT:
289 bit_depth = 4;
290 break;
291 case RL2_SAMPLE_UINT8:
292 bit_depth = 8;
293 break;
294 };
295 p_mask = mask;
296 type = PNG_COLOR_TYPE_GRAY;
297 nBands = 1;
298 if (p_mask != NULL && sample_type == RL2_SAMPLE_UINT8)
299 {
300 type = PNG_COLOR_TYPE_GRAY_ALPHA;
301 nBands = 2;
302 }
303 png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth,
304 type, PNG_INTERLACE_NONE,
305 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
306 png_write_info (png_ptr, info_ptr);
307 png_set_packing (png_ptr);
308 row_pointers = malloc (sizeof (png_bytep) * height);
309 if (row_pointers == NULL)
310 goto error;
311 for (row = 0; row < height; ++row)
312 row_pointers[row] = NULL;
313 p_in = pixels;
314 for (row = 0; row < height; row++)
315 {
316 if ((row_pointers[row] = malloc (width * nBands)) == NULL)
317 goto error;
318 p_out = row_pointers[row];
319 for (col = 0; col < width; col++)
320 {
321 if (is_monochrome)
322 {
323 if (*p_in++ != 0)
324 *p_out++ = 255;
325 else
326 *p_out++ = 0;
327 }
328 else
329 *p_out++ = *p_in++;
330 if (type == PNG_COLOR_TYPE_GRAY_ALPHA)
331 {
332 /* ALPHA channel */
333 int transparent = *p_mask++;
334 transparent = !transparent;
335 if (transparent)
336 *p_out++ = 0;
337 else
338 *p_out++ = alpha;
339 }
340 }
341 }
342
343 png_write_image (png_ptr, row_pointers);
344 png_write_end (png_ptr, info_ptr);
345 for (row = 0; row < height; ++row)
346 free (row_pointers[row]);
347 free (row_pointers);
348 png_destroy_write_struct (&png_ptr, &info_ptr);
349 *png = membuf.buffer;
350 *png_size = membuf.size;
351 return RL2_OK;
352
353 error:
354 png_destroy_write_struct (&png_ptr, &info_ptr);
355 for (row = 0; row < height; ++row)
356 free (row_pointers[row]);
357 free (row_pointers);
358 if (membuf.buffer != NULL)
359 free (membuf.buffer);
360 return RL2_ERROR;
361 }
362
363 static int
compress_rgb_png(const unsigned char * pixels,const unsigned char * mask,double opacity,unsigned int width,unsigned int height,unsigned char ** png,int * png_size)364 compress_rgb_png (const unsigned char *pixels, const unsigned char *mask,
365 double opacity, unsigned int width, unsigned int height,
366 unsigned char **png, int *png_size)
367 {
368 /* compressing a PNG image of the RGB type */
369 png_structp png_ptr;
370 png_infop info_ptr;
371 png_bytep *row_pointers = NULL;
372 png_bytep p_out;
373 unsigned int row;
374 unsigned int col;
375 const unsigned char *p_in;
376 const unsigned char *p_mask;
377 int nBands;
378 int type;
379 unsigned char alpha = 255;
380 struct png_memory_buffer membuf;
381 membuf.buffer = NULL;
382 membuf.size = 0;
383
384 if (opacity < 0.0)
385 opacity = 0.0;
386 if (opacity > 1.0)
387 opacity = 1.0;
388 if (opacity < 1.0)
389 alpha = (unsigned char) (255.0 * opacity);
390
391 png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
392 if (!png_ptr)
393 return RL2_ERROR;
394 info_ptr = png_create_info_struct (png_ptr);
395 if (!info_ptr)
396 {
397 png_destroy_write_struct (&png_ptr, NULL);
398 return RL2_ERROR;
399 }
400 if (setjmp (png_jmpbuf (png_ptr)))
401 {
402 goto error;
403 }
404
405 png_set_write_fn (png_ptr, &membuf, rl2_png_write_data, rl2_png_flush);
406 p_mask = mask;
407 type = PNG_COLOR_TYPE_RGB;
408 nBands = 3;
409 if (p_mask != NULL)
410 {
411 type = PNG_COLOR_TYPE_RGB_ALPHA;
412 nBands = 4;
413 }
414 png_set_IHDR (png_ptr, info_ptr, width, height, 8,
415 type, PNG_INTERLACE_NONE,
416 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
417 png_write_info (png_ptr, info_ptr);
418 row_pointers = malloc (sizeof (png_bytep) * height);
419 if (row_pointers == NULL)
420 goto error;
421 for (row = 0; row < height; ++row)
422 row_pointers[row] = NULL;
423 p_in = pixels;
424 for (row = 0; row < height; row++)
425 {
426 if ((row_pointers[row] = malloc (width * nBands)) == NULL)
427 goto error;
428 p_out = row_pointers[row];
429 for (col = 0; col < width; col++)
430 {
431 *p_out++ = *p_in++;
432 *p_out++ = *p_in++;
433 *p_out++ = *p_in++;
434 if (p_mask != NULL)
435 {
436 /* ALPHA channel */
437 int transparent = *p_mask++;
438 transparent = !transparent;
439 if (transparent)
440 *p_out++ = 0;
441 else
442 *p_out++ = alpha;
443 }
444 }
445 }
446 png_write_image (png_ptr, row_pointers);
447 png_write_end (png_ptr, info_ptr);
448 for (row = 0; row < height; ++row)
449 free (row_pointers[row]);
450 free (row_pointers);
451 png_destroy_write_struct (&png_ptr, &info_ptr);
452 *png = membuf.buffer;
453 *png_size = membuf.size;
454 return RL2_OK;
455
456 error:
457 png_destroy_write_struct (&png_ptr, &info_ptr);
458 for (row = 0; row < height; ++row)
459 free (row_pointers[row]);
460 free (row_pointers);
461 if (membuf.buffer != NULL)
462 free (membuf.buffer);
463 return RL2_ERROR;
464 }
465
466 static int
check_png_compatibility(unsigned char sample_type,unsigned char pixel_type,unsigned char num_samples)467 check_png_compatibility (unsigned char sample_type, unsigned char pixel_type,
468 unsigned char num_samples)
469 {
470 /* checks for PNG compatibility */
471 switch (sample_type)
472 {
473 case RL2_SAMPLE_1_BIT:
474 case RL2_SAMPLE_2_BIT:
475 case RL2_SAMPLE_4_BIT:
476 case RL2_SAMPLE_UINT8:
477 break;
478 default:
479 return RL2_ERROR;
480 };
481 switch (pixel_type)
482 {
483 case RL2_PIXEL_MONOCHROME:
484 case RL2_PIXEL_PALETTE:
485 case RL2_PIXEL_GRAYSCALE:
486 case RL2_PIXEL_RGB:
487 break;
488 default:
489 return RL2_ERROR;
490 };
491 if (pixel_type == RL2_PIXEL_MONOCHROME)
492 {
493 switch (sample_type)
494 {
495 case RL2_SAMPLE_1_BIT:
496 break;
497 default:
498 return RL2_ERROR;
499 };
500 if (num_samples != 1)
501 return RL2_ERROR;
502 }
503 if (pixel_type == RL2_PIXEL_PALETTE)
504 {
505 switch (sample_type)
506 {
507 case RL2_SAMPLE_1_BIT:
508 case RL2_SAMPLE_2_BIT:
509 case RL2_SAMPLE_4_BIT:
510 case RL2_SAMPLE_UINT8:
511 break;
512 default:
513 return RL2_ERROR;
514 };
515 if (num_samples != 1)
516 return RL2_ERROR;
517 }
518 if (pixel_type == RL2_PIXEL_GRAYSCALE)
519 {
520 switch (sample_type)
521 {
522 case RL2_SAMPLE_2_BIT:
523 case RL2_SAMPLE_4_BIT:
524 case RL2_SAMPLE_UINT8:
525 break;
526 default:
527 return RL2_ERROR;
528 };
529 if (num_samples != 1)
530 return RL2_ERROR;
531 }
532 if (pixel_type == RL2_PIXEL_RGB)
533 {
534 switch (sample_type)
535 {
536 case RL2_SAMPLE_UINT8:
537 break;
538 default:
539 return RL2_ERROR;
540 };
541 if (num_samples != 3)
542 return RL2_ERROR;
543 }
544 return RL2_OK;
545 }
546
547 RL2_DECLARE int
rl2_section_to_png(rl2SectionPtr scn,const char * path)548 rl2_section_to_png (rl2SectionPtr scn, const char *path)
549 {
550 /* attempting to save a raster section into a PNG file */
551 int blob_size;
552 unsigned char *blob;
553 rl2RasterPtr rst;
554 int ret;
555
556 if (scn == NULL)
557 return RL2_ERROR;
558 rst = rl2_get_section_raster (scn);
559 if (rst == NULL)
560 return RL2_ERROR;
561 /* attempting to export as a PNG image */
562 if (rl2_raster_to_png (rst, &blob, &blob_size) != RL2_OK)
563 return RL2_ERROR;
564 ret = rl2_blob_to_file (path, blob, blob_size);
565 free (blob);
566 if (ret != RL2_OK)
567 return RL2_ERROR;
568 return RL2_OK;
569 }
570
571 RL2_DECLARE int
rl2_raster_to_png(rl2RasterPtr rst,unsigned char ** png,int * png_size)572 rl2_raster_to_png (rl2RasterPtr rst, unsigned char **png, int *png_size)
573 {
574 /* creating a PNG image from a raster */
575 rl2PrivRasterPtr raster = (rl2PrivRasterPtr) rst;
576 rl2PalettePtr plt;
577 unsigned char sample_type;
578 unsigned char pixel_type;
579 unsigned char num_samples;
580 unsigned char *blob;
581 int blob_size;
582 if (rst == NULL)
583 return RL2_ERROR;
584 if (rl2_get_raster_type (rst, &sample_type, &pixel_type, &num_samples) !=
585 RL2_OK)
586 return RL2_ERROR;
587 if (check_png_compatibility (sample_type, pixel_type, num_samples) !=
588 RL2_OK)
589 return RL2_ERROR;
590 plt = rl2_get_raster_palette (rst);
591
592 if (rl2_data_to_png
593 (raster->rasterBuffer, raster->maskBuffer, 1.0, plt, raster->width,
594 raster->height, sample_type, pixel_type, &blob, &blob_size) != RL2_OK)
595 return RL2_ERROR;
596 *png = blob;
597 *png_size = blob_size;
598 return RL2_OK;
599 }
600
601 RL2_DECLARE int
rl2_rgb_to_png(unsigned int width,unsigned int height,const unsigned char * rgb,unsigned char ** png,int * png_size)602 rl2_rgb_to_png (unsigned int width, unsigned int height,
603 const unsigned char *rgb, unsigned char **png, int *png_size)
604 {
605 /* creating a PNG image from an RGB buffer */
606 unsigned char *blob;
607 int blob_size;
608 if (rgb == NULL)
609 return RL2_ERROR;
610
611 if (rl2_data_to_png
612 (rgb, NULL, 1.0, NULL, width, height, RL2_SAMPLE_UINT8, RL2_PIXEL_RGB,
613 &blob, &blob_size) != RL2_OK)
614 return RL2_ERROR;
615 *png = blob;
616 *png_size = blob_size;
617 return RL2_OK;
618 }
619
620 RL2_DECLARE int
rl2_rgb_alpha_to_png(unsigned int width,unsigned int height,const unsigned char * rgb,const unsigned char * alpha,unsigned char ** png,int * png_size,double opacity)621 rl2_rgb_alpha_to_png (unsigned int width, unsigned int height,
622 const unsigned char *rgb, const unsigned char *alpha,
623 unsigned char **png, int *png_size, double opacity)
624 {
625 /* creating a PNG image from two distinct RGB + Alpha buffer */
626 unsigned char *blob;
627 int blob_size;
628 if (rgb == NULL || alpha == NULL)
629 return RL2_ERROR;
630
631 if (rl2_data_to_png
632 (rgb, alpha, opacity, NULL, width, height, RL2_SAMPLE_UINT8,
633 RL2_PIXEL_RGB, &blob, &blob_size) != RL2_OK)
634 return RL2_ERROR;
635 *png = blob;
636 *png_size = blob_size;
637 return RL2_OK;
638 }
639
640 RL2_DECLARE int
rl2_gray_to_png(unsigned int width,unsigned int height,const unsigned char * gray,unsigned char ** png,int * png_size)641 rl2_gray_to_png (unsigned int width, unsigned int height,
642 const unsigned char *gray, unsigned char **png, int *png_size)
643 {
644 /* creating a PNG image from a Grayscale buffer */
645 unsigned char *blob;
646 int blob_size;
647 if (gray == NULL)
648 return RL2_ERROR;
649
650 if (rl2_data_to_png
651 (gray, NULL, 1.0, NULL, width, height, RL2_SAMPLE_UINT8,
652 RL2_PIXEL_GRAYSCALE, &blob, &blob_size) != RL2_OK)
653 return RL2_ERROR;
654 *png = blob;
655 *png_size = blob_size;
656 return RL2_OK;
657 }
658
659 RL2_DECLARE int
rl2_gray_alpha_to_png(unsigned int width,unsigned int height,const unsigned char * gray,const unsigned char * alpha,unsigned char ** png,int * png_size,double opacity)660 rl2_gray_alpha_to_png (unsigned int width, unsigned int height,
661 const unsigned char *gray, const unsigned char *alpha,
662 unsigned char **png, int *png_size, double opacity)
663 {
664 /* creating a PNG image from two distinct Grayscale + Alpha buffer */
665 unsigned char *blob;
666 int blob_size;
667 if (gray == NULL)
668 return RL2_ERROR;
669
670 if (rl2_data_to_png
671 (gray, alpha, opacity, NULL, width, height, RL2_SAMPLE_UINT8,
672 RL2_PIXEL_GRAYSCALE, &blob, &blob_size) != RL2_OK)
673 return RL2_ERROR;
674 *png = blob;
675 *png_size = blob_size;
676 return RL2_OK;
677 }
678
679 RL2_PRIVATE int
rl2_data_to_png(const unsigned char * pixels,const unsigned char * mask,double opacity,rl2PalettePtr plt,unsigned int width,unsigned int height,unsigned char sample_type,unsigned char pixel_type,unsigned char ** png,int * png_size)680 rl2_data_to_png (const unsigned char *pixels, const unsigned char *mask,
681 double opacity, rl2PalettePtr plt, unsigned int width,
682 unsigned int height, unsigned char sample_type,
683 unsigned char pixel_type, unsigned char **png, int *png_size)
684 {
685 /* encoding a PNG image */
686 int ret;
687 unsigned char *blob;
688 int blob_size;
689
690 if (pixels == NULL)
691 return RL2_ERROR;
692 switch (pixel_type)
693 {
694 case RL2_PIXEL_PALETTE:
695 ret =
696 compress_palette_png (pixels, width, height, plt, sample_type,
697 &blob, &blob_size);
698 break;
699 case RL2_PIXEL_MONOCHROME:
700 case RL2_PIXEL_GRAYSCALE:
701 ret =
702 compress_grayscale_png (pixels, mask, opacity, width, height,
703 sample_type, pixel_type, &blob,
704 &blob_size);
705 break;
706 case RL2_PIXEL_RGB:
707 ret =
708 compress_rgb_png (pixels, mask, opacity, width, height, &blob,
709 &blob_size);
710 break;
711 };
712 if (ret != RL2_OK)
713 return RL2_ERROR;
714 *png = blob;
715 *png_size = blob_size;
716 return RL2_OK;
717 }
718
719 RL2_DECLARE rl2SectionPtr
rl2_section_from_png(const char * path)720 rl2_section_from_png (const char *path)
721 {
722 /* attempting to create a raster section from a PNG file */
723 int blob_size;
724 unsigned char *blob;
725 rl2SectionPtr scn;
726 rl2RasterPtr rst;
727
728 /* attempting to create a raster */
729 if (rl2_blob_from_file (path, &blob, &blob_size) != RL2_OK)
730 return NULL;
731 rst = rl2_raster_from_png (blob, blob_size);
732 free (blob);
733 if (rst == NULL)
734 return NULL;
735
736 /* creating the raster section */
737 scn =
738 rl2_create_section (path, RL2_COMPRESSION_PNG, RL2_TILESIZE_UNDEFINED,
739 RL2_TILESIZE_UNDEFINED, rst);
740 return scn;
741 }
742
743 RL2_DECLARE rl2RasterPtr
rl2_raster_from_png(const unsigned char * blob,int blob_size)744 rl2_raster_from_png (const unsigned char *blob, int blob_size)
745 {
746 /* attempting to create a raster from a PNG image */
747 rl2RasterPtr rst = NULL;
748 unsigned int width;
749 unsigned int height;
750 unsigned char sample_type;
751 unsigned char pixel_type;
752 unsigned char nBands;
753 unsigned char *data = NULL;
754 int data_size;
755 unsigned char *mask = NULL;
756 int mask_sz;
757 rl2PalettePtr palette = NULL;
758
759 if (rl2_decode_png
760 (blob, blob_size, &width, &height, &sample_type, &pixel_type, &nBands,
761 &data, &data_size, &mask, &mask_sz, &palette) != RL2_OK)
762 goto error;
763 rst =
764 rl2_create_raster (width, height, sample_type, pixel_type, nBands, data,
765 data_size, palette, mask, mask_sz, NULL);
766 if (rst == NULL)
767 goto error;
768 return rst;
769
770 error:
771 if (data != NULL)
772 free (data);
773 if (mask != NULL)
774 free (mask);
775 if (palette != NULL)
776 rl2_destroy_palette (palette);
777 return NULL;
778 }
779
780 RL2_PRIVATE int
rl2_decode_png(const unsigned char * blob,int blob_size,unsigned int * xwidth,unsigned int * xheight,unsigned char * xsample_type,unsigned char * xpixel_type,unsigned char * num_bands,unsigned char ** pixels,int * pixels_sz,unsigned char ** xmask,int * xmask_sz,rl2PalettePtr * xpalette)781 rl2_decode_png (const unsigned char *blob, int blob_size,
782 unsigned int *xwidth, unsigned int *xheight,
783 unsigned char *xsample_type, unsigned char *xpixel_type,
784 unsigned char *num_bands, unsigned char **pixels,
785 int *pixels_sz, unsigned char **xmask, int *xmask_sz,
786 rl2PalettePtr * xpalette)
787 {
788 /* attempting to decode a PNG image - raw block */
789 png_uint_32 width;
790 png_uint_32 height;
791 png_uint_32 rowbytes;
792 int bit_depth;
793 int color_type;
794 int interlace_type;
795 png_structp png_ptr;
796 png_infop info_ptr;
797 struct png_memory_buffer membuf;
798 unsigned char sample_type = RL2_SAMPLE_UNKNOWN;
799 unsigned char pixel_type = RL2_PIXEL_UNKNOWN;
800 int nBands;
801 int i;
802 png_colorp palette;
803 int red[256];
804 int green[256];
805 int blue[256];
806 int alpha[256];
807 unsigned char *data = NULL;
808 unsigned char *p_data;
809 unsigned char *mask = NULL;
810 int mask_sz = 0;
811 unsigned char *p_mask = NULL;
812 int data_size;
813 png_bytep image_data = NULL;
814 png_bytepp row_pointers = NULL;
815 unsigned int row;
816 unsigned int col;
817 rl2PalettePtr rl_palette = NULL;
818 int nPalette = 0;
819 png_bytep transp;
820 int nTransp;
821 png_color_16p transpValues;
822 int has_alpha = 0;
823
824 if (blob == NULL || blob_size == 0)
825 return RL2_ERROR;
826 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
827 if (!png_ptr)
828 return RL2_ERROR;
829 info_ptr = png_create_info_struct (png_ptr);
830 if (!info_ptr)
831 {
832 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
833 return RL2_ERROR;
834 }
835 if (setjmp (png_jmpbuf (png_ptr)))
836 {
837 goto error;
838 }
839
840 membuf.buffer = (unsigned char *) blob;
841 membuf.size = blob_size;
842 membuf.off = 0;
843 png_set_read_fn (png_ptr, &membuf, rl2_png_read_data);
844 png_read_info (png_ptr, info_ptr);
845 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
846 &interlace_type, NULL, NULL);
847 switch (bit_depth)
848 {
849 case 1:
850 sample_type = RL2_SAMPLE_1_BIT;
851 break;
852 case 2:
853 sample_type = RL2_SAMPLE_2_BIT;
854 break;
855 case 4:
856 sample_type = RL2_SAMPLE_4_BIT;
857 break;
858 case 8:
859 sample_type = RL2_SAMPLE_UINT8;
860 break;
861 };
862 if (bit_depth < 8)
863 png_set_packing (png_ptr);
864 switch (color_type)
865 {
866 case PNG_COLOR_TYPE_PALETTE:
867 pixel_type = RL2_PIXEL_PALETTE;
868 nBands = 1;
869 png_get_PLTE (png_ptr, info_ptr, &palette, &nPalette);
870 for (i = 0; i < nPalette; i++)
871 {
872 red[i] = palette[i].red;
873 green[i] = palette[i].green;
874 blue[i] = palette[i].blue;
875 alpha[i] = 255;
876 }
877 break;
878 case PNG_COLOR_TYPE_GRAY:
879 case PNG_COLOR_TYPE_GRAY_ALPHA:
880 pixel_type = RL2_PIXEL_GRAYSCALE;
881 if (sample_type == RL2_SAMPLE_1_BIT)
882 pixel_type = RL2_PIXEL_MONOCHROME;
883 nBands = 1;
884 break;
885 case PNG_COLOR_TYPE_RGB:
886 case PNG_COLOR_TYPE_RGB_ALPHA:
887 pixel_type = RL2_PIXEL_RGB;
888 nBands = 3;
889 break;
890 };
891 if (pixel_type == RL2_PIXEL_PALETTE)
892 {
893 if (png_get_tRNS (png_ptr, info_ptr, &transp, &nTransp, &transpValues)
894 == PNG_INFO_tRNS)
895 {
896 /* a Transparency palette is defined */
897 int i;
898 for (i = 0; i < nTransp; i++)
899 *(alpha + i) = *(transp + i);
900 has_alpha = 1;
901 }
902 }
903 /* creating the raster data */
904 data_size = width * height * nBands;
905 data = malloc (data_size);
906 if (data == NULL)
907 goto error;
908 p_data = data;
909 if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA
910 || color_type == PNG_COLOR_TYPE_RGB_ALPHA || has_alpha)
911 {
912 /* creating a transparency mask */
913 mask_sz = width * height;
914 mask = malloc (mask_sz);
915 if (mask == NULL)
916 goto error;
917 p_mask = mask;
918 }
919 png_read_update_info (png_ptr, info_ptr);
920 rowbytes = png_get_rowbytes (png_ptr, info_ptr);
921 image_data = malloc (rowbytes * height);
922 if (!image_data)
923 goto error;
924 row_pointers = malloc (height * sizeof (png_bytep));
925 if (!row_pointers)
926 goto error;
927 for (row = 0; row < height; row++)
928 row_pointers[row] = image_data + (row * rowbytes);
929 png_read_image (png_ptr, row_pointers);
930 png_read_end (png_ptr, NULL);
931 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
932 switch (color_type)
933 {
934 case PNG_COLOR_TYPE_RGB:
935 for (row = 0; row < height; row++)
936 {
937 png_bytep p_in = row_pointers[row];
938 for (col = 0; col < width; col++)
939 {
940 *p_data++ = *p_in++;
941 *p_data++ = *p_in++;
942 *p_data++ = *p_in++;
943 }
944 }
945 break;
946 case PNG_COLOR_TYPE_RGB_ALPHA:
947 for (row = 0; row < height; row++)
948 {
949 png_bytep p_in = row_pointers[row];
950 for (col = 0; col < width; col++)
951 {
952 *p_data++ = *p_in++;
953 *p_data++ = *p_in++;
954 *p_data++ = *p_in++;
955 if (p_mask != NULL)
956 {
957 if (*p_in++ < 128)
958 *p_mask++ = 0;
959 else
960 *p_mask++ = 1;
961 }
962 else
963 p_in++;
964 }
965 }
966 break;
967 case PNG_COLOR_TYPE_GRAY:
968 for (row = 0; row < height; row++)
969 {
970 png_bytep p_in = row_pointers[row];
971 for (col = 0; col < width; col++)
972 {
973 unsigned char val = *p_in++;
974 switch (sample_type)
975 {
976 case RL2_SAMPLE_1_BIT:
977 case RL2_SAMPLE_2_BIT:
978 case RL2_SAMPLE_4_BIT:
979 case RL2_SAMPLE_UINT8:
980 break;
981 default:
982 val = 0;
983 };
984 *p_data++ = val;
985 }
986 }
987 break;
988 case PNG_COLOR_TYPE_GRAY_ALPHA:
989 for (row = 0; row < height; row++)
990 {
991 png_bytep p_in = row_pointers[row];
992 for (col = 0; col < width; col++)
993 {
994 *p_data++ = *p_in++;
995 if (p_mask != NULL)
996 {
997 if (*p_in++ < 128)
998 *p_mask++ = 0;
999 else
1000 *p_mask++ = 1;
1001 }
1002 else
1003 p_in++;
1004 }
1005 }
1006 break;
1007 default: /* palette */
1008 for (row = 0; row < height; row++)
1009 {
1010 png_bytep p_in = row_pointers[row];
1011 for (col = 0; col < width; col++)
1012 {
1013 *p_data++ = *p_in;
1014 if (p_mask != NULL)
1015 {
1016 if (alpha[*p_in] < 128)
1017 *p_mask++ = 0;
1018 else
1019 *p_mask++ = 1;
1020 }
1021 p_in++;
1022 }
1023 }
1024 break;
1025 };
1026
1027 free (image_data);
1028 free (row_pointers);
1029 /* creating the raster */
1030 if (nPalette > 0)
1031 {
1032 rl_palette = rl2_create_palette (nPalette);
1033 if (rl_palette == NULL)
1034 goto error;
1035 for (i = 0; i < nPalette; i++)
1036 rl2_set_palette_color (rl_palette, i, red[i], green[i], blue[i]);
1037 }
1038 *xwidth = width;
1039 *xheight = height;
1040 *xsample_type = sample_type;
1041 *xpixel_type = pixel_type;
1042 *num_bands = nBands;
1043 *pixels = data;
1044 *pixels_sz = data_size;
1045 *xmask = mask;
1046 *xmask_sz = mask_sz;
1047 *xpalette = rl_palette;
1048 return RL2_OK;
1049
1050 error:
1051 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
1052 free (image_data);
1053 if (mask != NULL)
1054 free (mask);
1055 free (row_pointers);
1056 return RL2_ERROR;
1057 }
1058