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