1 /* load tiff from a file
2  *
3  * 5/12/11
4  * 	- from tiffload.c
5  * 27/1/17
6  * 	- add get_flags for buffer loader
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 #ifdef HAVE_TIFF
56 
57 typedef struct _VipsForeignLoadTiff {
58 	VipsForeignLoad parent_object;
59 
60 	/* Set by subclasses.
61 	 */
62 	VipsSource *source;
63 
64 	/* Load this page.
65 	 */
66 	int page;
67 
68 	/* Load this many pages.
69 	 */
70 	int n;
71 
72 	/* Select subifd index. -1 for main image.
73 	 */
74 	int subifd;
75 
76 	/* Autorotate using orientation tag.
77 	 */
78 	gboolean autorotate;
79 
80 } VipsForeignLoadTiff;
81 
82 typedef VipsForeignLoadClass VipsForeignLoadTiffClass;
83 
84 G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadTiff, vips_foreign_load_tiff,
85 	VIPS_TYPE_FOREIGN_LOAD );
86 
87 static void
vips_foreign_load_tiff_dispose(GObject * gobject)88 vips_foreign_load_tiff_dispose( GObject *gobject )
89 {
90 	VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) gobject;
91 
92 	VIPS_UNREF( tiff->source );
93 
94 	G_OBJECT_CLASS( vips_foreign_load_tiff_parent_class )->
95 		dispose( gobject );
96 }
97 
98 static VipsForeignFlags
vips_foreign_load_tiff_get_flags_source(VipsSource * source)99 vips_foreign_load_tiff_get_flags_source( VipsSource *source )
100 {
101 	VipsForeignFlags flags;
102 
103 	flags = 0;
104 	if( vips__istifftiled_source( source ) )
105 		flags |= VIPS_FOREIGN_PARTIAL;
106 	else
107 		flags |= VIPS_FOREIGN_SEQUENTIAL;
108 
109 	return( flags );
110 }
111 
112 static VipsForeignFlags
vips_foreign_load_tiff_get_flags_filename(const char * filename)113 vips_foreign_load_tiff_get_flags_filename( const char *filename )
114 {
115 	VipsSource *source;
116 	VipsForeignFlags flags;
117 
118 	if( !(source = vips_source_new_from_file( filename )) )
119 		return( 0 );
120 	flags = vips_foreign_load_tiff_get_flags_source( source );
121 	VIPS_UNREF( source );
122 
123 	return( flags );
124 }
125 
126 static VipsForeignFlags
vips_foreign_load_tiff_get_flags(VipsForeignLoad * load)127 vips_foreign_load_tiff_get_flags( VipsForeignLoad *load )
128 {
129 	VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
130 
131 	return( vips_foreign_load_tiff_get_flags_source( tiff->source ) );
132 }
133 
134 static int
vips_foreign_load_tiff_header(VipsForeignLoad * load)135 vips_foreign_load_tiff_header( VipsForeignLoad *load )
136 {
137 	VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
138 
139 	if( vips__tiff_read_header_source( tiff->source, load->out,
140 		tiff->page, tiff->n, tiff->autorotate, tiff->subifd,
141 		load->fail_on ) )
142 		return( -1 );
143 
144 	return( 0 );
145 }
146 
147 static int
vips_foreign_load_tiff_load(VipsForeignLoad * load)148 vips_foreign_load_tiff_load( VipsForeignLoad *load )
149 {
150 	VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
151 
152 	if( vips__tiff_read_source( tiff->source, load->real,
153 		tiff->page, tiff->n,  tiff->autorotate, tiff->subifd,
154 		load->fail_on ) )
155 		return( -1 );
156 
157 	return( 0 );
158 }
159 
160 static void
vips_foreign_load_tiff_class_init(VipsForeignLoadTiffClass * class)161 vips_foreign_load_tiff_class_init( VipsForeignLoadTiffClass *class )
162 {
163 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
164 	VipsObjectClass *object_class = (VipsObjectClass *) class;
165 	VipsForeignClass *foreign_class = (VipsForeignClass *) class;
166 	VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
167 
168 	/* Other libraries may be using libtiff, we want to capture tiff
169 	 * warning and error as soon as we can.
170 	 *
171 	 * This class init will be triggered during startup.
172 	 */
173 	vips__tiff_init();
174 
175 	gobject_class->dispose = vips_foreign_load_tiff_dispose;
176 	gobject_class->set_property = vips_object_set_property;
177 	gobject_class->get_property = vips_object_get_property;
178 
179 	object_class->nickname = "tiffload_base";
180 	object_class->description = _( "load tiff" );
181 
182 	/* We are fast, but must test after openslideload.
183 	 */
184 	foreign_class->priority = 50;
185 
186 	load_class->get_flags_filename =
187 		vips_foreign_load_tiff_get_flags_filename;
188 	load_class->get_flags = vips_foreign_load_tiff_get_flags;
189 	load_class->header = vips_foreign_load_tiff_header;
190 	load_class->load = vips_foreign_load_tiff_load;
191 
192 	VIPS_ARG_INT( class, "page", 20,
193 		_( "Page" ),
194 		_( "Load this page from the image" ),
195 		VIPS_ARGUMENT_OPTIONAL_INPUT,
196 		G_STRUCT_OFFSET( VipsForeignLoadTiff, page ),
197 		0, 100000, 0 );
198 
199 	VIPS_ARG_INT( class, "n", 21,
200 		_( "n" ),
201 		_( "Load this many pages" ),
202 		VIPS_ARGUMENT_OPTIONAL_INPUT,
203 		G_STRUCT_OFFSET( VipsForeignLoadTiff, n ),
204 		-1, 100000, 1 );
205 
206 	VIPS_ARG_BOOL( class, "autorotate", 22,
207 		_( "Autorotate" ),
208 		_( "Rotate image using orientation tag" ),
209 		VIPS_ARGUMENT_OPTIONAL_INPUT,
210 		G_STRUCT_OFFSET( VipsForeignLoadTiff, autorotate ),
211 		FALSE );
212 
213 	VIPS_ARG_INT( class, "subifd", 21,
214 		_( "subifd" ),
215 		_( "Select subifd index" ),
216 		VIPS_ARGUMENT_OPTIONAL_INPUT,
217 		G_STRUCT_OFFSET( VipsForeignLoadTiff, subifd ),
218 		-1, 100000, -1 );
219 
220 }
221 
222 static void
vips_foreign_load_tiff_init(VipsForeignLoadTiff * tiff)223 vips_foreign_load_tiff_init( VipsForeignLoadTiff *tiff )
224 {
225 	tiff->page = 0;
226 	tiff->n = 1;
227 	tiff->subifd = -1;
228 }
229 
230 typedef struct _VipsForeignLoadTiffSource {
231 	VipsForeignLoadTiff parent_object;
232 
233 	/* Load from a source.
234 	 */
235 	VipsSource *source;
236 
237 } VipsForeignLoadTiffSource;
238 
239 typedef VipsForeignLoadTiffClass VipsForeignLoadTiffSourceClass;
240 
241 G_DEFINE_TYPE( VipsForeignLoadTiffSource, vips_foreign_load_tiff_source,
242 	vips_foreign_load_tiff_get_type() );
243 
244 static int
vips_foreign_load_tiff_source_build(VipsObject * object)245 vips_foreign_load_tiff_source_build( VipsObject *object )
246 {
247 	VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) object;
248 	VipsForeignLoadTiffSource *source =
249 		(VipsForeignLoadTiffSource *) object;
250 
251 	if( source->source ) {
252 		tiff->source = source->source;
253 		g_object_ref( tiff->source );
254 	}
255 
256 	if( VIPS_OBJECT_CLASS( vips_foreign_load_tiff_source_parent_class )->
257 		build( object ) )
258 		return( -1 );
259 
260 	return( 0 );
261 }
262 
263 static gboolean
vips_foreign_load_tiff_source_is_a_source(VipsSource * source)264 vips_foreign_load_tiff_source_is_a_source( VipsSource *source )
265 {
266 	return( vips__istiff_source( source ) );
267 }
268 
269 static void
vips_foreign_load_tiff_source_class_init(VipsForeignLoadTiffSourceClass * class)270 vips_foreign_load_tiff_source_class_init(
271 	VipsForeignLoadTiffSourceClass *class )
272 {
273 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
274 	VipsObjectClass *object_class = (VipsObjectClass *) class;
275 	VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
276 	VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
277 
278 	gobject_class->set_property = vips_object_set_property;
279 	gobject_class->get_property = vips_object_get_property;
280 
281 	object_class->nickname = "tiffload_source";
282 	object_class->description = _( "load tiff from source" );
283 	object_class->build = vips_foreign_load_tiff_source_build;
284 
285 	operation_class->flags = VIPS_OPERATION_NOCACHE;
286 
287 	load_class->is_a_source = vips_foreign_load_tiff_source_is_a_source;
288 
289 	VIPS_ARG_OBJECT( class, "source", 1,
290 		_( "Source" ),
291 		_( "Source to load from" ),
292 		VIPS_ARGUMENT_REQUIRED_INPUT,
293 		G_STRUCT_OFFSET( VipsForeignLoadTiffSource, source ),
294 		VIPS_TYPE_SOURCE );
295 
296 }
297 
298 static void
vips_foreign_load_tiff_source_init(VipsForeignLoadTiffSource * source)299 vips_foreign_load_tiff_source_init( VipsForeignLoadTiffSource *source )
300 {
301 }
302 
303 typedef struct _VipsForeignLoadTiffFile {
304 	VipsForeignLoadTiff parent_object;
305 
306 	/* Filename for load.
307 	 */
308 	char *filename;
309 
310 } VipsForeignLoadTiffFile;
311 
312 typedef VipsForeignLoadTiffClass VipsForeignLoadTiffFileClass;
313 
314 G_DEFINE_TYPE( VipsForeignLoadTiffFile, vips_foreign_load_tiff_file,
315 	vips_foreign_load_tiff_get_type() );
316 
317 static int
vips_foreign_load_tiff_file_build(VipsObject * object)318 vips_foreign_load_tiff_file_build( VipsObject *object )
319 {
320 	VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) object;
321 	VipsForeignLoadTiffFile *file = (VipsForeignLoadTiffFile *) object;
322 
323 	if( file->filename &&
324 		!(tiff->source =
325 			vips_source_new_from_file( file->filename )) )
326 		return( -1 );
327 
328 	if( VIPS_OBJECT_CLASS( vips_foreign_load_tiff_file_parent_class )->
329 		build( object ) )
330 		return( -1 );
331 
332 	return( 0 );
333 }
334 
335 static gboolean
vips_foreign_load_tiff_file_is_a(const char * filename)336 vips_foreign_load_tiff_file_is_a( const char *filename )
337 {
338 	VipsSource *source;
339 	gboolean result;
340 
341 	if( !(source = vips_source_new_from_file( filename )) )
342 		return( FALSE );
343 	result = vips_foreign_load_tiff_source_is_a_source( source );
344 	VIPS_UNREF( source );
345 
346 	return( result );
347 }
348 
349 const char *vips__foreign_tiff_suffs[] = { ".tif", ".tiff", NULL };
350 
351 static void
vips_foreign_load_tiff_file_class_init(VipsForeignLoadTiffFileClass * class)352 vips_foreign_load_tiff_file_class_init( VipsForeignLoadTiffFileClass *class )
353 {
354 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
355 	VipsObjectClass *object_class = (VipsObjectClass *) class;
356 	VipsForeignClass *foreign_class = (VipsForeignClass *) class;
357 	VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
358 
359 	gobject_class->set_property = vips_object_set_property;
360 	gobject_class->get_property = vips_object_get_property;
361 
362 	object_class->nickname = "tiffload";
363 	object_class->description = _( "load tiff from file" );
364 	object_class->build = vips_foreign_load_tiff_file_build;
365 
366 	foreign_class->suffs = vips__foreign_tiff_suffs;
367 
368 	load_class->is_a = vips_foreign_load_tiff_file_is_a;
369 
370 	VIPS_ARG_STRING( class, "filename", 1,
371 		_( "Filename" ),
372 		_( "Filename to load from" ),
373 		VIPS_ARGUMENT_REQUIRED_INPUT,
374 		G_STRUCT_OFFSET( VipsForeignLoadTiffFile, filename ),
375 		NULL );
376 }
377 
378 static void
vips_foreign_load_tiff_file_init(VipsForeignLoadTiffFile * file)379 vips_foreign_load_tiff_file_init( VipsForeignLoadTiffFile *file )
380 {
381 }
382 
383 typedef struct _VipsForeignLoadTiffBuffer {
384 	VipsForeignLoadTiff parent_object;
385 
386 	/* Load from a buffer.
387 	 */
388 	VipsBlob *blob;
389 
390 } VipsForeignLoadTiffBuffer;
391 
392 typedef VipsForeignLoadTiffClass VipsForeignLoadTiffBufferClass;
393 
394 G_DEFINE_TYPE( VipsForeignLoadTiffBuffer, vips_foreign_load_tiff_buffer,
395 	vips_foreign_load_tiff_get_type() );
396 
397 static int
vips_foreign_load_tiff_buffer_build(VipsObject * object)398 vips_foreign_load_tiff_buffer_build( VipsObject *object )
399 {
400 	VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) object;
401 	VipsForeignLoadTiffBuffer *buffer =
402 		(VipsForeignLoadTiffBuffer *) object;
403 
404 	if( buffer->blob &&
405 		!(tiff->source = vips_source_new_from_memory(
406 			VIPS_AREA( buffer->blob )->data,
407 			VIPS_AREA( buffer->blob )->length )) )
408 		return( -1 );
409 
410 	if( VIPS_OBJECT_CLASS( vips_foreign_load_tiff_buffer_parent_class )->
411 		build( object ) )
412 		return( -1 );
413 
414 	return( 0 );
415 }
416 
417 static gboolean
vips_foreign_load_tiff_buffer_is_a_buffer(const void * buf,size_t len)418 vips_foreign_load_tiff_buffer_is_a_buffer( const void *buf, size_t len )
419 {
420 	VipsSource *source;
421 	gboolean result;
422 
423 	if( !(source = vips_source_new_from_memory( buf, len )) )
424 		return( FALSE );
425 	result = vips_foreign_load_tiff_source_is_a_source( source );
426 	VIPS_UNREF( source );
427 
428 	return( result );
429 }
430 
431 static void
vips_foreign_load_tiff_buffer_class_init(VipsForeignLoadTiffBufferClass * class)432 vips_foreign_load_tiff_buffer_class_init(
433 	VipsForeignLoadTiffBufferClass *class )
434 {
435 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
436 	VipsObjectClass *object_class = (VipsObjectClass *) class;
437 	VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
438 
439 	gobject_class->set_property = vips_object_set_property;
440 	gobject_class->get_property = vips_object_get_property;
441 
442 	object_class->nickname = "tiffload_buffer";
443 	object_class->description = _( "load tiff from buffer" );
444 	object_class->build = vips_foreign_load_tiff_buffer_build;
445 
446 	load_class->is_a_buffer = vips_foreign_load_tiff_buffer_is_a_buffer;
447 
448 	VIPS_ARG_BOXED( class, "buffer", 1,
449 		_( "Buffer" ),
450 		_( "Buffer to load from" ),
451 		VIPS_ARGUMENT_REQUIRED_INPUT,
452 		G_STRUCT_OFFSET( VipsForeignLoadTiffBuffer, blob ),
453 		VIPS_TYPE_BLOB );
454 }
455 
456 static void
vips_foreign_load_tiff_buffer_init(VipsForeignLoadTiffBuffer * buffer)457 vips_foreign_load_tiff_buffer_init( VipsForeignLoadTiffBuffer *buffer )
458 {
459 }
460 
461 #endif /*HAVE_TIFF*/
462 
463 /**
464  * vips_tiffload:
465  * @filename: file to load
466  * @out: (out): decompressed image
467  * @...: %NULL-terminated list of optional named arguments
468  *
469  * Optional arguments:
470  *
471  * * @page: %gint, load this page
472  * * @n: %gint, load this many pages
473  * * @autorotate: %gboolean, use orientation tag to rotate the image
474  *   during load
475  * * @subifd: %gint, select this subifd index
476  *
477  * Read a TIFF file into a VIPS image. It is a full baseline TIFF 6 reader,
478  * with extensions for tiled images, multipage images, XYZ and LAB colour
479  * space, pyramidal images and JPEG compression, including CMYK and YCbCr.
480  *
481  * @page means load this page from the file. By default the first page (page
482  * 0) is read.
483  *
484  * @n means load this many pages. By default a single page is read. All the
485  * pages must have the same dimensions, and they are loaded as a tall, thin
486  * "toilet roll" image. The #VIPS_META_PAGE_HEIGHT metadata
487  * tag gives the height in pixels of each page. Use -1 to load all pages.
488  *
489  * Setting @autorotate to %TRUE will make the loader interpret the
490  * orientation tag and automatically rotate the image appropriately during
491  * load.
492  *
493  * If @autorotate is %FALSE, the metadata field #VIPS_META_ORIENTATION is set
494  * to the value of the orientation tag. Applications may read and interpret
495  * this field
496  * as they wish later in processing. See vips_autorot(). Save
497  * operations will use #VIPS_META_ORIENTATION, if present, to set the
498  * orientation of output images.
499  *
500  * If @autorotate is TRUE, the image will be rotated upright during load and
501  * no metadata attached. This can be very slow.
502  *
503  * If @subifd is -1 (the default), the main image is selected for each page.
504  * If it is 0 or greater and there is a SUBIFD tag, the indexed SUBIFD is
505  * selected. This can be used to read lower resolution layers from
506  * bioformats-style image pyramids.
507  *
508  * Any ICC profile is read and attached to the VIPS image as
509  * #VIPS_META_ICC_NAME. Any XMP metadata is read and attached to the image
510  * as #VIPS_META_XMP_NAME. Any IPTC is attached as #VIPS_META_IPTC_NAME. The
511  * image description is
512  * attached as #VIPS_META_IMAGEDESCRIPTION. Data in the photoshop tag is
513  * attached as #VIPS_META_PHOTOSHOP_NAME.
514  *
515  * See also: vips_image_new_from_file(), vips_autorot().
516  *
517  * Returns: 0 on success, -1 on error.
518  */
519 int
vips_tiffload(const char * filename,VipsImage ** out,...)520 vips_tiffload( const char *filename, VipsImage **out, ... )
521 {
522 	va_list ap;
523 	int result;
524 
525 	va_start( ap, out );
526 	result = vips_call_split( "tiffload", ap, filename, out );
527 	va_end( ap );
528 
529 	return( result );
530 }
531 
532 /**
533  * vips_tiffload_buffer:
534  * @buf: (array length=len) (element-type guint8): memory area to load
535  * @len: (type gsize): size of memory area
536  * @out: (out): image to write
537  * @...: %NULL-terminated list of optional named arguments
538  *
539  * Optional arguments:
540  *
541  * * @page: %gint, load this page
542  * * @n: %gint, load this many pages
543  * * @autorotate: %gboolean, use orientation tag to rotate the image
544  *   during load
545  * * @subifd: %gint, select this subifd index
546  *
547  * Read a TIFF-formatted memory block into a VIPS image. Exactly as
548  * vips_tiffload(), but read from a memory source.
549  *
550  * You must not free the buffer while @out is active. The
551  * #VipsObject::postclose signal on @out is a good place to free.
552  *
553  * See also: vips_tiffload().
554  *
555  * Returns: 0 on success, -1 on error.
556  */
557 int
vips_tiffload_buffer(void * buf,size_t len,VipsImage ** out,...)558 vips_tiffload_buffer( void *buf, size_t len, VipsImage **out, ... )
559 {
560 	va_list ap;
561 	VipsBlob *blob;
562 	int result;
563 
564 	/* We don't take a copy of the data or free it.
565 	 */
566 	blob = vips_blob_new( NULL, buf, len );
567 
568 	va_start( ap, out );
569 	result = vips_call_split( "tiffload_buffer", ap, blob, out );
570 	va_end( ap );
571 
572 	vips_area_unref( VIPS_AREA( blob ) );
573 
574 	return( result );
575 }
576 
577 /**
578  * vips_tiffload_source:
579  * @source: source to load
580  * @out: (out): image to write
581  * @...: %NULL-terminated list of optional named arguments
582  *
583  * Optional arguments:
584  *
585  * * @page: %gint, load this page
586  * * @n: %gint, load this many pages
587  * * @autorotate: %gboolean, use orientation tag to rotate the image
588  *   during load
589  * * @subifd: %gint, select this subifd index
590  *
591  * Exactly as vips_tiffload(), but read from a source.
592  *
593  * See also: vips_tiffload().
594  *
595  * Returns: 0 on success, -1 on error.
596  */
597 int
vips_tiffload_source(VipsSource * source,VipsImage ** out,...)598 vips_tiffload_source( VipsSource *source, VipsImage **out, ... )
599 {
600 	va_list ap;
601 	int result;
602 
603 	va_start( ap, out );
604 	result = vips_call_split( "tiffload_source", ap, source, out );
605 	va_end( ap );
606 
607 	return( result );
608 }
609