| /* TIFF PARTS: |
| * Copyright (c) 1988, 1990 by Sam Leffler. |
| * All rights reserved. |
| * |
| * This file is provided for unrestricted use provided that this |
| * legend is included on all tape media and as a part of the |
| * software program in whole or part. Users may copy, modify or |
| * distribute this file at will. |
| |
| MODIFICATION FOR VIPS Copyright 1991, K.Martinez |
| * software may be distributed FREE, with these copyright notices |
| * no responsibility/warantee is implied or given |
| * |
| * |
| * Modified and added im_LabQ2LabC() function. It can write IM_TYPE_LABQ image |
| * in vips format to LAB in tiff format. |
| * Copyright 1994 Ahmed Abbood. |
| * |
| * 19/9/95 JC |
| * - calls TIFFClose() more reliably |
| * - tidied up |
| * 12/4/97 JC |
| * - thrown away and rewritten for TIFF 6 lib |
| * 22/4/97 JC |
| * - writes a pyramid! |
| * - to separate TIFF files tho' |
| * 23/4/97 JC |
| * - does 2nd gather pass to put pyramid into a single TIFF file |
| * - ... and shrinks IM_CODING_LABQ too |
| * 26/10/98 JC |
| * - binary open for stupid systems |
| * 7/6/99 JC |
| * - 16bit TIFF write too |
| * 9/7/99 JC |
| * - ZIP tiff added |
| * 11/5/00 JC |
| * - removed TIFFmalloc/TIFFfree |
| * 5/8/00 JC |
| * - mode string now part of filename |
| * 23/4/01 JC |
| * - HAVE_TIFF turns on TIFFness |
| * 19/3/02 ruven |
| * - pyramid stops at tile size, not 64x64 |
| * 29/4/02 JC |
| * - write any number of bands (but still with photometric RGB, so not |
| * very useful) |
| * 10/9/02 JC |
| * - oops, handle TIFF errors better |
| * - now writes CMYK correctly |
| * 13/2/03 JC |
| * - tries not to write mad resolutions |
| * 7/5/03 JC |
| * - only write CMYK if Type == CMYK |
| * - writes EXTRASAMPLES ALPHA for bands == 2 or 4 (if we're writing RGB) |
| * 17/11/03 JC |
| * - write float too |
| * 28/11/03 JC |
| * - read via a "p" so we work from mmap window images |
| * - uses threadgroups for speedup |
| * 9/3/04 JC |
| * - 1 bit write mode added |
| * 5/4/04 |
| * - better handling of edge tiles (thanks Ruven) |
| * 18/5/04 Andrey Kiselev |
| * - added res_inch/res_cm option |
| * 20/5/04 JC |
| * - allow single res number too |
| * 19/7/04 |
| * - write several scanlines at once, good speed up for some cases |
| * 22/9/04 |
| * - got rid of wrapper image so nip gets progress feedback |
| * - fixed tiny read-beyond-buffer issue for edge tiles |
| * 7/10/04 |
| * - added ICC profile embedding |
| * 13/12/04 |
| * - can now pyramid any non-complex type (thanks Ruven) |
| * 27/1/05 |
| * - added ccittfax4 as a compression option |
| * 9/3/05 |
| * - set PHOTOMETRIC_CIELAB for vips TYPE_LAB images ... so we can write |
| * float LAB as well as float RGB |
| * - also LABS images |
| * 22/6/05 |
| * - 16 bit LAB write was broken |
| * 9/9/05 |
| * - write any icc profile from meta |
| * 3/3/06 |
| * - raise tile buffer limit (thanks Ruven) |
| * 11/11/06 |
| * - set ORIENTATION_TOPLEFT (thanks Josef) |
| * 18/7/07 Andrey Kiselev |
| * - remove "b" option on TIFFOpen() |
| * - support TIFFTAG_PREDICTOR types for lzw and deflate compression |
| * 3/11/07 |
| * - use im_wbuffer() for background writes |
| * 15/2/08 |
| * - set TIFFTAG_JPEGQUALITY explicitly when we copy TIFF files, since |
| * libtiff doesn't keep this in the header (thanks Joe) |
| * 20/2/08 |
| * - use tiff error handler from im_tiff2vips.c |
| * 27/2/08 |
| * - don't try to copy icc profiles when building pyramids (thanks Joe) |
| * 9/4/08 |
| * - use IM_META_RESOLUTION_UNIT to set default resunit |
| * 17/4/08 |
| * - allow CMYKA (thanks Doron) |
| * 5/9/08 |
| * - trigger eval callbacks during tile write |
| * 4/2/10 |
| * - gtkdoc |
| * 26/2/10 |
| * - option to turn on bigtiff output |
| * 16/4/10 |
| * - use vips_sink_*() instead of threadgroup and friends |
| * 22/6/10 |
| * - make no-owner regions for the tile cache, since we share these |
| * between threads |
| */ |
| |
| /* |
| |
| This file is part of VIPS. |
| |
| VIPS is free software; you can redistribute it and/or modify |
| it under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
| */ |
| |
| /* |
| |
| These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
| |
| */ |
| |
| /* Turn on IM_REGION_ADDR() range checks, don't delete intermediates. |
| #define DEBUG |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif /*HAVE_CONFIG_H*/ |
| #include <vips/intl.h> |
| |
| #ifndef HAVE_TIFF |
| |
| #include <vips/vips.h> |
| |
| int |
| im_vips2tiff( IMAGE *im, const char *filename ) |
| { |
| im_error( "im_vips2tiff", "%s", |
| _( "TIFF support disabled" ) ); |
| |
| return( -1 ); |
| } |
| |
| #else /*HAVE_TIFF*/ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif /*HAVE_UNISTD_H*/ |
| #include <string.h> |
| #include <assert.h> |
| |
| #include <vips/vips.h> |
| #include <vips/internal.h> |
| |
| #include <tiffio.h> |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #endif /*WITH_DMALLOC*/ |
| |
| /* Max no of tiles we buffer in a layer. Enough to buffer a line of 64x64 |
| * tiles on a 100k pixel across image. |
| */ |
| #define IM_MAX_LAYER_BUFFER (1000) |
| |
| /* Bits we OR together for quadrants in a tile. |
| */ |
| typedef enum pyramid_bits { |
| PYR_TL = 1, /* Top-left etc. */ |
| PYR_TR = 2, |
| PYR_BL = 4, |
| PYR_BR = 8, |
| PYR_ALL = 15, |
| PYR_NONE = 0 |
| } PyramidBits; |
| |
| /* A tile in our pyramid. |
| */ |
| typedef struct pyramid_tile { |
| REGION *tile; |
| PyramidBits bits; |
| } PyramidTile; |
| |
| /* A layer in the pyramid. |
| */ |
| typedef struct pyramid_layer { |
| /* Parameters. |
| */ |
| struct tiff_write *tw; /* Main TIFF write struct */ |
| int width, height; /* Layer size */ |
| int sub; /* Subsample factor for this layer */ |
| |
| char *lname; /* Name of this TIFF file */ |
| TIFF *tif; /* TIFF file we write this layer to */ |
| PEL *tbuf; /* TIFF output buffer */ |
| PyramidTile tiles[IM_MAX_LAYER_BUFFER]; |
| |
| struct pyramid_layer *below; /* Tiles go to here */ |
| struct pyramid_layer *above; /* Tiles come from here */ |
| } PyramidLayer; |
| |
| /* A TIFF image in the process of being written. |
| */ |
| typedef struct tiff_write { |
| IMAGE *im; /* Original input image */ |
| char *name; /* Final name we write to */ |
| char *mode; /* Mode string */ |
| |
| /* Read from im with these. |
| */ |
| REGION *reg; |
| |
| char *bname; /* Name for base layer */ |
| TIFF *tif; /* Image we write to */ |
| |
| PyramidLayer *layer; /* Top of pyramid, if in use */ |
| PEL *tbuf; /* TIFF output buffer */ |
| int tls; /* Tile line size */ |
| |
| int compression; /* Compression type */ |
| int jpqual; /* JPEG q-factor */ |
| int predictor; /* Predictor value */ |
| int tile; /* Tile or not */ |
| int tilew, tileh; /* Tile size */ |
| int pyramid; /* Write pyramid */ |
| int onebit; /* Write as 1-bit TIFF */ |
| int resunit; /* Resolution unit (inches or cm) */ |
| float xres; /* Resolution in X */ |
| float yres; /* Resolution in Y */ |
| int embed; /* Embed ICC profile */ |
| char *icc_profile; /* Profile to embed */ |
| int bigtiff; /* True for bigtiff write */ |
| |
| GMutex *write_lock; /* Lock TIFF*() calls with this */ |
| } TiffWrite; |
| |
| /* Use these from im_tiff2vips(). |
| */ |
| void im__thandler_error( char *module, char *fmt, va_list ap ); |
| void im__thandler_warning( char *module, char *fmt, va_list ap ); |
| |
| /* Open TIFF for output. |
| */ |
| static TIFF * |
| tiff_openout( TiffWrite *tw, const char *name ) |
| { |
| TIFF *tif; |
| const char *mode = tw->bigtiff ? "w8" : "w"; |
| |
| #ifdef DEBUG |
| printf( "TIFFOpen( \"%s\", \"%s\" )\n", name, mode ); |
| #endif /*DEBUG*/ |
| |
| if( !(tif = TIFFOpen( name, mode )) ) { |
| im_error( "im_vips2tiff", |
| _( "unable to open \"%s\" for output" ), name ); |
| return( NULL ); |
| } |
| |
| return( tif ); |
| } |
| |
| /* Open TIFF for input. |
| */ |
| static TIFF * |
| tiff_openin( const char *name ) |
| { |
| TIFF *tif; |
| |
| if( !(tif = TIFFOpen( name, "r" )) ) { |
| im_error( "im_vips2tiff", |
| _( "unable to open \"%s\" for input" ), name ); |
| return( NULL ); |
| } |
| |
| return( tif ); |
| } |
| |
| /* Convert VIPS LabQ to TIFF LAB. Just take the first three bands. |
| */ |
| static void |
| LabQ2LabC( PEL *q, PEL *p, int n ) |
| { |
| int x; |
| |
| for( x = 0; x < n; x++ ) { |
| /* Get most significant 8 bits of lab. |
| */ |
| q[0] = p[0]; |
| q[1] = p[1]; |
| q[2] = p[2]; |
| |
| p += 4; |
| q += 3; |
| } |
| } |
| |
| /* Pack 8 bit VIPS to 1 bit TIFF. |
| */ |
| static void |
| eightbit2onebit( PEL *q, PEL *p, int n ) |
| { |
| int x; |
| PEL bits; |
| |
| bits = 0; |
| for( x = 0; x < n; x++ ) { |
| bits <<= 1; |
| if( p[x] ) |
| bits |= 1; |
| |
| if( (x & 0x7) == 0x7 ) { |
| *q++ = bits; |
| bits = 0; |
| } |
| } |
| |
| /* Any left-over bits? Need to be left-aligned. |
| */ |
| if( (x & 0x7) != 0 ) |
| *q++ = bits << (8 - (x & 0x7)); |
| } |
| |
| /* Convert VIPS LABS to TIFF 16 bit LAB. |
| */ |
| static void |
| LabS2Lab16( PEL *q, PEL *p, int n ) |
| { |
| int x; |
| short *p1 = (short *) p; |
| unsigned short *q1 = (unsigned short *) q; |
| |
| for( x = 0; x < n; x++ ) { |
| /* TIFF uses unsigned 16 bit ... move zero, scale up L. |
| */ |
| q1[0] = (int) p1[0] << 1; |
| q1[1] = p1[1]; |
| q1[2] = p1[2]; |
| |
| p1 += 3; |
| q1 += 3; |
| } |
| } |
| |
| /* Pack a VIPS region into a TIFF tile buffer. |
| */ |
| static void |
| pack2tiff( TiffWrite *tw, REGION *in, PEL *q, Rect *area ) |
| { |
| int y; |
| |
| for( y = area->top; y < IM_RECT_BOTTOM( area ); y++ ) { |
| PEL *p = (PEL *) IM_REGION_ADDR( in, area->left, y ); |
| |
| if( in->im->Coding == IM_CODING_LABQ ) |
| LabQ2LabC( q, p, area->width ); |
| else if( tw->onebit ) |
| eightbit2onebit( q, p, area->width ); |
| else if( in->im->BandFmt == IM_BANDFMT_SHORT && |
| in->im->Type == IM_TYPE_LABS ) |
| LabS2Lab16( q, p, area->width ); |
| else |
| memcpy( q, p, |
| area->width * IM_IMAGE_SIZEOF_PEL( in->im ) ); |
| |
| q += tw->tls; |
| } |
| } |
| |
| /* Embed an ICC profile from a file. |
| */ |
| static int |
| embed_profile_file( TIFF *tif, const char *profile ) |
| { |
| char *buffer; |
| unsigned int length; |
| |
| if( !(buffer = im__file_read_name( profile, VIPS_ICC_DIR, &length )) ) |
| return( -1 ); |
| TIFFSetField( tif, TIFFTAG_ICCPROFILE, length, buffer ); |
| im_free( buffer ); |
| |
| #ifdef DEBUG |
| printf( "im_vips2tiff: attached profile \"%s\"\n", profile ); |
| #endif /*DEBUG*/ |
| |
| return( 0 ); |
| } |
| |
| /* Embed an ICC profile from IMAGE metadata. |
| */ |
| static int |
| embed_profile_meta( TIFF *tif, IMAGE *im ) |
| { |
| void *data; |
| size_t data_length; |
| |
| if( im_meta_get_blob( im, IM_META_ICC_NAME, &data, &data_length ) ) |
| return( -1 ); |
| TIFFSetField( tif, TIFFTAG_ICCPROFILE, data_length, data ); |
| |
| #ifdef DEBUG |
| printf( "im_vips2tiff: attached profile from meta\n" ); |
| #endif /*DEBUG*/ |
| |
| return( 0 ); |
| } |
| |
| static int |
| embed_profile( TiffWrite *tw, TIFF *tif ) |
| { |
| if( tw->embed && embed_profile_file( tif, tw->icc_profile ) ) |
| return( -1 ); |
| if( !tw->embed && im_header_get_typeof( tw->im, IM_META_ICC_NAME ) && |
| embed_profile_meta( tif, tw->im ) ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| /* Write a TIFF header. width and height are the size of the IMAGE we are |
| * writing (may have been shrunk!). |
| */ |
| static int |
| write_tiff_header( TiffWrite *tw, TIFF *tif, int width, int height ) |
| { |
| uint16 v[1]; |
| |
| /* Output base header fields. |
| */ |
| TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, width ); |
| TIFFSetField( tif, TIFFTAG_IMAGELENGTH, height ); |
| TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); |
| TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT ); |
| TIFFSetField( tif, TIFFTAG_COMPRESSION, tw->compression ); |
| |
| /* Don't write mad resolutions (eg. zero), it confuses some programs. |
| */ |
| TIFFSetField( tif, TIFFTAG_RESOLUTIONUNIT, tw->resunit ); |
| TIFFSetField( tif, TIFFTAG_XRESOLUTION, |
| IM_CLIP( 0.01, tw->xres, 10000 ) ); |
| TIFFSetField( tif, TIFFTAG_YRESOLUTION, |
| IM_CLIP( 0.01, tw->yres, 10000 ) ); |
| |
| if( tw->compression == COMPRESSION_JPEG ) |
| TIFFSetField( tif, TIFFTAG_JPEGQUALITY, tw->jpqual ); |
| |
| if( tw->predictor != -1 ) |
| TIFFSetField( tif, TIFFTAG_PREDICTOR, tw->predictor ); |
| |
| /* Attach ICC profile. |
| */ |
| if( embed_profile( tw, tif ) ) |
| return( -1 ); |
| |
| /* And colour fields. |
| */ |
| if( tw->im->Coding == IM_CODING_LABQ ) { |
| TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 3 ); |
| TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 8 ); |
| TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB ); |
| } |
| else if( tw->onebit ) { |
| TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 1 ); |
| TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 1 ); |
| TIFFSetField( tif, |
| TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK ); |
| } |
| else { |
| int photometric; |
| |
| TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, tw->im->Bands ); |
| TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, |
| im_bits_of_fmt( tw->im->BandFmt ) ); |
| |
| switch( tw->im->Bands ) { |
| case 1: |
| case 2: |
| photometric = PHOTOMETRIC_MINISBLACK; |
| if( tw->im->Bands == 2 ) { |
| v[0] = EXTRASAMPLE_ASSOCALPHA; |
| TIFFSetField( tif, TIFFTAG_EXTRASAMPLES, 1, v ); |
| } |
| break; |
| |
| case 3: |
| case 4: |
| if( tw->im->Type == IM_TYPE_LAB || |
| tw->im->Type == IM_TYPE_LABS ) |
| photometric = PHOTOMETRIC_CIELAB; |
| else if( tw->im->Type == IM_TYPE_CMYK ) { |
| photometric = PHOTOMETRIC_SEPARATED; |
| TIFFSetField( tif, |
| TIFFTAG_INKSET, INKSET_CMYK ); |
| } |
| else |
| photometric = PHOTOMETRIC_RGB; |
| |
| if( tw->im->Type != IM_TYPE_CMYK && |
| tw->im->Bands == 4 ) { |
| v[0] = EXTRASAMPLE_ASSOCALPHA; |
| TIFFSetField( tif, TIFFTAG_EXTRASAMPLES, 1, v ); |
| } |
| break; |
| |
| case 5: |
| if( tw->im->Type == IM_TYPE_CMYK ) { |
| photometric = PHOTOMETRIC_SEPARATED; |
| TIFFSetField( tif, |
| TIFFTAG_INKSET, INKSET_CMYK ); |
| } |
| break; |
| |
| default: |
| assert( 0 ); |
| } |
| |
| TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric ); |
| } |
| |
| /* Layout. |
| */ |
| if( tw->tile ) { |
| TIFFSetField( tif, TIFFTAG_TILEWIDTH, tw->tilew ); |
| TIFFSetField( tif, TIFFTAG_TILELENGTH, tw->tileh ); |
| } |
| else |
| TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, 16 ); |
| |
| /* Sample format ... for float, we write IEEE. |
| */ |
| if( tw->im->BandFmt == IM_BANDFMT_FLOAT ) |
| TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP ); |
| |
| return( 0 ); |
| } |
| |
| /* Free a pyramid layer. |
| */ |
| static void |
| free_layer( PyramidLayer *layer ) |
| { |
| int i; |
| |
| for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) |
| if( layer->tiles[i].tile ) { |
| im_region_free( layer->tiles[i].tile ); |
| layer->tiles[i].tile = NULL; |
| } |
| |
| /* And close the TIFF file we are writing to. |
| */ |
| IM_FREEF( im_free, layer->tbuf ); |
| IM_FREEF( TIFFClose, layer->tif ); |
| } |
| |
| /* Free an entire pyramid. |
| */ |
| static void |
| free_pyramid( PyramidLayer *layer ) |
| { |
| if( layer->below ) |
| free_pyramid( layer->below ); |
| |
| free_layer( layer ); |
| } |
| |
| /* Make a name for a new TIFF layer. Base it on sub factor. |
| */ |
| static char * |
| new_tiff_name( TiffWrite *tw, char *name, int sub ) |
| { |
| char buf[FILENAME_MAX]; |
| char buf2[FILENAME_MAX]; |
| |
| /* Remove existing .tif/.tiff suffix, if any. |
| */ |
| strcpy( buf, name ); |
| if( im_ispostfix( buf, ".tif" ) ) |
| buf[strlen( buf ) - 4] = '\0'; |
| if( im_ispostfix( buf, ".tiff" ) ) |
| buf[strlen( buf ) - 5] = '\0'; |
| |
| im_snprintf( buf2, FILENAME_MAX, "%s.%d.tif", buf, sub ); |
| |
| return( im_strdup( tw->im, buf2 ) ); |
| } |
| |
| /* Build a pyramid. w & h are size of layer above this layer. Write new layer |
| * struct into *zap, return 0/-1 for success/fail. |
| */ |
| static int |
| build_pyramid( TiffWrite *tw, PyramidLayer *above, |
| PyramidLayer **zap, int w, int h ) |
| { |
| PyramidLayer *layer = IM_NEW( tw->im, PyramidLayer ); |
| int i; |
| |
| if( !layer ) |
| return( -1 ); |
| layer->tw = tw; |
| layer->width = w / 2; |
| layer->height = h / 2; |
| |
| if( !above ) |
| /* Top of pyramid. |
| */ |
| layer->sub = 2; |
| else |
| layer->sub = above->sub * 2; |
| |
| layer->lname = NULL; |
| layer->tif = NULL; |
| layer->tbuf = NULL; |
| |
| for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) { |
| layer->tiles[i].tile = NULL; |
| layer->tiles[i].bits = PYR_NONE; |
| } |
| |
| layer->below = NULL; |
| layer->above = above; |
| |
| /* Save layer, to make sure it gets freed properly. |
| */ |
| *zap = layer; |
| |
| if( layer->width > tw->tilew || layer->height > tw->tileh ) |
| if( build_pyramid( tw, layer, |
| &layer->below, layer->width, layer->height ) ) |
| return( -1 ); |
| |
| if( !(layer->lname = new_tiff_name( tw, tw->name, layer->sub )) ) |
| return( -1 ); |
| |
| /* Make output image. |
| */ |
| if( !(layer->tif = tiff_openout( tw, layer->lname )) ) |
| return( -1 ); |
| |
| /* Write the TIFF header for this layer. |
| */ |
| if( write_tiff_header( tw, layer->tif, layer->width, layer->height ) ) |
| return( -1 ); |
| |
| if( !(layer->tbuf = im_malloc( NULL, TIFFTileSize( layer->tif ) )) ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| /* Pick a new tile to write to in this layer. Either reuse a tile we have |
| * previously filled, or make a new one. |
| */ |
| static int |
| find_new_tile( PyramidLayer *layer ) |
| { |
| int i; |
| |
| /* Exisiting buffer we have finished with? |
| */ |
| for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) |
| if( layer->tiles[i].bits == PYR_ALL ) |
| return( i ); |
| |
| /* Have to make a new one. |
| */ |
| for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) |
| if( !layer->tiles[i].tile ) { |
| if( !(layer->tiles[i].tile = |
| im_region_create( layer->tw->im )) ) |
| return( -1 ); |
| im__region_no_ownership( layer->tiles[i].tile ); |
| return( i ); |
| } |
| |
| /* Out of space! |
| */ |
| im_error( "im_vips2tiff", "%s", _( "layer buffer exhausted -- " |
| "try making TIFF output tiles smaller" ) ); |
| |
| return( -1 ); |
| } |
| |
| /* Find a tile in the layer buffer - if it's not there, make a new one. |
| */ |
| static int |
| find_tile( PyramidLayer *layer, Rect *pos ) |
| { |
| int i; |
| Rect quad; |
| Rect image; |
| Rect inter; |
| |
| /* Do we have a REGION for this position? |
| */ |
| for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) { |
| REGION *reg = layer->tiles[i].tile; |
| |
| if( reg && reg->valid.left == pos->left && |
| reg->valid.top == pos->top ) |
| return( i ); |
| } |
| |
| /* Make a new one. |
| */ |
| if( (i = find_new_tile( layer )) < 0 ) |
| return( -1 ); |
| if( im_region_buffer( layer->tiles[i].tile, pos ) ) |
| return( -1 ); |
| layer->tiles[i].bits = PYR_NONE; |
| |
| /* Do any quadrants of this tile fall entirely outside the image? |
| * If they do, set their bits now. |
| */ |
| quad.width = layer->tw->tilew / 2; |
| quad.height = layer->tw->tileh / 2; |
| image.left = 0; |
| image.top = 0; |
| image.width = layer->width; |
| image.height = layer->height; |
| |
| quad.left = pos->left; |
| quad.top = pos->top; |
| im_rect_intersectrect( &quad, &image, &inter ); |
| if( im_rect_isempty( &inter ) ) |
| layer->tiles[i].bits |= PYR_TL; |
| |
| quad.left = pos->left + quad.width; |
| quad.top = pos->top; |
| im_rect_intersectrect( &quad, &image, &inter ); |
| if( im_rect_isempty( &inter ) ) |
| layer->tiles[i].bits |= PYR_TR; |
| |
| quad.left = pos->left; |
| quad.top = pos->top + quad.height; |
| im_rect_intersectrect( &quad, &image, &inter ); |
| if( im_rect_isempty( &inter ) ) |
| layer->tiles[i].bits |= PYR_BL; |
| |
| quad.left = pos->left + quad.width; |
| quad.top = pos->top + quad.height; |
| im_rect_intersectrect( &quad, &image, &inter ); |
| if( im_rect_isempty( &inter ) ) |
| layer->tiles[i].bits |= PYR_BR; |
| |
| return( i ); |
| } |
| |
| /* Shrink a region by a factor of two, writing the result to a specified |
| * offset in another region. IM_CODING_LABQ only. |
| */ |
| static void |
| shrink_region_labpack( REGION *from, Rect *area, |
| REGION *to, int xoff, int yoff ) |
| { |
| int ls = IM_REGION_LSKIP( from ); |
| Rect *t = &to->valid; |
| |
| int x, y; |
| Rect out; |
| |
| /* Calculate output size and position. |
| */ |
| out.left = t->left + xoff; |
| out.top = t->top + yoff; |
| out.width = area->width / 2; |
| out.height = area->height / 2; |
| |
| /* Shrink ... ignore the extension byte for speed. |
| */ |
| for( y = 0; y < out.height; y++ ) { |
| PEL *p = (PEL *) |
| IM_REGION_ADDR( from, area->left, area->top + y * 2 ); |
| PEL *q = (PEL *) |
| IM_REGION_ADDR( to, out.left, out.top + y ); |
| |
| for( x = 0; x < out.width; x++ ) { |
| signed char *sp = (signed char *) p; |
| unsigned char *up = (unsigned char *) p; |
| |
| int l = up[0] + up[4] + |
| up[ls] + up[ls + 4]; |
| int a = sp[1] + sp[5] + |
| sp[ls + 1] + sp[ls + 5]; |
| int b = sp[2] + sp[6] + |
| sp[ls + 2] + sp[ls + 6]; |
| |
| q[0] = l >> 2; |
| q[1] = a >> 2; |
| q[2] = b >> 2; |
| q[3] = 0; |
| |
| q += 4; |
| p += 8; |
| } |
| } |
| } |
| |
| #define SHRINK_TYPE_INT( TYPE ) \ |
| for( x = 0; x < out.width; x++ ) { \ |
| TYPE *tp = (TYPE *) p; \ |
| TYPE *tp1 = (TYPE *) (p + ls); \ |
| TYPE *tq = (TYPE *) q; \ |
| \ |
| for( z = 0; z < nb; z++ ) { \ |
| int tot = tp[z] + tp[z + nb] + \ |
| tp1[z] + tp1[z + nb]; \ |
| \ |
| tq[z] = tot >> 2; \ |
| } \ |
| \ |
| /* Move on two pels in input. \ |
| */ \ |
| p += ps << 1; \ |
| q += ps; \ |
| } |
| |
| #define SHRINK_TYPE_FLOAT( TYPE ) \ |
| for( x = 0; x < out.width; x++ ) { \ |
| TYPE *tp = (TYPE *) p; \ |
| TYPE *tp1 = (TYPE *) (p + ls); \ |
| TYPE *tq = (TYPE *) q; \ |
| \ |
| for( z = 0; z < nb; z++ ) { \ |
| double tot = (double) tp[z] + tp[z + nb] + \ |
| tp1[z] + tp1[z + nb]; \ |
| \ |
| tq[z] = tot / 4; \ |
| } \ |
| \ |
| /* Move on two pels in input. \ |
| */ \ |
| p += ps << 1; \ |
| q += ps; \ |
| } |
| |
| /* Shrink a region by a factor of two, writing the result to a specified |
| * offset in another region. n-band, non-complex. |
| */ |
| static void |
| shrink_region( REGION *from, Rect *area, |
| REGION *to, int xoff, int yoff ) |
| { |
| int ls = IM_REGION_LSKIP( from ); |
| int ps = IM_IMAGE_SIZEOF_PEL( from->im ); |
| int nb = from->im->Bands; |
| Rect *t = &to->valid; |
| |
| int x, y, z; |
| Rect out; |
| |
| /* Calculate output size and position. |
| */ |
| out.left = t->left + xoff; |
| out.top = t->top + yoff; |
| out.width = area->width / 2; |
| out.height = area->height / 2; |
| |
| for( y = 0; y < out.height; y++ ) { |
| PEL *p = (PEL *) |
| IM_REGION_ADDR( from, area->left, area->top + y * 2 ); |
| PEL *q = (PEL *) |
| IM_REGION_ADDR( to, out.left, out.top + y ); |
| |
| /* Process this line of pels. |
| */ |
| switch( from->im->BandFmt ) { |
| case IM_BANDFMT_UCHAR: |
| SHRINK_TYPE_INT( unsigned char ); break; |
| case IM_BANDFMT_CHAR: |
| SHRINK_TYPE_INT( signed char ); break; |
| case IM_BANDFMT_USHORT: |
| SHRINK_TYPE_INT( unsigned short ); break; |
| case IM_BANDFMT_SHORT: |
| SHRINK_TYPE_INT( signed short ); break; |
| case IM_BANDFMT_UINT: |
| SHRINK_TYPE_INT( unsigned int ); break; |
| case IM_BANDFMT_INT: |
| SHRINK_TYPE_INT( signed int ); break; |
| case IM_BANDFMT_FLOAT: |
| SHRINK_TYPE_FLOAT( float ); break; |
| case IM_BANDFMT_DOUBLE: |
| SHRINK_TYPE_FLOAT( double ); break; |
| |
| default: |
| assert( 0 ); |
| } |
| } |
| } |
| |
| /* Write a tile from a layer. |
| */ |
| static int |
| save_tile( TiffWrite *tw, TIFF *tif, PEL *tbuf, REGION *reg, Rect *area ) |
| { |
| /* Have to repack pixels. |
| */ |
| pack2tiff( tw, reg, tbuf, area ); |
| |
| #ifdef DEBUG |
| printf( "Writing %dx%d pixels at position %dx%d to image %s\n", |
| tw->tilew, tw->tileh, area->left, area->top, |
| TIFFFileName( tif ) ); |
| #endif /*DEBUG*/ |
| |
| /* Write to TIFF! easy. |
| */ |
| if( TIFFWriteTile( tif, tbuf, area->left, area->top, 0, 0 ) < 0 ) { |
| im_error( "im_vips2tiff", "%s", _( "TIFF write tile failed" ) ); |
| return( -1 ); |
| } |
| |
| return( 0 ); |
| } |
| |
| /* A new tile has arrived! Shrink into this layer, if we fill a region, write |
| * it and recurse. |
| */ |
| static int |
| new_tile( PyramidLayer *layer, REGION *tile, Rect *area ) |
| { |
| TiffWrite *tw = layer->tw; |
| int xoff, yoff; |
| |
| int t, ri, bo; |
| Rect out, new; |
| PyramidBits bit; |
| |
| /* Calculate pos and size of new pixels we make inside this layer. |
| */ |
| new.left = area->left / 2; |
| new.top = area->top / 2; |
| new.width = area->width / 2; |
| new.height = area->height / 2; |
| |
| /* Has size fallen to zero? Can happen if this is a one-pixel-wide |
| * strip. |
| */ |
| if( im_rect_isempty( &new ) ) |
| return( 0 ); |
| |
| /* Offset into this tile ... ie. which quadrant we are writing. |
| */ |
| xoff = new.left % layer->tw->tilew; |
| yoff = new.top % layer->tw->tileh; |
| |
| /* Calculate pos for tile we shrink into in this layer. |
| */ |
| out.left = new.left - xoff; |
| out.top = new.top - yoff; |
| |
| /* Clip against edge of image. |
| */ |
| ri = IM_MIN( layer->width, out.left + layer->tw->tilew ); |
| bo = IM_MIN( layer->height, out.top + layer->tw->tileh ); |
| out.width = ri - out.left; |
| out.height = bo - out.top; |
| |
| if( (t = find_tile( layer, &out )) < 0 ) |
| return( -1 ); |
| |
| /* Shrink into place. |
| */ |
| if( tw->im->Coding == IM_CODING_NONE ) |
| shrink_region( tile, area, |
| layer->tiles[t].tile, xoff, yoff ); |
| else |
| shrink_region_labpack( tile, area, |
| layer->tiles[t].tile, xoff, yoff ); |
| |
| /* Set that bit. |
| */ |
| if( xoff ) |
| if( yoff ) |
| bit = PYR_BR; |
| else |
| bit = PYR_TR; |
| else |
| if( yoff ) |
| bit = PYR_BL; |
| else |
| bit = PYR_TL; |
| if( layer->tiles[t].bits & bit ) { |
| im_error( "im_vips2tiff", |
| "%s", _( "internal error #9876345" ) ); |
| return( -1 ); |
| } |
| layer->tiles[t].bits |= bit; |
| |
| if( layer->tiles[t].bits == PYR_ALL ) { |
| /* Save this complete tile. |
| */ |
| if( save_tile( tw, layer->tif, layer->tbuf, |
| layer->tiles[t].tile, &layer->tiles[t].tile->valid ) ) |
| return( -1 ); |
| |
| /* And recurse down the pyramid! |
| */ |
| if( layer->below && |
| new_tile( layer->below, |
| layer->tiles[t].tile, |
| &layer->tiles[t].tile->valid ) ) |
| return( -1 ); |
| } |
| |
| return( 0 ); |
| } |
| |
| /* Write as tiles. This is called by vips_sink_tile() for every tile |
| * generated. |
| */ |
| static int |
| write_tif_tile( REGION *out, void *seq, void *a, void *b ) |
| { |
| TiffWrite *tw = (TiffWrite *) a; |
| |
| g_mutex_lock( tw->write_lock ); |
| |
| /* Write to TIFF. |
| */ |
| if( save_tile( tw, tw->tif, tw->tbuf, out, &out->valid ) ) { |
| g_mutex_unlock( tw->write_lock ); |
| return( -1 ); |
| } |
| |
| /* Is there a pyramid? Write to that too. |
| */ |
| if( tw->layer && |
| new_tile( tw->layer, out, &out->valid ) ) { |
| g_mutex_unlock( tw->write_lock ); |
| return( -1 ); |
| } |
| |
| g_mutex_unlock( tw->write_lock ); |
| |
| return( 0 ); |
| } |
| |
| /* Write as tiles. |
| */ |
| static int |
| write_tif_tilewise( TiffWrite *tw ) |
| { |
| IMAGE *im = tw->im; |
| |
| g_assert( !tw->tbuf ); |
| if( !(tw->tbuf = im_malloc( NULL, TIFFTileSize( tw->tif ) )) ) |
| return( -1 ); |
| |
| g_assert( !tw->write_lock ); |
| tw->write_lock = g_mutex_new(); |
| |
| /* Write pyramid too? Only bother if bigger than tile size. |
| */ |
| if( tw->pyramid && |
| (im->Xsize > tw->tilew || im->Ysize > tw->tileh) && |
| build_pyramid( tw, NULL, &tw->layer, im->Xsize, im->Ysize ) ) |
| return( -1 ); |
| |
| if( vips_sink_tile( im, tw->tilew, tw->tileh, |
| NULL, write_tif_tile, NULL, tw, NULL ) ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| static int |
| write_tif_block( REGION *region, Rect *area, void *a ) |
| { |
| TiffWrite *tw = (TiffWrite *) a; |
| IMAGE *im = tw->im; |
| |
| int y; |
| |
| for( y = 0; y < area->height; y++ ) { |
| PEL *p = (PEL *) IM_REGION_ADDR( region, 0, area->top + y ); |
| |
| /* Any repacking necessary. |
| */ |
| if( im->Coding == IM_CODING_LABQ ) { |
| LabQ2LabC( tw->tbuf, p, im->Xsize ); |
| p = tw->tbuf; |
| } |
| else if( im->BandFmt == IM_BANDFMT_SHORT && |
| im->Type == IM_TYPE_LABS ) { |
| LabS2Lab16( tw->tbuf, p, im->Xsize ); |
| p = tw->tbuf; |
| } |
| else if( tw->onebit ) { |
| eightbit2onebit( tw->tbuf, p, im->Xsize ); |
| p = tw->tbuf; |
| } |
| |
| if( TIFFWriteScanline( tw->tif, p, area->top + y, 0 ) < 0 ) |
| return( -1 ); |
| } |
| |
| return( 0 ); |
| } |
| |
| /* Write as scan-lines. |
| */ |
| static int |
| write_tif_stripwise( TiffWrite *tw ) |
| { |
| g_assert( !tw->tbuf ); |
| |
| if( !(tw->tbuf = im_malloc( NULL, TIFFScanlineSize( tw->tif ) )) ) |
| return( -1 ); |
| |
| if( vips_sink_disc( tw->im, write_tif_block, tw ) ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| /* Delete any temp files we wrote. |
| */ |
| static void |
| delete_files( TiffWrite *tw ) |
| { |
| PyramidLayer *layer = tw->layer; |
| |
| if( tw->bname ) { |
| unlink( tw->bname ); |
| tw->bname = NULL; |
| } |
| |
| for( layer = tw->layer; layer; layer = layer->below ) |
| if( layer->lname ) { |
| unlink( layer->lname ); |
| layer->lname = NULL; |
| } |
| } |
| |
| /* Free a TiffWrite. |
| */ |
| static void |
| free_tiff_write( TiffWrite *tw ) |
| { |
| #ifndef DEBUG |
| delete_files( tw ); |
| #endif /*DEBUG*/ |
| |
| IM_FREEF( TIFFClose, tw->tif ); |
| IM_FREEF( im_free, tw->tbuf ); |
| IM_FREEF( g_mutex_free, tw->write_lock ); |
| IM_FREEF( free_pyramid, tw->layer ); |
| IM_FREEF( im_free, tw->icc_profile ); |
| } |
| |
| /* Round N down to P boundary. |
| */ |
| #define ROUND_DOWN(N,P) ((N) - ((N) % P)) |
| |
| /* Round N up to P boundary. |
| */ |
| #define ROUND_UP(N,P) (ROUND_DOWN( (N) + (P) - 1, (P) )) |
| |
| /* Make and init a TiffWrite. |
| */ |
| static TiffWrite * |
| make_tiff_write( IMAGE *im, const char *filename ) |
| { |
| TiffWrite *tw; |
| char *p, *q, *r; |
| char name[FILENAME_MAX]; |
| char mode[FILENAME_MAX]; |
| char buf[FILENAME_MAX]; |
| |
| if( !(tw = IM_NEW( im, TiffWrite )) ) |
| return( NULL ); |
| tw->im = im; |
| im_filename_split( filename, name, mode ); |
| tw->name = im_strdup( im, name ); |
| tw->mode = im_strdup( im, mode ); |
| tw->bname = NULL; |
| tw->tif = NULL; |
| tw->layer = NULL; |
| tw->tbuf = NULL; |
| tw->compression = COMPRESSION_NONE; |
| tw->jpqual = 75; |
| tw->predictor = -1; |
| tw->tile = 0; |
| tw->tilew = 128; |
| tw->tileh = 128; |
| tw->pyramid = 0; |
| tw->onebit = 0; |
| tw->embed = 0; |
| tw->icc_profile = NULL; |
| tw->bigtiff = 0; |
| tw->write_lock = NULL; |
| |
| /* Output resolution settings ... default to VIPS-alike. |
| */ |
| tw->resunit = RESUNIT_CENTIMETER; |
| tw->xres = im->Xres * 10; |
| tw->yres = im->Yres * 10; |
| if( !im_meta_get_string( im, IM_META_RESOLUTION_UNIT, &p ) && |
| strcmp( p, "in" ) == 0 ) { |
| tw->resunit = RESUNIT_INCH; |
| tw->xres *= 2.54; |
| tw->yres *= 2.54; |
| } |
| |
| /* Parse mode string. |
| */ |
| strcpy( buf, mode ); |
| p = &buf[0]; |
| if( (q = im_getnextoption( &p )) ) { |
| if( im_isprefix( "none", q ) ) |
| tw->compression = COMPRESSION_NONE; |
| else if( im_isprefix( "packbits", q ) ) |
| tw->compression = COMPRESSION_PACKBITS; |
| else if( im_isprefix( "ccittfax4", q ) ) |
| tw->compression = COMPRESSION_CCITTFAX4; |
| else if( im_isprefix( "lzw", q ) ) { |
| tw->compression = COMPRESSION_LZW; |
| |
| if( (r = im_getsuboption( q )) ) |
| if( sscanf( r, "%d", &tw->predictor ) != 1 ) { |
| im_error( "im_vips2tiff", |
| "%s", _( "bad predictor " |
| "parameter" ) ); |
| return( NULL ); |
| } |
| } |
| else if( im_isprefix( "deflate", q ) ) { |
| tw->compression = COMPRESSION_ADOBE_DEFLATE; |
| |
| if( (r = im_getsuboption( q )) ) |
| if( sscanf( r, "%d", &tw->predictor ) != 1 ) { |
| im_error( "im_vips2tiff", |
| "%s", _( "bad predictor " |
| "parameter" ) ); |
| return( NULL ); |
| } |
| } |
| else if( im_isprefix( "jpeg", q ) ) { |
| tw->compression = COMPRESSION_JPEG; |
| |
| if( (r = im_getsuboption( q )) ) |
| if( sscanf( r, "%d", &tw->jpqual ) != 1 ) { |
| im_error( "im_vips2tiff", |
| "%s", _( "bad JPEG quality " |
| "parameter" ) ); |
| return( NULL ); |
| } |
| } |
| else { |
| im_error( "im_vips2tiff", _( "unknown compression mode " |
| "\"%s\"\nshould be one of \"none\", " |
| "\"packbits\", \"ccittfax4\", \"lzw\", " |
| "\"deflate\" or \"jpeg\"" ), q ); |
| return( NULL ); |
| } |
| } |
| if( (q = im_getnextoption( &p )) ) { |
| if( im_isprefix( "tile", q ) ) { |
| tw->tile = 1; |
| |
| if( (r = im_getsuboption( q )) ) { |
| if( sscanf( r, "%dx%d", |
| &tw->tilew, &tw->tileh ) != 2 ) { |
| im_error( "im_vips2tiff", "%s", |
| _( "bad tile sizes" ) ); |
| return( NULL ); |
| } |
| |
| if( tw->tilew < 10 || tw->tileh < 10 || |
| tw->tilew > 1000 || tw->tileh > 1000 ) { |
| im_error( "im_vips2tiff", |
| _( "bad tile size %dx%d" ), |
| tw->tilew, tw->tileh ); |
| return( NULL ); |
| } |
| |
| if( (tw->tilew & 0xf) != 0 || |
| (tw->tileh & 0xf) != 0 ) { |
| im_error( "im_vips2tiff", "%s", |
| _( "tile size not a " |
| "multiple of 16" ) ); |
| return( NULL ); |
| } |
| } |
| } |
| else if( im_isprefix( "strip", q ) ) |
| tw->tile = 0; |
| else { |
| im_error( "im_vips2tiff", _( "unknown layout mode " |
| "\"%s\"\nshould be one of \"tile\" or " |
| "\"strip\"" ), q ); |
| return( NULL ); |
| } |
| } |
| if( (q = im_getnextoption( &p )) ) { |
| if( im_isprefix( "pyramid", q ) ) |
| tw->pyramid = 1; |
| else if( im_isprefix( "flat", q ) ) |
| tw->pyramid = 0; |
| else { |
| im_error( "im_vips2tiff", _( "unknown multi-res mode " |
| "\"%s\"\nshould be one of \"flat\" or " |
| "\"pyramid\"" ), q ); |
| return( NULL ); |
| } |
| } |
| if( (q = im_getnextoption( &p )) ) { |
| if( im_isprefix( "onebit", q ) ) |
| tw->onebit = 1; |
| else if( im_isprefix( "manybit", q ) ) |
| tw->onebit = 0; |
| else { |
| im_error( "im_vips2tiff", _( "unknown format " |
| "\"%s\"\nshould be one of \"onebit\" or " |
| "\"manybit\"" ), q ); |
| return( NULL ); |
| } |
| } |
| if( (q = im_getnextoption( &p )) ) { |
| if( im_isprefix( "res_cm", q ) ) { |
| if( tw->resunit == RESUNIT_INCH ) { |
| tw->xres /= 2.54; |
| tw->yres /= 2.54; |
| } |
| tw->resunit = RESUNIT_CENTIMETER; |
| } |
| else if( im_isprefix( "res_inch", q ) ) { |
| if( tw->resunit == RESUNIT_CENTIMETER ) { |
| tw->xres *= 2.54; |
| tw->yres *= 2.54; |
| } |
| tw->resunit = RESUNIT_INCH; |
| } |
| else { |
| im_error( "im_vips2tiff", _( "unknown resolution unit " |
| "\"%s\"\nshould be one of \"res_cm\" or " |
| "\"res_inch\"" ), q ); |
| return( NULL ); |
| } |
| |
| if( (r = im_getsuboption( q )) ) { |
| if( sscanf( r, "%fx%f", &tw->xres, &tw->yres ) != 2 ) { |
| if( sscanf( r, "%f", &tw->xres ) != 1 ) { |
| im_error( "im_vips2tiff", "%s", |
| _( "bad resolution values" ) ); |
| return( NULL ); |
| } |
| |
| tw->yres = tw->xres; |
| } |
| } |
| } |
| if( (q = im_getnextoption( &p )) && strcmp( q, "" ) != 0 ) { |
| tw->embed = 1; |
| tw->icc_profile = im_strdup( NULL, q ); |
| } |
| if( (q = im_getnextoption( &p )) && strcmp( q, "8" ) == 0 ) { |
| tw->bigtiff = 1; |
| } |
| if( (q = im_getnextoption( &p )) ) { |
| im_error( "im_vips2tiff", |
| _( "unknown extra options \"%s\"" ), q ); |
| return( NULL ); |
| } |
| if( !tw->tile && tw->pyramid ) { |
| im_warn( "im_vips2tiff", "%s", _( "can't have strip pyramid -- " |
| "enabling tiling" ) ); |
| tw->tile = 1; |
| } |
| |
| /* We can only pyramid LABQ and non-complex images. |
| */ |
| if( tw->pyramid ) { |
| if( im->Coding == IM_CODING_NONE && |
| vips_bandfmt_iscomplex( im->BandFmt ) ) { |
| im_error( "im_vips2tiff", |
| "%s", _( "can only pyramid LABQ and " |
| "non-complex images" ) ); |
| return( NULL ); |
| } |
| } |
| |
| /* Only 1-bit-ize 8 bit mono images. |
| */ |
| if( tw->onebit ) { |
| if( im->Coding != IM_CODING_NONE || |
| im->BandFmt != IM_BANDFMT_UCHAR || |
| im->Bands != 1 ) |
| tw->onebit = 0; |
| } |
| |
| if( tw->onebit && tw->compression == COMPRESSION_JPEG ) { |
| im_warn( "im_vips2tiff", "%s", _( "can't have 1-bit JPEG -- " |
| "disabling JPEG" ) ); |
| tw->compression = COMPRESSION_NONE; |
| } |
| |
| /* Sizeof a line of bytes in the TIFF tile. |
| */ |
| if( im->Coding == IM_CODING_LABQ ) |
| tw->tls = tw->tilew * 3; |
| else if( tw->onebit ) |
| tw->tls = ROUND_UP( tw->tilew, 8 ) / 8; |
| else |
| tw->tls = IM_IMAGE_SIZEOF_PEL( im ) * tw->tilew; |
| |
| return( tw ); |
| } |
| |
| /* Copy fields. |
| */ |
| #define CopyField( tag, v ) \ |
| if( TIFFGetField( in, tag, &v ) ) TIFFSetField( out, tag, v ) |
| |
| /* Copy a TIFF file ... we know we wrote it, so just copy the tags we know |
| * we might have set. |
| */ |
| static int |
| tiff_copy( TiffWrite *tw, TIFF *out, TIFF *in ) |
| { |
| uint32 i32; |
| uint16 i16; |
| float f; |
| tdata_t buf; |
| ttile_t tile; |
| ttile_t n; |
| |
| /* All the fields we might have set. |
| */ |
| CopyField( TIFFTAG_IMAGEWIDTH, i32 ); |
| CopyField( TIFFTAG_IMAGELENGTH, i32 ); |
| CopyField( TIFFTAG_PLANARCONFIG, i16 ); |
| CopyField( TIFFTAG_ORIENTATION, i16 ); |
| CopyField( TIFFTAG_XRESOLUTION, f ); |
| CopyField( TIFFTAG_YRESOLUTION, f ); |
| CopyField( TIFFTAG_RESOLUTIONUNIT, i16 ); |
| CopyField( TIFFTAG_COMPRESSION, i16 ); |
| CopyField( TIFFTAG_SAMPLESPERPIXEL, i16 ); |
| CopyField( TIFFTAG_BITSPERSAMPLE, i16 ); |
| CopyField( TIFFTAG_PHOTOMETRIC, i16 ); |
| CopyField( TIFFTAG_TILEWIDTH, i32 ); |
| CopyField( TIFFTAG_TILELENGTH, i32 ); |
| CopyField( TIFFTAG_ROWSPERSTRIP, i32 ); |
| |
| if( tw->predictor != -1 ) |
| TIFFSetField( out, TIFFTAG_PREDICTOR, tw->predictor ); |
| |
| /* TIFFTAG_JPEGQUALITY is a pesudo-tag, so we can't copy it. |
| * Set explicitly from TiffWrite. |
| */ |
| if( tw->compression == COMPRESSION_JPEG ) |
| TIFFSetField( out, TIFFTAG_JPEGQUALITY, tw->jpqual ); |
| |
| /* We can't copy profiles :( Set again from TiffWrite. |
| */ |
| if( embed_profile( tw, out ) ) |
| return( -1 ); |
| |
| buf = im_malloc( NULL, TIFFTileSize( in ) ); |
| n = TIFFNumberOfTiles( in ); |
| for( tile = 0; tile < n; tile++ ) { |
| tsize_t len; |
| |
| /* It'd be good to use TIFFReadRawTile()/TIFFWriteRawTile() |
| * here to save compression/decompression, but sadly it seems |
| * not to work :-( investigate at some point. |
| */ |
| len = TIFFReadEncodedTile( in, tile, buf, (tsize_t) -1 ); |
| if( len < 0 || |
| TIFFWriteEncodedTile( out, tile, buf, len ) < 0 ) { |
| im_free( buf ); |
| return( -1 ); |
| } |
| } |
| im_free( buf ); |
| |
| return( 0 ); |
| } |
| |
| /* Append a file to a TIFF file. |
| */ |
| static int |
| tiff_append( TiffWrite *tw, TIFF *out, const char *name ) |
| { |
| TIFF *in; |
| |
| if( !(in = tiff_openin( name )) ) |
| return( -1 ); |
| |
| if( tiff_copy( tw, out, in ) ) { |
| TIFFClose( in ); |
| return( -1 ); |
| } |
| TIFFClose( in ); |
| |
| if( !TIFFWriteDirectory( out ) ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| /* Gather all of the files we wrote into single output file. |
| */ |
| static int |
| gather_pyramid( TiffWrite *tw ) |
| { |
| PyramidLayer *layer; |
| TIFF *out; |
| |
| #ifdef DEBUG |
| printf( "Starting pyramid gather ...\n" ); |
| #endif /*DEBUG*/ |
| |
| if( !(out = tiff_openout( tw, tw->name )) ) |
| return( -1 ); |
| |
| if( tiff_append( tw, out, tw->bname ) ) { |
| TIFFClose( out ); |
| return( -1 ); |
| } |
| |
| for( layer = tw->layer; layer; layer = layer->below ) |
| if( tiff_append( tw, out, layer->lname ) ) { |
| TIFFClose( out ); |
| return( -1 ); |
| } |
| |
| TIFFClose( out ); |
| |
| #ifdef DEBUG |
| printf( "Pyramid built\n" ); |
| #endif /*DEBUG*/ |
| |
| return( 0 ); |
| } |
| |
| |
| /** |
| * im_vips2tiff: |
| * @in: image to save |
| * @filename: file to write to |
| * |
| * Write a VIPS image to a file as TIFF. |
| * |
| * You can embed options in the filename. They have the form: |
| * |
| * |[ |
| * filename.tif:<emphasis>compression</emphasis>,<emphasis>layout</emphasis>,<emphasis>multi-res</emphasis>,<emphasis>format</emphasis>,<emphasis>resolution</emphasis>,<emphasis>icc</emphasis>, <emphasis>bigtiff</emphasis> |
| * ]| |
| * |
| * <itemizedlist> |
| * <listitem> |
| * <para> |
| * <emphasis>compression</emphasis> |
| * should be one of "none" (no compression), "jpeg" (JPEG compression), |
| * "deflate" (ZIP compression), "packbits" (TIFF packbits compression), |
| * "ccittfax4" (CCITT Group 4 fax encoding), "lzw" (Lempel-Ziv compression). |
| * |
| * "jpeg" compression can be followed by a ":" character and a JPEG quality |
| * level; "lzw" and "deflate" can be followed by a ":" and predictor value. |
| * The default compression type is "none", the default JPEG quality factor |
| * is 75. |
| * |
| * Predictor is not set by default. There are three predictor values recognised |
| * at the moment (2007, July): 1 is no prediction, 2 is a horizontal |
| * differencing and 3 is a floating point predictor. Refer to the libtiff |
| * specifications for further discussion of various predictors. In short, |
| * predictor helps to better compress image, especially in case of digital |
| * photos or scanned images and bit depths > 8. Try it to find whether it |
| * works for your images. |
| * |
| * JPEG compression is a good lossy compressor for photographs, packbits is |
| * good for 1-bit images, and deflate is the best lossless compression TIFF |
| * can do. LZW has patent problems and is no longer recommended. |
| * </para> |
| * </listitem> |
| * <listitem> |
| * <para> |
| * <emphasis>layout</emphasis> |
| * should be "strip" (strip layout) or "tile" (tiled layout). |
| * |
| * "tile" layout can be followed by a ":" character and the horizontal and |
| * vertical tile size, separated by a "x" character. The default layout is |
| * "strip", and the default tile size is 128 by 128 pixels. |
| * </para> |
| * </listitem> |
| * <listitem> |
| * <para> |
| * <emphasis>multi-res</emphasis> |
| * should be "flat" (single image) or "pyramid" (many images arranged in a |
| * pyramid). The default multi-res mode is "flat". |
| * </para> |
| * </listitem> |
| * <listitem> |
| * <para> |
| * <emphasis>format</emphasis> |
| * shoiuld be "manybit" (don't bit-reduce images) or "onebit" (one band 8 |
| * bit images are saved as 1 bit). The default format is "multibit". |
| * </para> |
| * </listitem> |
| * <listitem> |
| * <para> |
| * <emphasis>resolution</emphasis> |
| * should be "res_cm" (output resolution unit is pixels per centimetre) or |
| * "res_inch" (output resolution unit is pixels per inch). The default |
| * resolution unit is taken from the header field "resolution-unit" |
| * (#IM_META_RESOLUTION_UNIT in C). If this field is not set, then |
| * VIPS defaults to cm. |
| * |
| * The unit can optionally be followed by a ":" character and the |
| * horizontal and vertical resolution, separated by a "x" character. |
| * You can have a single number with no "x" and set the horizontal and |
| * vertical resolutions together. |
| * </para> |
| * </listitem> |
| * <listitem> |
| * <para> |
| * <emphasis>icc</emphasis> |
| * Attach this ICC profile. |
| * This does not affect the pixels which are written, just the way |
| * they are tagged. |
| * </para> |
| * </listitem> |
| * <listitem> |
| * <para> |
| * <emphasis>bigtiff</emphasis> |
| * Set this to 8 to enable bigtiff output. Bigtiff is a variant of the TIFF |
| * format that allows more than 4GB in a file. |
| * </para> |
| * </listitem> |
| * </itemizedlist> |
| * |
| * Example: |
| * |
| * |[ |
| * im_vips2jpeg( in, "fred.tif:jpeg,tile,pyramid" ); |
| * ]| |
| * |
| * Will write "fred.tif" as a tiled jpeg-compressed pyramid. |
| * |
| * |[ |
| * im_vips2jpeg( in, "fred.tif:packbits,tile,,onebit" ); |
| * ]| |
| * |
| * Writes a tiled one bit TIFF image (provided fred.v is a one band 8 bit |
| * image) compressed with packbits. |
| * |
| * See also: #VipsFormat, im_tiff2vips(). |
| * |
| * Returns: 0 on success, -1 on error. |
| */ |
| int |
| im_vips2tiff( IMAGE *in, const char *filename ) |
| { |
| TiffWrite *tw; |
| int res; |
| |
| #ifdef DEBUG |
| printf( "im_tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion() ); |
| #endif /*DEBUG*/ |
| |
| /* Override the default TIFF error handler. |
| */ |
| TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error ); |
| TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning ); |
| |
| /* Check input image. |
| */ |
| if( im_pincheck( in ) || |
| im_check_coding_known( "im_vips2tiff", in ) ) |
| return( -1 ); |
| if( in->BandFmt != IM_BANDFMT_UCHAR && |
| !(in->BandFmt == IM_BANDFMT_SHORT && |
| in->Type == IM_TYPE_LABS) && |
| in->BandFmt != IM_BANDFMT_USHORT && |
| in->BandFmt != IM_BANDFMT_FLOAT ) { |
| im_error( "im_vips2tiff", "%s", |
| _( "unsigned 8-bit int, 16-bit int, " |
| "and 32-bit float only" ) ); |
| return( -1 ); |
| } |
| if( in->Coding == IM_CODING_NONE ) { |
| if( in->Bands < 1 || in->Bands > 5 ) { |
| im_error( "im_vips2tiff", "%s", |
| _( "1 to 5 bands only" ) ); |
| return( -1 ); |
| } |
| } |
| |
| /* Make output image. If this is a pyramid, write the base image to |
| * fred.1.tif rather than fred.tif. |
| */ |
| if( !(tw = make_tiff_write( in, filename )) ) |
| return( -1 ); |
| if( tw->pyramid ) { |
| if( !(tw->bname = new_tiff_name( tw, tw->name, 1 )) || |
| !(tw->tif = tiff_openout( tw, tw->bname )) ) { |
| free_tiff_write( tw ); |
| return( -1 ); |
| } |
| } |
| else { |
| /* No pyramid ... write straight to name. |
| */ |
| if( !(tw->tif = tiff_openout( tw, tw->name )) ) { |
| free_tiff_write( tw ); |
| return( -1 ); |
| } |
| } |
| |
| /* Write the TIFF header for the full-res file. |
| */ |
| if( write_tiff_header( tw, tw->tif, in->Xsize, in->Ysize ) ) { |
| free_tiff_write( tw ); |
| return( -1 ); |
| } |
| |
| |
| if( tw->tile ) |
| res = write_tif_tilewise( tw ); |
| else |
| res = write_tif_stripwise( tw ); |
| if( res ) { |
| free_tiff_write( tw ); |
| return( -1 ); |
| } |
| |
| /* Free pyramid resources ... this will TIFFClose() the intermediates, |
| * ready for us to read from them again. |
| */ |
| if( tw->layer ) |
| free_pyramid( tw->layer ); |
| if( tw->tif ) { |
| TIFFClose( tw->tif ); |
| tw->tif = NULL; |
| } |
| |
| /* Gather layers together into final pyramid file. |
| */ |
| if( tw->pyramid && gather_pyramid( tw ) ) { |
| free_tiff_write( tw ); |
| return( -1 ); |
| } |
| |
| free_tiff_write( tw ); |
| |
| return( 0 ); |
| } |
| |
| #endif /*HAVE_TIFF*/ |