Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Media Tools sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/media_dev.h>
27 : #include <gpac/internal/isomedia_dev.h>
28 : #include <gpac/constants.h>
29 :
30 : #ifdef GPAC_HAS_PNG
31 :
32 : #if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
33 : #pragma comment(lib, "libpng")
34 : #endif
35 :
36 : /*include png.h before setjmp.h, otherwise we get compilation errors*/
37 : #include <png.h>
38 :
39 : #endif /*GPAC_HAS_PNG*/
40 :
41 :
42 : #ifdef GPAC_HAS_JPEG
43 :
44 : #if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
45 : #pragma comment(lib, "libjpeg")
46 : #endif
47 :
48 : #include <jpeglib.h>
49 : #include <setjmp.h>
50 :
51 : #endif /*GPAC_HAS_JPEG*/
52 :
53 : GF_EXPORT
54 302 : void gf_img_parse(GF_BitStream *bs, u32 *codecid, u32 *width, u32 *height, u8 **dsi, u32 *dsi_len)
55 : {
56 : u8 b1, b2, b3;
57 : u32 size, type;
58 : u64 pos;
59 302 : pos = gf_bs_get_position(bs);
60 302 : gf_bs_seek(bs, 0);
61 :
62 302 : *width = *height = 0;
63 302 : *codecid = 0;
64 302 : if (dsi) {
65 302 : *dsi = NULL;
66 302 : *dsi_len = 0;
67 : }
68 :
69 302 : b1 = gf_bs_read_u8(bs);
70 302 : b2 = gf_bs_read_u8(bs);
71 302 : b3 = gf_bs_read_u8(bs);
72 : /*JPEG*/
73 302 : if ((b1==0xFF) && (b2==0xD8) && (b3==0xFF)) {
74 : u32 offset = 0;
75 : u32 Xdens, Ydens, nb_comp;
76 165 : gf_bs_read_u8(bs);
77 165 : gf_bs_skip_bytes(bs, 10); /*2 size, 5 JFIF\0, 2 version, 1 units*/
78 165 : Xdens = gf_bs_read_int(bs, 16);
79 165 : Ydens = gf_bs_read_int(bs, 16);
80 : nb_comp = 0;
81 :
82 : /*get frame header FFC0*/
83 11681437 : while (gf_bs_available(bs)) {
84 : u32 w, h,length;
85 11681107 : if (gf_bs_read_u8(bs) != 0xFF) continue;
86 38120 : if (!offset) offset = (u32)gf_bs_get_position(bs) - 1;
87 :
88 38120 : type = gf_bs_read_u8(bs);
89 : /*process all Start of Image markers*/
90 : switch (type) {
91 169 : case 0xC0:
92 : case 0xC1:
93 : case 0xC2:
94 : case 0xC3:
95 : case 0xC5:
96 : case 0xC6:
97 : case 0xC7:
98 : case 0xC9:
99 : case 0xCA:
100 : case 0xCB:
101 : case 0xCD:
102 : case 0xCE:
103 : case 0xCF:
104 169 : length = gf_bs_read_u16(bs);
105 169 : /*prec = */gf_bs_read_u8(bs);
106 169 : h = gf_bs_read_int(bs, 16);
107 169 : w = gf_bs_read_int(bs, 16);
108 169 : nb_comp = gf_bs_read_int(bs, 8);
109 169 : if (length != 8 + 3*nb_comp) continue; //This is not the right marker
110 167 : if ((w > *width) || (h > *height)) {
111 167 : *width = w;
112 167 : *height = h;
113 : }
114 : break;
115 : }
116 : }
117 165 : *codecid = GF_CODECID_JPEG;
118 165 : if (dsi) {
119 165 : GF_BitStream *bs_dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
120 165 : gf_bs_write_u16(bs_dsi, offset);
121 165 : gf_bs_write_u16(bs_dsi, Xdens);
122 165 : gf_bs_write_u16(bs_dsi, Ydens);
123 165 : gf_bs_write_u8(bs_dsi, nb_comp);
124 165 : gf_bs_get_content(bs_dsi, dsi, dsi_len);
125 165 : gf_bs_del(bs_dsi);
126 : }
127 : }
128 : /*PNG*/
129 137 : else if ((b1==0x89) && (b2==0x50) && (b3==0x4E)) {
130 : /*check for PNG sig*/
131 399 : if ( (gf_bs_read_u8(bs) != 0x47) || (gf_bs_read_u8(bs) != 0x0D) || (gf_bs_read_u8(bs) != 0x0A)
132 266 : || (gf_bs_read_u8(bs) != 0x1A) || (gf_bs_read_u8(bs) != 0x0A) ) goto exit;
133 133 : gf_bs_read_u32(bs);
134 : /*check for PNG IHDR*/
135 266 : if ( (gf_bs_read_u8(bs) != 'I') || (gf_bs_read_u8(bs) != 'H')
136 266 : || (gf_bs_read_u8(bs) != 'D') || (gf_bs_read_u8(bs) != 'R')) goto exit;
137 :
138 133 : *width = gf_bs_read_u32(bs);
139 133 : *height = gf_bs_read_u32(bs);
140 133 : *codecid = GF_CODECID_PNG;
141 : }
142 : /*try j2k*/
143 : else {
144 : u32 jp2h_size=0, jp2h_start=0;
145 4 : size = gf_bs_read_u8(bs);
146 4 : type = gf_bs_read_u32(bs);
147 4 : if ( ((size==12) && (type==GF_ISOM_BOX_TYPE_JP ))
148 0 : || (type==GF_ISOM_BOX_TYPE_JP2H ) ) {
149 :
150 4 : if (type==GF_ISOM_BOX_TYPE_JP2H) {
151 0 : *codecid = GF_CODECID_J2K;
152 0 : goto j2k_restart;
153 : }
154 :
155 4 : type = gf_bs_read_u32(bs);
156 4 : if (type!=0x0D0A870A) goto exit;
157 :
158 4 : *codecid = GF_CODECID_J2K;
159 :
160 12 : while (gf_bs_available(bs)) {
161 8 : j2k_restart:
162 12 : size = gf_bs_read_u32(bs);
163 12 : type = gf_bs_read_u32(bs);
164 12 : switch (type) {
165 4 : case GF_ISOM_BOX_TYPE_JP2H:
166 4 : jp2h_size=size-8;
167 4 : jp2h_start = (u32) gf_bs_get_position(bs);
168 4 : goto j2k_restart;
169 4 : case GF_ISOM_BOX_TYPE_IHDR:
170 : {
171 4 : *height = gf_bs_read_u32(bs);
172 4 : *width = gf_bs_read_u32(bs);
173 : /*nb_comp = gf_bs_read_u16(bs);
174 : BPC = gf_bs_read_u8(bs);
175 : C = gf_bs_read_u8(bs);
176 : UnkC = gf_bs_read_u8(bs);
177 : IPR = gf_bs_read_u8(bs);
178 : */
179 4 : if (dsi && jp2h_size) {
180 4 : *dsi = gf_malloc(sizeof(char)*jp2h_size);
181 4 : gf_bs_seek(bs, jp2h_start);
182 4 : gf_bs_read_data(bs, *dsi, jp2h_size);
183 4 : *dsi_len = jp2h_size;
184 : }
185 : goto exit;
186 : }
187 : break;
188 4 : default:
189 4 : gf_bs_skip_bytes(bs, size-8);
190 4 : break;
191 : }
192 : }
193 : }
194 : }
195 :
196 0 : exit:
197 302 : gf_bs_seek(bs, pos);
198 302 : }
199 :
200 : #ifdef GPAC_HAS_JPEG
201 :
202 5916 : void gf_jpeg_nonfatal_error2(j_common_ptr cinfo, int lev)
203 : {
204 :
205 5916 : }
206 :
207 : /*JPG context while decoding*/
208 : typedef struct
209 : {
210 : struct jpeg_error_mgr pub;
211 : jmp_buf jmpbuf;
212 : } JPGErr;
213 :
214 : typedef struct
215 : {
216 : /*io manager*/
217 : struct jpeg_source_mgr src;
218 :
219 : s32 skip;
220 : struct jpeg_decompress_struct cinfo;
221 : } JPGCtx;
222 :
223 0 : static void gf_jpeg_output_message (j_common_ptr cinfo)
224 : {
225 0 : if (cinfo) {
226 : char buffer[JMSG_LENGTH_MAX];
227 : /* Create the message */
228 0 : (*cinfo->err->format_message) (cinfo, buffer);
229 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[JPEG OUTPUT MESSAGE]: %s\n", buffer));
230 : }
231 0 : }
232 :
233 0 : static void gf_jpeg_fatal_error(j_common_ptr cinfo)
234 : {
235 0 : if (cinfo) {
236 0 : JPGErr *err = (JPGErr *) cinfo->err;
237 0 : gf_jpeg_output_message(cinfo);
238 0 : longjmp(err->jmpbuf, 1);
239 : }
240 0 : }
241 :
242 348 : void gf_jpeg_stub(j_decompress_ptr cinfo) {}
243 :
244 : /*a JPEG is always carried in a complete, single MPEG4 AU so no refill*/
245 0 : static boolean gf_jpeg_fill_input_buffer(j_decompress_ptr cinfo)
246 : {
247 0 : return 0;
248 : }
249 :
250 0 : static void gf_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
251 : {
252 0 : if (cinfo) {
253 0 : JPGCtx *jpx = (JPGCtx *) cinfo->src;
254 0 : if (num_bytes > (long) jpx->src.bytes_in_buffer) {
255 0 : jpx->skip = (s32) (num_bytes - jpx->src.bytes_in_buffer);
256 0 : jpx->src.next_input_byte += jpx->src.bytes_in_buffer;
257 0 : jpx->src.bytes_in_buffer = 0;
258 : } else {
259 0 : jpx->src.bytes_in_buffer -= num_bytes;
260 0 : jpx->src.next_input_byte += num_bytes;
261 0 : jpx->skip = 0;
262 : }
263 : }
264 0 : }
265 :
266 : #define JPEG_MAX_SCAN_BLOCK_HEIGHT 16
267 :
268 : GF_EXPORT
269 232 : GF_Err gf_img_jpeg_dec(u8 *jpg, u32 jpg_size, u32 *width, u32 *height, u32 *pixel_format, u8 *dst, u32 *dst_size, u32 dst_nb_comp)
270 : {
271 : s32 i, j, scans, k;
272 : u32 stride;
273 : char *scan_line, *ptr, *tmp;
274 : char *lines[JPEG_MAX_SCAN_BLOCK_HEIGHT];
275 : JPGErr jper;
276 : JPGCtx jpx;
277 :
278 : #ifdef GPAC_ENABLE_COVERAGE
279 232 : if (gf_sys_is_cov_mode()) {
280 : gf_jpeg_fatal_error(NULL);
281 : gf_jpeg_output_message(NULL);
282 : gf_jpeg_nonfatal_error2(NULL, 0);
283 : gf_jpeg_fill_input_buffer(NULL);
284 : gf_jpeg_skip_input_data(NULL, 0);
285 : }
286 : #endif
287 232 : if (!dst) *dst_size = 0;
288 :
289 232 : jpx.cinfo.err = jpeg_std_error(&(jper.pub));
290 232 : jper.pub.error_exit = gf_jpeg_fatal_error;
291 232 : jper.pub.output_message = gf_jpeg_output_message;
292 232 : jper.pub.emit_message = gf_jpeg_nonfatal_error2;
293 232 : if (setjmp(jper.jmpbuf)) {
294 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[JPEGDecode] : Failed to decode\n"));
295 0 : jpeg_destroy_decompress(&jpx.cinfo);
296 : return GF_IO_ERR;
297 : }
298 :
299 : /*create decompress struct*/
300 232 : jpeg_create_decompress(&jpx.cinfo);
301 :
302 : /*prepare IO*/
303 232 : jpx.src.init_source = gf_jpeg_stub;
304 232 : jpx.src.fill_input_buffer = gf_jpeg_fill_input_buffer;
305 232 : jpx.src.skip_input_data = gf_jpeg_skip_input_data;
306 232 : jpx.src.resync_to_restart = jpeg_resync_to_restart;
307 232 : jpx.src.term_source = gf_jpeg_stub;
308 232 : jpx.skip = 0;
309 232 : jpx.src.next_input_byte = (JOCTET *) jpg;
310 232 : jpx.src.bytes_in_buffer = jpg_size;
311 232 : jpx.cinfo.src = (void *) &jpx.src;
312 :
313 : /*read header*/
314 : do {
315 232 : i = jpeg_read_header(&jpx.cinfo, TRUE);
316 232 : } while (i == JPEG_HEADER_TABLES_ONLY);
317 : /*we're supposed to have the full image in the buffer, wrong stream*/
318 232 : if (i == JPEG_SUSPENDED) {
319 0 : jpeg_destroy_decompress(&jpx.cinfo);
320 : return GF_NON_COMPLIANT_BITSTREAM;
321 : }
322 :
323 232 : *width = jpx.cinfo.image_width;
324 232 : *height = jpx.cinfo.image_height;
325 232 : stride = *width * jpx.cinfo.num_components;
326 :
327 232 : switch (jpx.cinfo.num_components) {
328 0 : case 1:
329 0 : *pixel_format = GF_PIXEL_GREYSCALE;
330 0 : break;
331 232 : case 3:
332 232 : *pixel_format = GF_PIXEL_RGB;
333 232 : break;
334 0 : default:
335 0 : jpeg_destroy_decompress(&jpx.cinfo);
336 : return GF_NON_COMPLIANT_BITSTREAM;
337 : }
338 232 : if (!dst || (*dst_size < *height * *width * jpx.cinfo.num_components)) {
339 116 : *dst_size = *height * *width * jpx.cinfo.num_components;
340 116 : jpeg_destroy_decompress(&jpx.cinfo);
341 : return GF_BUFFER_TOO_SMALL;
342 : }
343 116 : if (!dst_nb_comp) dst_nb_comp = jpx.cinfo.num_components;
344 :
345 : scan_line = NULL;
346 : /*decode*/
347 116 : jpx.cinfo.do_fancy_upsampling = FALSE;
348 116 : jpx.cinfo.do_block_smoothing = FALSE;
349 116 : if (!jpeg_start_decompress(&jpx.cinfo)) {
350 0 : jpeg_destroy_decompress(&jpx.cinfo);
351 : return GF_NON_COMPLIANT_BITSTREAM;
352 : }
353 116 : if (jpx.cinfo.rec_outbuf_height>JPEG_MAX_SCAN_BLOCK_HEIGHT) {
354 0 : jpeg_destroy_decompress(&jpx.cinfo);
355 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[gf_img_jpeg_dec] : jpx.cinfo.rec_outbuf_height>JPEG_MAX_SCAN_BLOCK_HEIGHT\n"));
356 : return GF_IO_ERR;
357 : }
358 :
359 : /*read scanlines (the scan is not one line by one line so alloc a placeholder for block scaning) */
360 116 : scan_line = gf_malloc(sizeof(char) * stride * jpx.cinfo.rec_outbuf_height);
361 232 : for (i = 0; i<jpx.cinfo.rec_outbuf_height; i++) {
362 232 : lines[i] = scan_line + i * stride;
363 : }
364 : tmp = dst;
365 8756 : for (j=0; j< (s32) *height; j += jpx.cinfo.rec_outbuf_height) {
366 8756 : jpeg_read_scanlines(&jpx.cinfo, (unsigned char **) lines, jpx.cinfo.rec_outbuf_height);
367 8756 : scans = jpx.cinfo.rec_outbuf_height;
368 8756 : if (( (s32) *height - j) < scans) scans = *height - j;
369 : ptr = scan_line;
370 : /*for each line in the scan*/
371 26268 : for (k = 0; k < scans; k++) {
372 17512 : if (dst_nb_comp==(u32)jpx.cinfo.num_components) {
373 : memcpy(tmp, ptr, sizeof(char) * stride);
374 17512 : ptr += stride;
375 17512 : tmp += stride;
376 : } else {
377 : u32 z, c;
378 0 : for (z=0; z<*width; z++) {
379 0 : for (c=0; c<(u32)jpx.cinfo.num_components; c++) {
380 0 : if (c >= dst_nb_comp) break;
381 0 : tmp[c] = ptr[c];
382 : }
383 0 : ptr += jpx.cinfo.num_components;
384 0 : tmp += dst_nb_comp;
385 : }
386 : }
387 : }
388 : }
389 :
390 : /*done*/
391 116 : jpeg_finish_decompress(&jpx.cinfo);
392 116 : jpeg_destroy_decompress(&jpx.cinfo);
393 :
394 116 : gf_free(scan_line);
395 :
396 : return GF_OK;
397 : }
398 : #else
399 :
400 : GF_EXPORT
401 : GF_Err gf_img_jpeg_dec(u8 *jpg, u32 jpg_size, u32 *width, u32 *height, u32 *pixel_format, u8 *dst, u32 *dst_size, u32 dst_nb_comp)
402 : {
403 : return GF_NOT_SUPPORTED;
404 : }
405 :
406 : #endif /*GPAC_HAS_JPEG*/
407 :
408 :
409 : #ifdef GPAC_HAS_PNG
410 :
411 : typedef struct
412 : {
413 : char *buffer;
414 : u32 pos;
415 : u32 size;
416 : png_byte **rows;
417 : } GFpng;
418 :
419 5073 : static void gf_png_user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
420 : {
421 5073 : GFpng *ctx = (GFpng*)png_get_io_ptr(png_ptr);
422 :
423 5073 : if (ctx->pos + length > ctx->size) {
424 0 : png_error(png_ptr, "Read Error");
425 : } else {
426 5073 : memcpy(data, (char*) ctx->buffer + ctx->pos, length);
427 5073 : ctx->pos += (u32) length;
428 : }
429 5073 : }
430 0 : static void gf_png_user_error_fn(png_structp png_ptr,png_const_charp error_msg)
431 : {
432 0 : if (png_ptr) {
433 0 : longjmp(png_jmpbuf(png_ptr), 1);
434 : }
435 0 : }
436 :
437 :
438 : GF_EXPORT
439 230 : GF_Err gf_img_png_dec(u8 *png, u32 png_size, u32 *width, u32 *height, u32 *pixel_format, u8 *dst, u32 *dst_size)
440 : {
441 : GFpng udta;
442 : png_struct *png_ptr;
443 : png_info *info_ptr;
444 : u32 i, stride, out_size;
445 : png_bytep trans_alpha;
446 : int num_trans;
447 : png_color_16p trans_color;
448 :
449 230 : if ((png_size<8) || png_sig_cmp((png_bytep)png, 0, 8) ) {
450 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[PNG]: Wrong signature\n"));
451 : return GF_NON_COMPLIANT_BITSTREAM;
452 : }
453 230 : udta.buffer = png;
454 230 : udta.size = png_size;
455 230 : udta.pos = 0;
456 230 : udta.rows=NULL;
457 :
458 : #ifdef GPAC_ENABLE_COVERAGE
459 230 : if (gf_sys_is_cov_mode()) {
460 : gf_png_user_error_fn(NULL, NULL);
461 : }
462 : #endif
463 :
464 230 : png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) &udta, NULL, NULL);
465 230 : if (!png_ptr) return GF_IO_ERR;
466 230 : info_ptr = png_create_info_struct(png_ptr);
467 230 : if (info_ptr == NULL) {
468 0 : png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
469 : return GF_IO_ERR;
470 : }
471 230 : if (setjmp(png_jmpbuf(png_ptr))) {
472 0 : png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr);
473 0 : png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
474 0 : if (udta.rows) gf_free(udta.rows);
475 : return GF_IO_ERR;
476 : }
477 230 : png_set_read_fn(png_ptr, &udta, (png_rw_ptr) gf_png_user_read_data);
478 230 : png_set_error_fn(png_ptr, &udta, (png_error_ptr) gf_png_user_error_fn, NULL);
479 :
480 230 : png_read_info(png_ptr, info_ptr);
481 :
482 : /*unpaletize*/
483 230 : if (png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_PALETTE) {
484 0 : png_set_expand(png_ptr);
485 0 : png_read_update_info(png_ptr, info_ptr);
486 : }
487 230 : num_trans = 0;
488 230 : png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);
489 230 : if (num_trans) {
490 0 : png_set_tRNS_to_alpha(png_ptr);
491 0 : png_read_update_info(png_ptr, info_ptr);
492 : }
493 230 : *width = (u32) png_get_image_width(png_ptr, info_ptr);
494 230 : *height = (u32) png_get_image_height(png_ptr, info_ptr);
495 :
496 230 : switch (png_get_color_type(png_ptr, info_ptr)) {
497 0 : case PNG_COLOR_TYPE_GRAY:
498 0 : *pixel_format = GF_PIXEL_GREYSCALE;
499 0 : break;
500 0 : case PNG_COLOR_TYPE_GRAY_ALPHA:
501 0 : *pixel_format = GF_PIXEL_GREYALPHA;
502 0 : break;
503 2 : case PNG_COLOR_TYPE_RGB:
504 2 : *pixel_format = GF_PIXEL_RGB;
505 2 : break;
506 228 : case PNG_COLOR_TYPE_RGB_ALPHA:
507 228 : *pixel_format = GF_PIXEL_RGBA;
508 228 : break;
509 0 : default:
510 0 : png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr);
511 0 : png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
512 : return GF_NOT_SUPPORTED;
513 :
514 : }
515 :
516 230 : out_size = (u32) (png_get_rowbytes(png_ptr, info_ptr) * png_get_image_height(png_ptr, info_ptr));
517 : /*new cfg, reset*/
518 230 : if (*dst_size != out_size) {
519 115 : *dst_size = out_size;
520 115 : png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr);
521 115 : png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
522 : return GF_BUFFER_TOO_SMALL;
523 : }
524 115 : *dst_size = out_size;
525 115 : if (!dst) return GF_BAD_PARAM;
526 :
527 : /*read*/
528 115 : stride = (u32) png_get_rowbytes(png_ptr, info_ptr);
529 115 : udta.rows = (png_bytepp) gf_malloc(sizeof(png_bytep) * png_get_image_height(png_ptr, info_ptr));
530 19994 : for (i=0; i<png_get_image_height(png_ptr, info_ptr); i++) {
531 19879 : udta.rows[i] = (png_bytep)dst + i*stride;
532 : }
533 115 : png_read_image(png_ptr, udta.rows);
534 115 : png_read_end(png_ptr, NULL);
535 115 : gf_free(udta.rows);
536 :
537 115 : png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr);
538 115 : png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
539 : return GF_OK;
540 : }
541 :
542 :
543 24 : void gf_png_write(png_structp png, png_bytep data, png_size_t size)
544 : {
545 24 : GFpng *p = (GFpng *)png_get_io_ptr(png);
546 24 : memcpy(p->buffer+p->pos, data, sizeof(char)*size);
547 24 : p->pos += (u32) size;
548 24 : }
549 0 : void gf_png_flush(png_structp png)
550 : {
551 0 : }
552 :
553 : /* write a png file */
554 : GF_EXPORT
555 2 : GF_Err gf_img_png_enc(u8 *data, u32 width, u32 height, s32 stride, u32 pixel_format, u8 *dst, u32 *dst_size)
556 : {
557 : GFpng udta;
558 : png_color_8 sig_bit;
559 : png_int_32 k;
560 : png_bytep *row_pointers;
561 : png_structp png_ptr;
562 : png_infop info_ptr;
563 : u32 type, nb_comp;
564 :
565 2 : switch (pixel_format) {
566 : case GF_PIXEL_GREYSCALE:
567 : nb_comp = 1;
568 : type = PNG_COLOR_TYPE_GRAY;
569 : break;
570 0 : case GF_PIXEL_GREYALPHA:
571 : nb_comp = 1;
572 : type = PNG_COLOR_TYPE_GRAY_ALPHA;
573 0 : break;
574 2 : case GF_PIXEL_RGB:
575 : case GF_PIXEL_BGR:
576 : case GF_PIXEL_RGBX:
577 : case GF_PIXEL_BGRX:
578 : nb_comp = 3;
579 : type = PNG_COLOR_TYPE_RGB;
580 2 : break;
581 0 : case GF_PIXEL_RGBA:
582 : case GF_PIXEL_ARGB:
583 : nb_comp = 4;
584 : type = PNG_COLOR_TYPE_RGB_ALPHA;
585 0 : break;
586 : default:
587 : return GF_NOT_SUPPORTED;
588 : }
589 2 : if (*dst_size < width*height*nb_comp) return GF_BUFFER_TOO_SMALL;
590 :
591 :
592 2 : png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
593 : // png_voidp user_error_ptr, user_error_fn, user_warning_fn);
594 :
595 2 : if (png_ptr == NULL) return GF_IO_ERR;
596 :
597 : #ifdef GPAC_ENABLE_COVERAGE
598 2 : if (gf_sys_is_cov_mode()) {
599 : gf_png_flush(NULL);
600 : }
601 : #endif
602 :
603 : /* Allocate/initialize the image information data. REQUIRED */
604 2 : info_ptr = png_create_info_struct(png_ptr);
605 2 : if (info_ptr == NULL) {
606 0 : png_destroy_write_struct(&png_ptr, NULL);
607 : return GF_IO_ERR;
608 : }
609 :
610 : /* Set error handling. REQUIRED if you aren't supplying your own
611 : * error handling functions in the png_create_write_struct() call.
612 : */
613 2 : if (setjmp(png_jmpbuf(png_ptr))) {
614 0 : png_destroy_write_struct(&png_ptr, &info_ptr);
615 : return GF_NON_COMPLIANT_BITSTREAM;
616 : }
617 :
618 2 : udta.buffer = dst;
619 2 : udta.pos = 0;
620 2 : png_set_write_fn(png_ptr, &udta, gf_png_write, gf_png_flush);
621 :
622 2 : png_set_IHDR(png_ptr, info_ptr, width, height, 8, type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
623 :
624 : /* otherwise, if we are dealing with a color image then */
625 2 : sig_bit.red = 8;
626 2 : sig_bit.green = 8;
627 2 : sig_bit.blue = 8;
628 2 : sig_bit.gray = 8;
629 2 : sig_bit.alpha = 8;
630 2 : png_set_sBIT(png_ptr, info_ptr, &sig_bit);
631 :
632 : #if 0
633 : /* Optionally write comments into the image */
634 : text_ptr[0].key = "Title";
635 : text_ptr[0].text = "Mona Lisa";
636 : text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
637 : text_ptr[1].key = "Author";
638 : text_ptr[1].text = "Leonardo DaVinci";
639 : text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
640 : text_ptr[2].key = "Description";
641 : text_ptr[2].text = "<long text>";
642 : text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
643 : #ifdef PNG_iTXt_SUPPORTED
644 : text_ptr[0].lang = NULL;
645 : text_ptr[1].lang = NULL;
646 : text_ptr[2].lang = NULL;
647 : #endif
648 : png_set_text(png_ptr, info_ptr, text_ptr, 3);
649 : #endif
650 :
651 2 : png_write_info(png_ptr, info_ptr);
652 :
653 : /* Shift the pixels up to a legal bit depth and fill in
654 : * as appropriate to correctly scale the image.
655 : */
656 2 : png_set_shift(png_ptr, &sig_bit);
657 :
658 : /* pack pixels into bytes */
659 2 : png_set_packing(png_ptr);
660 :
661 2 : if (pixel_format==GF_PIXEL_ARGB) {
662 : // png_set_swap_alpha(png_ptr);
663 0 : png_set_bgr(png_ptr);
664 : }
665 2 : switch (pixel_format) {
666 0 : case GF_PIXEL_RGBX:
667 0 : png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
668 0 : png_set_bgr(png_ptr);
669 : break;
670 0 : case GF_PIXEL_BGRX:
671 0 : png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
672 : break;
673 0 : case GF_PIXEL_BGR:
674 0 : png_set_bgr(png_ptr);
675 : break;
676 : }
677 2 : row_pointers = gf_malloc(sizeof(png_bytep)*height);
678 400 : for (k = 0; k < (s32)height; k++)
679 400 : row_pointers[k] = (png_bytep) data + k*stride;
680 :
681 2 : png_write_image(png_ptr, row_pointers);
682 2 : png_write_end(png_ptr, info_ptr);
683 2 : gf_free(row_pointers);
684 : /* clean up after the write, and free any memory allocated */
685 2 : png_destroy_write_struct(&png_ptr, &info_ptr);
686 :
687 2 : *dst_size = udta.pos;
688 2 : return GF_OK;
689 : }
690 :
691 : #else
692 : GF_EXPORT
693 : GF_Err gf_img_png_dec(u8 *png, u32 png_size, u32 *width, u32 *height, u32 *pixel_format, u8 *dst, u32 *dst_size)
694 : {
695 : return GF_NOT_SUPPORTED;
696 : }
697 : GF_EXPORT
698 : GF_Err gf_img_png_enc(u8 *data, u32 width, u32 height, s32 stride, u32 pixel_format, u8 *dst, u32 *dst_size)
699 : {
700 : return GF_NOT_SUPPORTED;
701 : }
702 :
703 : #endif /*GPAC_HAS_PNG*/
704 :
705 :
|