1 /* Some shared TIFF utilities.
2  *
3  * 14/10/16
4  * 	- from vips2tiff.c
5  *
6  * 26/8/17
7  * 	- add openout_read, to help tiffsave_buffer for pyramids
8  */
9 
10 /*
11 
12     This file is part of VIPS.
13 
14     VIPS is free software; you can redistribute it and/or modify
15     it under the terms of the GNU Lesser General Public License as published by
16     the Free Software Foundation; either version 2 of the License, or
17     (at your option) any later version.
18 
19     This program is distributed in the hope that it will be useful,
20     but WITHOUT ANY WARRANTY; without even the implied warranty of
21     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22     GNU Lesser General Public License for more details.
23 
24     You should have received a copy of the GNU Lesser General Public License
25     along with this program; if not, write to the Free Software
26     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27     02110-1301  USA
28 
29  */
30 
31 /*
32 
33     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
34 
35  */
36 
37 /*
38 #define DEBUG
39  */
40 
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif /*HAVE_CONFIG_H*/
44 #include <vips/intl.h>
45 
46 #ifdef HAVE_TIFF
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif /*HAVE_UNISTD_H*/
53 #include <string.h>
54 
55 #include <vips/vips.h>
56 #include <vips/internal.h>
57 
58 #include <tiffio.h>
59 
60 #include "tiff.h"
61 
62 /* Handle TIFF errors here. Shared with vips2tiff.c. These can be called from
63  * more than one thread.
64  */
65 static void
vips__thandler_error(const char * module,const char * fmt,va_list ap)66 vips__thandler_error( const char *module, const char *fmt, va_list ap )
67 {
68 	vips_verror( module, fmt, ap );
69 }
70 
71 /* It'd be nice to be able to support the @fail option for the tiff loader, but
72  * there's no easy way to do this, since libtiff has a global warning handler.
73  */
74 static void
vips__thandler_warning(const char * module,const char * fmt,va_list ap)75 vips__thandler_warning( const char *module, const char *fmt, va_list ap )
76 {
77 	g_logv( G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, ap );
78 }
79 
80 /* Called during library init.
81  *
82  * libtiff error and warning handlers may be called from other threads
83  * running in other libs. Other libs may install error handlers and capture
84  * messages caused by us.
85  */
86 void
vips__tiff_init(void)87 vips__tiff_init( void )
88 {
89 	TIFFSetErrorHandler( vips__thandler_error );
90 	TIFFSetWarningHandler( vips__thandler_warning );
91 }
92 
93 /* Open TIFF for output.
94  */
95 TIFF *
vips__tiff_openout(const char * path,gboolean bigtiff)96 vips__tiff_openout( const char *path, gboolean bigtiff )
97 {
98 	TIFF *tif;
99 	const char *mode = bigtiff ? "w8" : "w";
100 
101 #ifdef DEBUG
102 	printf( "vips__tiff_openout( \"%s\", \"%s\" )\n", path, mode );
103 #endif /*DEBUG*/
104 
105 	/* Need the utf-16 version on Windows.
106 	 */
107 #ifdef G_OS_WIN32
108 {
109 	GError *error = NULL;
110 	wchar_t *path16;
111 
112 	if( !(path16 = (wchar_t *)
113 		g_utf8_to_utf16( path, -1, NULL, NULL, &error )) ) {
114 		vips_g_error( &error );
115 		return( NULL );
116 	}
117 
118 	tif = TIFFOpenW( path16, mode );
119 
120 	g_free( path16 );
121 }
122 #else /*!G_OS_WIN32*/
123 	tif = TIFFOpen( path, mode );
124 #endif /*G_OS_WIN32*/
125 
126 	if( !tif ) {
127 		vips_error( "tiff",
128 			_( "unable to open \"%s\" for output" ), path );
129 		return( NULL );
130 	}
131 
132 	return( tif );
133 }
134 
135 /* TIFF input from a vips source.
136  */
137 
138 static tsize_t
openin_source_read(thandle_t st,tdata_t data,tsize_t size)139 openin_source_read( thandle_t st, tdata_t data, tsize_t size )
140 {
141 	VipsSource *source = VIPS_SOURCE( st );
142 
143 	return( vips_source_read( source, data, size ) );
144 }
145 
146 static tsize_t
openin_source_write(thandle_t st,tdata_t buffer,tsize_t size)147 openin_source_write( thandle_t st, tdata_t buffer, tsize_t size )
148 {
149 	g_assert_not_reached();
150 
151 	return( 0 );
152 }
153 
154 static toff_t
openin_source_seek(thandle_t st,toff_t position,int whence)155 openin_source_seek( thandle_t st, toff_t position, int whence )
156 {
157 	VipsSource *source = VIPS_SOURCE( st );
158 
159 	/* toff_t is usually uint64, with -1 cast to uint64 to indicate error.
160 	 */
161 	return( (toff_t) vips_source_seek( source, position, whence ) );
162 }
163 
164 static int
openin_source_close(thandle_t st)165 openin_source_close( thandle_t st )
166 {
167 	VipsSource *source = VIPS_SOURCE( st );
168 
169 	VIPS_UNREF( source );
170 
171 	return( 0 );
172 }
173 
174 static toff_t
openin_source_length(thandle_t st)175 openin_source_length( thandle_t st )
176 {
177 	VipsSource *source = VIPS_SOURCE( st );
178 
179 	/* libtiff will use this to get file size if tags like StripByteCounts
180 	 * are missing.
181 	 *
182 	 * toff_t is usually uint64, with -1 cast to uint64 to indicate error.
183 	 */
184 	return( (toff_t) vips_source_length( source ) );
185 }
186 
187 static int
openin_source_map(thandle_t st,tdata_t * start,toff_t * len)188 openin_source_map( thandle_t st, tdata_t *start, toff_t *len )
189 {
190 	g_assert_not_reached();
191 
192 	return( 0 );
193 }
194 
195 static void
openin_source_unmap(thandle_t st,tdata_t start,toff_t len)196 openin_source_unmap( thandle_t st, tdata_t start, toff_t len )
197 {
198 	g_assert_not_reached();
199 
200 	return;
201 }
202 
203 TIFF *
vips__tiff_openin_source(VipsSource * source)204 vips__tiff_openin_source( VipsSource *source )
205 {
206 	TIFF *tiff;
207 
208 #ifdef DEBUG
209 	printf( "vips__tiff_openin_source:\n" );
210 #endif /*DEBUG*/
211 
212 	if( vips_source_rewind( source ) )
213 		return( NULL );
214 
215 	/* Disable memory mapped input -- it chews up VM and the performance
216 	 * gain is very small.
217 	 *
218 	 * C enables strip chopping: very large uncompressed strips are
219 	 * chopped into c. 8kb chunks. This can reduce peak memory use for
220 	 * this type of file.
221 	 */
222 	if( !(tiff = TIFFClientOpen( "source input", "rmC",
223 		(thandle_t) source,
224 		openin_source_read,
225 		openin_source_write,
226 		openin_source_seek,
227 		openin_source_close,
228 		openin_source_length,
229 		openin_source_map,
230 		openin_source_unmap )) ) {
231 		vips_error( "vips__tiff_openin_source", "%s",
232 			_( "unable to open source for input" ) );
233 		return( NULL );
234 	}
235 
236 	/* Unreffed on close(), see above.
237 	 */
238 	g_object_ref( source );
239 
240 	return( tiff );
241 }
242 
243 /* TIFF output to a memory buffer.
244  */
245 
246 typedef struct _VipsTiffOpenoutBuffer {
247 	VipsDbuf dbuf;
248 
249 	/* On close, consolidate and write the output here.
250 	 */
251 	void **out_data;
252 	size_t *out_length;
253 } VipsTiffOpenoutBuffer;
254 
255 static tsize_t
openout_buffer_read(thandle_t st,tdata_t data,tsize_t size)256 openout_buffer_read( thandle_t st, tdata_t data, tsize_t size )
257 {
258 	VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st;
259 
260 #ifdef DEBUG
261 	printf( "openout_buffer_read: %zd bytes\n", size );
262 #endif /*DEBUG*/
263 
264 	return( vips_dbuf_read( &buffer->dbuf, data, size ) );
265 }
266 
267 static tsize_t
openout_buffer_write(thandle_t st,tdata_t data,tsize_t size)268 openout_buffer_write( thandle_t st, tdata_t data, tsize_t size )
269 {
270 	VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st;
271 
272 #ifdef DEBUG
273 	printf( "openout_buffer_write: %zd bytes\n", size );
274 #endif /*DEBUG*/
275 
276 	vips_dbuf_write( &buffer->dbuf, data, size );
277 
278 	return( size );
279 }
280 
281 static int
openout_buffer_close(thandle_t st)282 openout_buffer_close( thandle_t st )
283 {
284 	VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st;
285 
286 	*(buffer->out_data) = vips_dbuf_steal( &buffer->dbuf,
287 		buffer->out_length);
288 
289 	return( 0 );
290 }
291 
292 static toff_t
openout_buffer_seek(thandle_t st,toff_t position,int whence)293 openout_buffer_seek( thandle_t st, toff_t position, int whence )
294 {
295 	VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st;
296 
297 #ifdef DEBUG
298 	printf( "openout_buffer_seek: position %zd, whence %d ",
299 		position, whence );
300 	switch( whence ) {
301 	case SEEK_SET:
302 		printf( "set" );
303 		break;
304 
305 	case SEEK_END:
306 		printf( "end" );
307 		break;
308 
309 	case SEEK_CUR:
310 		printf( "cur" );
311 		break;
312 
313 	default:
314 		printf( "unknown" );
315 		break;
316 	}
317 	printf( "\n" );
318 #endif /*DEBUG*/
319 
320 	vips_dbuf_seek( &buffer->dbuf, position, whence );
321 
322 	return( vips_dbuf_tell( &buffer->dbuf ) );
323 }
324 
325 static toff_t
openout_buffer_length(thandle_t st)326 openout_buffer_length( thandle_t st )
327 {
328 	g_assert_not_reached();
329 
330 	return( 0 );
331 }
332 
333 static int
openout_buffer_map(thandle_t st,tdata_t * start,toff_t * len)334 openout_buffer_map( thandle_t st, tdata_t *start, toff_t *len )
335 {
336 	g_assert_not_reached();
337 
338 	return( 0 );
339 }
340 
341 static void
openout_buffer_unmap(thandle_t st,tdata_t start,toff_t len)342 openout_buffer_unmap( thandle_t st, tdata_t start, toff_t len )
343 {
344 	g_assert_not_reached();
345 
346 	return;
347 }
348 
349 /* On TIFFClose(), @data and @length are set to point to the output buffer.
350  */
351 TIFF *
vips__tiff_openout_buffer(VipsImage * image,gboolean bigtiff,void ** out_data,size_t * out_length)352 vips__tiff_openout_buffer( VipsImage *image,
353 	gboolean bigtiff, void **out_data, size_t *out_length )
354 {
355 	const char *mode = bigtiff ? "w8" : "w";
356 
357 	VipsTiffOpenoutBuffer *buffer;
358 	TIFF *tiff;
359 
360 #ifdef DEBUG
361 	printf( "vips__tiff_openout_buffer:\n" );
362 #endif /*DEBUG*/
363 
364 	g_assert( out_data );
365 	g_assert( out_length );
366 
367 	buffer = VIPS_NEW( image, VipsTiffOpenoutBuffer );
368 	vips_dbuf_init( &buffer->dbuf );
369 	buffer->out_data = out_data;
370 	buffer->out_length = out_length;
371 
372 	if( !(tiff = TIFFClientOpen( "memory output", mode,
373 		(thandle_t) buffer,
374 		openout_buffer_read,
375 		openout_buffer_write,
376 		openout_buffer_seek,
377 		openout_buffer_close,
378 		openout_buffer_length,
379 		openout_buffer_map,
380 		openout_buffer_unmap )) ) {
381 		vips_error( "vips__tiff_openout_buffer", "%s",
382 			_( "unable to open memory buffer for output" ) );
383 		return( NULL );
384 	}
385 
386 	return( tiff );
387 }
388 
389 #endif /*HAVE_TIFF*/
390 
391