Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgcodecs/src/grfmt_png.cpp
16337 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15
// Third party copyrights are property of their respective owners.
16
//
17
// Redistribution and use in source and binary forms, with or without modification,
18
// are permitted provided that the following conditions are met:
19
//
20
// * Redistribution's of source code must retain the above copyright notice,
21
// this list of conditions and the following disclaimer.
22
//
23
// * Redistribution's in binary form must reproduce the above copyright notice,
24
// this list of conditions and the following disclaimer in the documentation
25
// and/or other materials provided with the distribution.
26
//
27
// * The name of the copyright holders may not be used to endorse or promote products
28
// derived from this software without specific prior written permission.
29
//
30
// This software is provided by the copyright holders and contributors "as is" and
31
// any express or implied warranties, including, but not limited to, the implied
32
// warranties of merchantability and fitness for a particular purpose are disclaimed.
33
// In no event shall the Intel Corporation or contributors be liable for any direct,
34
// indirect, incidental, special, exemplary, or consequential damages
35
// (including, but not limited to, procurement of substitute goods or services;
36
// loss of use, data, or profits; or business interruption) however caused
37
// and on any theory of liability, whether in contract, strict liability,
38
// or tort (including negligence or otherwise) arising in any way out of
39
// the use of this software, even if advised of the possibility of such damage.
40
//
41
//M*/
42
43
#include "precomp.hpp"
44
45
#ifdef HAVE_PNG
46
47
/****************************************************************************************\
48
This part of the file implements PNG codec on base of libpng library,
49
in particular, this code is based on example.c from libpng
50
(see otherlibs/_graphics/readme.txt for copyright notice)
51
and png2bmp sample from libpng distribution (Copyright (C) 1999-2001 MIYASAKA Masaru)
52
\****************************************************************************************/
53
54
#ifndef _LFS64_LARGEFILE
55
# define _LFS64_LARGEFILE 0
56
#endif
57
#ifndef _FILE_OFFSET_BITS
58
# define _FILE_OFFSET_BITS 0
59
#endif
60
61
#ifdef HAVE_LIBPNG_PNG_H
62
#include <libpng/png.h>
63
#else
64
#include <png.h>
65
#endif
66
#include <zlib.h>
67
68
#include "grfmt_png.hpp"
69
70
#if defined _MSC_VER && _MSC_VER >= 1200
71
// interaction between '_setjmp' and C++ object destruction is non-portable
72
#pragma warning( disable: 4611 )
73
#endif
74
75
// the following defines are a hack to avoid multiple problems with frame ponter handling and setjmp
76
// see http://gcc.gnu.org/ml/gcc/2011-10/msg00324.html for some details
77
#define mingw_getsp(...) 0
78
#define __builtin_frame_address(...) 0
79
80
namespace cv
81
{
82
83
/////////////////////// PngDecoder ///////////////////
84
85
PngDecoder::PngDecoder()
86
{
87
m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
88
m_color_type = 0;
89
m_png_ptr = 0;
90
m_info_ptr = m_end_info = 0;
91
m_f = 0;
92
m_buf_supported = true;
93
m_buf_pos = 0;
94
m_bit_depth = 0;
95
}
96
97
98
PngDecoder::~PngDecoder()
99
{
100
close();
101
}
102
103
ImageDecoder PngDecoder::newDecoder() const
104
{
105
return makePtr<PngDecoder>();
106
}
107
108
void PngDecoder::close()
109
{
110
if( m_f )
111
{
112
fclose( m_f );
113
m_f = 0;
114
}
115
116
if( m_png_ptr )
117
{
118
png_structp png_ptr = (png_structp)m_png_ptr;
119
png_infop info_ptr = (png_infop)m_info_ptr;
120
png_infop end_info = (png_infop)m_end_info;
121
png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
122
m_png_ptr = m_info_ptr = m_end_info = 0;
123
}
124
}
125
126
127
void PngDecoder::readDataFromBuf( void* _png_ptr, uchar* dst, size_t size )
128
{
129
png_structp png_ptr = (png_structp)_png_ptr;
130
PngDecoder* decoder = (PngDecoder*)(png_get_io_ptr(png_ptr));
131
CV_Assert( decoder );
132
const Mat& buf = decoder->m_buf;
133
if( decoder->m_buf_pos + size > buf.cols*buf.rows*buf.elemSize() )
134
{
135
png_error(png_ptr, "PNG input buffer is incomplete");
136
return;
137
}
138
memcpy( dst, decoder->m_buf.ptr() + decoder->m_buf_pos, size );
139
decoder->m_buf_pos += size;
140
}
141
142
bool PngDecoder::readHeader()
143
{
144
volatile bool result = false;
145
close();
146
147
png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
148
149
if( png_ptr )
150
{
151
png_infop info_ptr = png_create_info_struct( png_ptr );
152
png_infop end_info = png_create_info_struct( png_ptr );
153
154
m_png_ptr = png_ptr;
155
m_info_ptr = info_ptr;
156
m_end_info = end_info;
157
m_buf_pos = 0;
158
159
if( info_ptr && end_info )
160
{
161
if( setjmp( png_jmpbuf( png_ptr ) ) == 0 )
162
{
163
if( !m_buf.empty() )
164
png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
165
else
166
{
167
m_f = fopen( m_filename.c_str(), "rb" );
168
if( m_f )
169
png_init_io( png_ptr, m_f );
170
}
171
172
if( !m_buf.empty() || m_f )
173
{
174
png_uint_32 wdth, hght;
175
int bit_depth, color_type, num_trans=0;
176
png_bytep trans;
177
png_color_16p trans_values;
178
179
png_read_info( png_ptr, info_ptr );
180
181
png_get_IHDR( png_ptr, info_ptr, &wdth, &hght,
182
&bit_depth, &color_type, 0, 0, 0 );
183
184
m_width = (int)wdth;
185
m_height = (int)hght;
186
m_color_type = color_type;
187
m_bit_depth = bit_depth;
188
189
if( bit_depth <= 8 || bit_depth == 16 )
190
{
191
switch(color_type)
192
{
193
case PNG_COLOR_TYPE_RGB:
194
case PNG_COLOR_TYPE_PALETTE:
195
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
196
if( num_trans > 0 )
197
m_type = CV_8UC4;
198
else
199
m_type = CV_8UC3;
200
break;
201
case PNG_COLOR_TYPE_GRAY_ALPHA:
202
case PNG_COLOR_TYPE_RGB_ALPHA:
203
m_type = CV_8UC4;
204
break;
205
default:
206
m_type = CV_8UC1;
207
}
208
if( bit_depth == 16 )
209
m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
210
result = true;
211
}
212
}
213
}
214
}
215
}
216
217
if( !result )
218
close();
219
220
return result;
221
}
222
223
224
bool PngDecoder::readData( Mat& img )
225
{
226
volatile bool result = false;
227
AutoBuffer<uchar*> _buffer(m_height);
228
uchar** buffer = _buffer.data();
229
bool color = img.channels() > 1;
230
231
png_structp png_ptr = (png_structp)m_png_ptr;
232
png_infop info_ptr = (png_infop)m_info_ptr;
233
png_infop end_info = (png_infop)m_end_info;
234
235
if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
236
{
237
if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
238
{
239
int y;
240
241
if( img.depth() == CV_8U && m_bit_depth == 16 )
242
png_set_strip_16( png_ptr );
243
else if( !isBigEndian() )
244
png_set_swap( png_ptr );
245
246
if(img.channels() < 4)
247
{
248
/* observation: png_read_image() writes 400 bytes beyond
249
* end of data when reading a 400x118 color png
250
* "mpplus_sand.png". OpenCV crashes even with demo
251
* programs. Looking at the loaded image I'd say we get 4
252
* bytes per pixel instead of 3 bytes per pixel. Test
253
* indicate that it is a good idea to always ask for
254
* stripping alpha.. 18.11.2004 Axel Walthelm
255
*/
256
png_set_strip_alpha( png_ptr );
257
} else
258
png_set_tRNS_to_alpha( png_ptr );
259
260
if( m_color_type == PNG_COLOR_TYPE_PALETTE )
261
png_set_palette_to_rgb( png_ptr );
262
263
if( (m_color_type & PNG_COLOR_MASK_COLOR) == 0 && m_bit_depth < 8 )
264
#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
265
(PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
266
png_set_expand_gray_1_2_4_to_8( png_ptr );
267
#else
268
png_set_gray_1_2_4_to_8( png_ptr );
269
#endif
270
271
if( (m_color_type & PNG_COLOR_MASK_COLOR) && color )
272
png_set_bgr( png_ptr ); // convert RGB to BGR
273
else if( color )
274
png_set_gray_to_rgb( png_ptr ); // Gray->RGB
275
else
276
png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray
277
278
png_set_interlace_handling( png_ptr );
279
png_read_update_info( png_ptr, info_ptr );
280
281
for( y = 0; y < m_height; y++ )
282
buffer[y] = img.data + y*img.step;
283
284
png_read_image( png_ptr, buffer );
285
png_read_end( png_ptr, end_info );
286
287
result = true;
288
}
289
}
290
291
close();
292
return result;
293
}
294
295
296
/////////////////////// PngEncoder ///////////////////
297
298
299
PngEncoder::PngEncoder()
300
{
301
m_description = "Portable Network Graphics files (*.png)";
302
m_buf_supported = true;
303
}
304
305
306
PngEncoder::~PngEncoder()
307
{
308
}
309
310
311
bool PngEncoder::isFormatSupported( int depth ) const
312
{
313
return depth == CV_8U || depth == CV_16U;
314
}
315
316
ImageEncoder PngEncoder::newEncoder() const
317
{
318
return makePtr<PngEncoder>();
319
}
320
321
322
void PngEncoder::writeDataToBuf(void* _png_ptr, uchar* src, size_t size)
323
{
324
if( size == 0 )
325
return;
326
png_structp png_ptr = (png_structp)_png_ptr;
327
PngEncoder* encoder = (PngEncoder*)(png_get_io_ptr(png_ptr));
328
CV_Assert( encoder && encoder->m_buf );
329
size_t cursz = encoder->m_buf->size();
330
encoder->m_buf->resize(cursz + size);
331
memcpy( &(*encoder->m_buf)[cursz], src, size );
332
}
333
334
335
void PngEncoder::flushBuf(void*)
336
{
337
}
338
339
bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
340
{
341
png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
342
png_infop info_ptr = 0;
343
FILE * volatile f = 0;
344
int y, width = img.cols, height = img.rows;
345
int depth = img.depth(), channels = img.channels();
346
volatile bool result = false;
347
AutoBuffer<uchar*> buffer;
348
349
if( depth != CV_8U && depth != CV_16U )
350
return false;
351
352
if( png_ptr )
353
{
354
info_ptr = png_create_info_struct( png_ptr );
355
356
if( info_ptr )
357
{
358
if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
359
{
360
if( m_buf )
361
{
362
png_set_write_fn(png_ptr, this,
363
(png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf);
364
}
365
else
366
{
367
f = fopen( m_filename.c_str(), "wb" );
368
if( f )
369
png_init_io( png_ptr, (png_FILE_p)f );
370
}
371
372
int compression_level = -1; // Invalid value to allow setting 0-9 as valid
373
int compression_strategy = IMWRITE_PNG_STRATEGY_RLE; // Default strategy
374
bool isBilevel = false;
375
376
for( size_t i = 0; i < params.size(); i += 2 )
377
{
378
if( params[i] == IMWRITE_PNG_COMPRESSION )
379
{
380
compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy
381
compression_level = params[i+1];
382
compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION);
383
}
384
if( params[i] == IMWRITE_PNG_STRATEGY )
385
{
386
compression_strategy = params[i+1];
387
compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED);
388
}
389
if( params[i] == IMWRITE_PNG_BILEVEL )
390
{
391
isBilevel = params[i+1] != 0;
392
}
393
}
394
395
if( m_buf || f )
396
{
397
if( compression_level >= 0 )
398
{
399
png_set_compression_level( png_ptr, compression_level );
400
}
401
else
402
{
403
// tune parameters for speed
404
// (see http://wiki.linuxquestions.org/wiki/Libpng)
405
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
406
png_set_compression_level(png_ptr, Z_BEST_SPEED);
407
}
408
png_set_compression_strategy(png_ptr, compression_strategy);
409
410
png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16,
411
channels == 1 ? PNG_COLOR_TYPE_GRAY :
412
channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
413
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
414
PNG_FILTER_TYPE_DEFAULT );
415
416
png_write_info( png_ptr, info_ptr );
417
418
if (isBilevel)
419
png_set_packing(png_ptr);
420
421
png_set_bgr( png_ptr );
422
if( !isBigEndian() )
423
png_set_swap( png_ptr );
424
425
buffer.allocate(height);
426
for( y = 0; y < height; y++ )
427
buffer[y] = img.data + y*img.step;
428
429
png_write_image( png_ptr, buffer.data() );
430
png_write_end( png_ptr, info_ptr );
431
432
result = true;
433
}
434
}
435
}
436
}
437
438
png_destroy_write_struct( &png_ptr, &info_ptr );
439
if(f) fclose( (FILE*)f );
440
441
return result;
442
}
443
444
}
445
446
#endif
447
448
/* End of file. */
449
450