1 /* load png from a file
2 *
3 * 5/12/11
4 * - from tiffload.c
5 * 29/8/21 joshuamsager
6 * - add "unlimited" flag to png load
7 */
8
9 /*
10
11 This file is part of VIPS.
12
13 VIPS is free software; you can redistribute it and/or modify
14 it under the terms of the GNU Lesser General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU Lesser General Public License for more details.
22
23 You should have received a copy of the GNU Lesser General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 02110-1301 USA
27
28 */
29
30 /*
31
32 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
33
34 */
35
36 /*
37 #define DEBUG
38 */
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif /*HAVE_CONFIG_H*/
43 #include <vips/intl.h>
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include <vips/vips.h>
50 #include <vips/buf.h>
51 #include <vips/internal.h>
52
53 #include "pforeign.h"
54
55 #if defined(HAVE_PNG) && !defined(HAVE_SPNG)
56
57 typedef struct _VipsForeignLoadPng {
58 VipsForeignLoad parent_object;
59
60 /* Set by subclasses.
61 */
62 VipsSource *source;
63
64 /* remove all denial of service limits.
65 */
66 gboolean unlimited;
67
68 } VipsForeignLoadPng;
69
70 typedef VipsForeignLoadClass VipsForeignLoadPngClass;
71
72 G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadPng, vips_foreign_load_png,
73 VIPS_TYPE_FOREIGN_LOAD );
74
75 static void
vips_foreign_load_png_dispose(GObject * gobject)76 vips_foreign_load_png_dispose( GObject *gobject )
77 {
78 VipsForeignLoadPng *png = (VipsForeignLoadPng *) gobject;
79
80 VIPS_UNREF( png->source );
81
82 G_OBJECT_CLASS( vips_foreign_load_png_parent_class )->
83 dispose( gobject );
84 }
85
86 static VipsForeignFlags
vips_foreign_load_png_get_flags_source(VipsSource * source)87 vips_foreign_load_png_get_flags_source( VipsSource *source )
88 {
89 VipsForeignFlags flags;
90
91 flags = 0;
92 if( vips__png_isinterlaced_source( source ) )
93 flags |= VIPS_FOREIGN_PARTIAL;
94 else
95 flags |= VIPS_FOREIGN_SEQUENTIAL;
96
97 return( flags );
98 }
99
100 static VipsForeignFlags
vips_foreign_load_png_get_flags(VipsForeignLoad * load)101 vips_foreign_load_png_get_flags( VipsForeignLoad *load )
102 {
103 VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
104
105 return( vips_foreign_load_png_get_flags_source( png->source ) );
106 }
107
108 static VipsForeignFlags
vips_foreign_load_png_get_flags_filename(const char * filename)109 vips_foreign_load_png_get_flags_filename( const char *filename )
110 {
111 VipsSource *source;
112 VipsForeignFlags flags;
113
114 if( !(source = vips_source_new_from_file( filename )) )
115 return( 0 );
116 flags = vips_foreign_load_png_get_flags_source( source );
117 VIPS_UNREF( source );
118
119 return( flags );
120 }
121
122 static int
vips_foreign_load_png_header(VipsForeignLoad * load)123 vips_foreign_load_png_header( VipsForeignLoad *load )
124 {
125 VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
126
127 if( vips__png_header_source( png->source, load->out, png->unlimited ) )
128 return( -1 );
129
130 return( 0 );
131 }
132
133 static int
vips_foreign_load_png_load(VipsForeignLoad * load)134 vips_foreign_load_png_load( VipsForeignLoad *load )
135 {
136 VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
137
138 if( vips__png_read_source( png->source, load->real,
139 load->fail_on, png->unlimited ) )
140 return( -1 );
141
142 return( 0 );
143 }
144
145 static void
vips_foreign_load_png_class_init(VipsForeignLoadPngClass * class)146 vips_foreign_load_png_class_init( VipsForeignLoadPngClass *class )
147 {
148 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
149 VipsObjectClass *object_class = (VipsObjectClass *) class;
150 VipsForeignClass *foreign_class = (VipsForeignClass *) class;
151 VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
152
153 gobject_class->dispose = vips_foreign_load_png_dispose;
154 gobject_class->set_property = vips_object_set_property;
155 gobject_class->get_property = vips_object_get_property;
156
157 object_class->nickname = "pngload_base";
158 object_class->description = _( "load png base class" );
159
160 /* We are fast at is_a(), so high priority.
161 */
162 foreign_class->priority = 200;
163
164 load_class->get_flags_filename =
165 vips_foreign_load_png_get_flags_filename;
166 load_class->get_flags = vips_foreign_load_png_get_flags;
167 load_class->header = vips_foreign_load_png_header;
168 load_class->load = vips_foreign_load_png_load;
169
170 VIPS_ARG_BOOL( class, "unlimited", 23,
171 _( "Unlimited" ),
172 _( "Remove all denial of service limits" ),
173 VIPS_ARGUMENT_OPTIONAL_INPUT,
174 G_STRUCT_OFFSET( VipsForeignLoadPng, unlimited ),
175 FALSE );
176 }
177
178 static void
vips_foreign_load_png_init(VipsForeignLoadPng * png)179 vips_foreign_load_png_init( VipsForeignLoadPng *png )
180 {
181 }
182
183 typedef struct _VipsForeignLoadPngSource {
184 VipsForeignLoadPng parent_object;
185
186 /* Load from a source.
187 */
188 VipsSource *source;
189
190 } VipsForeignLoadPngSource;
191
192 typedef VipsForeignLoadPngClass VipsForeignLoadPngSourceClass;
193
194 G_DEFINE_TYPE( VipsForeignLoadPngSource, vips_foreign_load_png_source,
195 vips_foreign_load_png_get_type() );
196
197 static int
vips_foreign_load_png_source_build(VipsObject * object)198 vips_foreign_load_png_source_build( VipsObject *object )
199 {
200 VipsForeignLoadPng *png = (VipsForeignLoadPng *) object;
201 VipsForeignLoadPngSource *source = (VipsForeignLoadPngSource *) object;
202
203 if( source->source ) {
204 png->source = source->source;
205 g_object_ref( png->source );
206 }
207
208 if( VIPS_OBJECT_CLASS( vips_foreign_load_png_source_parent_class )->
209 build( object ) )
210 return( -1 );
211
212 return( 0 );
213 }
214
215 static gboolean
vips_foreign_load_png_source_is_a_source(VipsSource * source)216 vips_foreign_load_png_source_is_a_source( VipsSource *source )
217 {
218 return( vips__png_ispng_source( source ) );
219 }
220
221 static void
vips_foreign_load_png_source_class_init(VipsForeignLoadPngSourceClass * class)222 vips_foreign_load_png_source_class_init( VipsForeignLoadPngSourceClass *class )
223 {
224 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
225 VipsObjectClass *object_class = (VipsObjectClass *) class;
226 VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
227 VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
228
229 gobject_class->set_property = vips_object_set_property;
230 gobject_class->get_property = vips_object_get_property;
231
232 object_class->nickname = "pngload_source";
233 object_class->description = _( "load png from source" );
234 object_class->build = vips_foreign_load_png_source_build;
235
236 operation_class->flags = VIPS_OPERATION_NOCACHE;
237
238 load_class->is_a_source = vips_foreign_load_png_source_is_a_source;
239
240 VIPS_ARG_OBJECT( class, "source", 1,
241 _( "Source" ),
242 _( "Source to load from" ),
243 VIPS_ARGUMENT_REQUIRED_INPUT,
244 G_STRUCT_OFFSET( VipsForeignLoadPngSource, source ),
245 VIPS_TYPE_SOURCE );
246
247 }
248
249 static void
vips_foreign_load_png_source_init(VipsForeignLoadPngSource * source)250 vips_foreign_load_png_source_init( VipsForeignLoadPngSource *source )
251 {
252 }
253
254 typedef struct _VipsForeignLoadPngFile {
255 VipsForeignLoadPng parent_object;
256
257 /* Filename for load.
258 */
259 char *filename;
260
261 } VipsForeignLoadPngFile;
262
263 typedef VipsForeignLoadPngClass VipsForeignLoadPngFileClass;
264
265 G_DEFINE_TYPE( VipsForeignLoadPngFile, vips_foreign_load_png_file,
266 vips_foreign_load_png_get_type() );
267
268 static int
vips_foreign_load_png_file_build(VipsObject * object)269 vips_foreign_load_png_file_build( VipsObject *object )
270 {
271 VipsForeignLoadPng *png = (VipsForeignLoadPng *) object;
272 VipsForeignLoadPngFile *file = (VipsForeignLoadPngFile *) object;
273
274 if( file->filename &&
275 !(png->source = vips_source_new_from_file( file->filename )) )
276 return( -1 );
277
278 if( VIPS_OBJECT_CLASS( vips_foreign_load_png_file_parent_class )->
279 build( object ) )
280 return( -1 );
281
282 return( 0 );
283 }
284
285 static gboolean
vips_foreign_load_png_file_is_a(const char * filename)286 vips_foreign_load_png_file_is_a( const char *filename )
287 {
288 VipsSource *source;
289 gboolean result;
290
291 if( !(source = vips_source_new_from_file( filename )) )
292 return( FALSE );
293 result = vips_foreign_load_png_source_is_a_source( source );
294 VIPS_UNREF( source );
295
296 return( result );
297 }
298
299 static void
vips_foreign_load_png_file_class_init(VipsForeignLoadPngFileClass * class)300 vips_foreign_load_png_file_class_init( VipsForeignLoadPngFileClass *class )
301 {
302 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
303 VipsObjectClass *object_class = (VipsObjectClass *) class;
304 VipsForeignClass *foreign_class = (VipsForeignClass *) class;
305 VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
306
307 gobject_class->set_property = vips_object_set_property;
308 gobject_class->get_property = vips_object_get_property;
309
310 object_class->nickname = "pngload";
311 object_class->description = _( "load png from file" );
312 object_class->build = vips_foreign_load_png_file_build;
313
314 foreign_class->suffs = vips__png_suffs;
315
316 load_class->is_a = vips_foreign_load_png_file_is_a;
317
318 VIPS_ARG_STRING( class, "filename", 1,
319 _( "Filename" ),
320 _( "Filename to load from" ),
321 VIPS_ARGUMENT_REQUIRED_INPUT,
322 G_STRUCT_OFFSET( VipsForeignLoadPngFile, filename ),
323 NULL );
324 }
325
326 static void
vips_foreign_load_png_file_init(VipsForeignLoadPngFile * file)327 vips_foreign_load_png_file_init( VipsForeignLoadPngFile *file )
328 {
329 }
330
331 typedef struct _VipsForeignLoadPngBuffer {
332 VipsForeignLoadPng parent_object;
333
334 /* Load from a buffer.
335 */
336 VipsBlob *blob;
337
338 } VipsForeignLoadPngBuffer;
339
340 typedef VipsForeignLoadPngClass VipsForeignLoadPngBufferClass;
341
342 G_DEFINE_TYPE( VipsForeignLoadPngBuffer, vips_foreign_load_png_buffer,
343 vips_foreign_load_png_get_type() );
344
345 static int
vips_foreign_load_png_buffer_build(VipsObject * object)346 vips_foreign_load_png_buffer_build( VipsObject *object )
347 {
348 VipsForeignLoadPng *png = (VipsForeignLoadPng *) object;
349 VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) object;
350
351 if( buffer->blob &&
352 !(png->source = vips_source_new_from_memory(
353 VIPS_AREA( buffer->blob )->data,
354 VIPS_AREA( buffer->blob )->length )) )
355 return( -1 );
356
357 if( VIPS_OBJECT_CLASS( vips_foreign_load_png_buffer_parent_class )->
358 build( object ) )
359 return( -1 );
360
361 return( 0 );
362 }
363
364 static gboolean
vips_foreign_load_png_buffer_is_a_buffer(const void * buf,size_t len)365 vips_foreign_load_png_buffer_is_a_buffer( const void *buf, size_t len )
366 {
367 VipsSource *source;
368 gboolean result;
369
370 if( !(source = vips_source_new_from_memory( buf, len )) )
371 return( FALSE );
372 result = vips_foreign_load_png_source_is_a_source( source );
373 VIPS_UNREF( source );
374
375 return( result );
376 }
377
378 static void
vips_foreign_load_png_buffer_class_init(VipsForeignLoadPngBufferClass * class)379 vips_foreign_load_png_buffer_class_init( VipsForeignLoadPngBufferClass *class )
380 {
381 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
382 VipsObjectClass *object_class = (VipsObjectClass *) class;
383 VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
384
385 gobject_class->set_property = vips_object_set_property;
386 gobject_class->get_property = vips_object_get_property;
387
388 object_class->nickname = "pngload_buffer";
389 object_class->description = _( "load png from buffer" );
390 object_class->build = vips_foreign_load_png_buffer_build;
391
392 load_class->is_a_buffer = vips_foreign_load_png_buffer_is_a_buffer;
393
394 VIPS_ARG_BOXED( class, "buffer", 1,
395 _( "Buffer" ),
396 _( "Buffer to load from" ),
397 VIPS_ARGUMENT_REQUIRED_INPUT,
398 G_STRUCT_OFFSET( VipsForeignLoadPngBuffer, blob ),
399 VIPS_TYPE_BLOB );
400
401 }
402
403 static void
vips_foreign_load_png_buffer_init(VipsForeignLoadPngBuffer * buffer)404 vips_foreign_load_png_buffer_init( VipsForeignLoadPngBuffer *buffer )
405 {
406 }
407
408 #endif /*defined(HAVE_PNG) && !defined(HAVE_SPNG)*/
409
410 /**
411 * vips_pngload:
412 * @filename: file to load
413 * @out: (out): decompressed image
414 * @...: %NULL-terminated list of optional named arguments
415 *
416 * Optional arguments:
417 *
418 * * @fail_on: #VipsFailOn, types of read error to fail on
419 * * @unlimited: %gboolean, remove all denial of service limits
420 *
421 * Read a PNG file into a VIPS image. It can read all png images, including 8-
422 * and 16-bit images, 1 and 3 channel, with and without an alpha channel.
423 *
424 * Any ICC profile is read and attached to the VIPS image. It also supports
425 * XMP metadata.
426 *
427 * Use @fail_on to set the type of error that will cause load to fail. By
428 * default, loaders are permissive, that is, #VIPS_FAIL_ON_NONE.
429 *
430 * By default, the PNG loader limits the number of text and data chunks to
431 * block some denial of service attacks. Set @unlimited to disable these
432 * limits.
433 *
434 * See also: vips_image_new_from_file().
435 *
436 * Returns: 0 on success, -1 on error.
437 */
438 int
vips_pngload(const char * filename,VipsImage ** out,...)439 vips_pngload( const char *filename, VipsImage **out, ... )
440 {
441 va_list ap;
442 int result;
443
444 va_start( ap, out );
445 result = vips_call_split( "pngload", ap, filename, out );
446 va_end( ap );
447
448 return( result );
449 }
450
451 /**
452 * vips_pngload_buffer:
453 * @buf: (array length=len) (element-type guint8): memory area to load
454 * @len: (type gsize): size of memory area
455 * @out: (out): image to write
456 * @...: %NULL-terminated list of optional named arguments
457 *
458 * Optional arguments:
459 *
460 * * @fail_on: #VipsFailOn, types of read error to fail on
461 * * @unlimited: %gboolean, Remove all denial of service limits
462 *
463 * Exactly as vips_pngload(), but read from a PNG-formatted memory block.
464 *
465 * You must not free the buffer while @out is active. The
466 * #VipsObject::postclose signal on @out is a good place to free.
467 *
468 * See also: vips_pngload().
469 *
470 * Returns: 0 on success, -1 on error.
471 */
472 int
vips_pngload_buffer(void * buf,size_t len,VipsImage ** out,...)473 vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
474 {
475 va_list ap;
476 VipsBlob *blob;
477 int result;
478
479 /* We don't take a copy of the data or free it.
480 */
481 blob = vips_blob_new( NULL, buf, len );
482
483 va_start( ap, out );
484 result = vips_call_split( "pngload_buffer", ap, blob, out );
485 va_end( ap );
486
487 vips_area_unref( VIPS_AREA( blob ) );
488
489 return( result );
490 }
491
492 /**
493 * vips_pngload_source:
494 * @source: source to load from
495 * @out: (out): image to write
496 * @...: %NULL-terminated list of optional named arguments
497 *
498 * Optional arguments:
499 *
500 * * @fail_on: #VipsFailOn, types of read error to fail on
501 * * @unlimited: %gboolean, Remove all denial of service limits
502 *
503 * Exactly as vips_pngload(), but read from a source.
504 *
505 * See also: vips_pngload().
506 *
507 * Returns: 0 on success, -1 on error.
508 */
509 int
vips_pngload_source(VipsSource * source,VipsImage ** out,...)510 vips_pngload_source( VipsSource *source, VipsImage **out, ... )
511 {
512 va_list ap;
513 int result;
514
515 va_start( ap, out );
516 result = vips_call_split( "pngload_source", ap, source, out );
517 va_end( ap );
518
519 return( result );
520 }
521