diff --git a/configure.ac b/configure.ac index 5dd1bc5d..cd892bd9 100644 --- a/configure.ac +++ b/configure.ac @@ -658,6 +658,57 @@ if test "$HAVE_JBIG" = "yes" ; then fi +dnl --------------------------------------------------------------------------- +dnl Check for liblzma2. +dnl --------------------------------------------------------------------------- + +HAVE_LZMA=no + +AC_ARG_ENABLE(lzma, + AS_HELP_STRING([--disable-lzma], + [disable liblzma usage (required for LZMA2 compression, enabled by default)]),,) +AC_ARG_WITH(lzma-include-dir, + AS_HELP_STRING([--with-lzma-include-dir=DIR], + [location of liblzma headers]),,) +AC_ARG_WITH(lzma-lib-dir, + AS_HELP_STRING([--with-lzma-lib-dir=DIR], + [location of liblzma library binary]),,) + +if test "x$enable_lzma" != "xno" ; then + + if test "x$with_lzma_lib_dir" != "x" ; then + LDFLAGS="-L$with_lzma_lib_dir $LDFLAGS" + fi + + AC_CHECK_LIB(lzma, lzma_code, [lzma_lib=yes], [lzma_lib=no],) + if test "$lzma_lib" = "no" -a "x$with_lzma_lib_dir" != "x"; then + AC_MSG_ERROR([lzma library not found at $with_lzma_lib_dir]) + fi + + if test "x$with_lzma_include_dir" != "x" ; then + CPPFLAGS="-I$with_lzma_include_dir $CPPFLAGS" + fi + AC_CHECK_HEADER(lzma.h, [lzma_h=yes], [lzma_h=no]) + if test "$lzma_h" = "no" -a "x$with_lzma_include_dir" != "x" ; then + AC_MSG_ERROR([Liblzma headers not found at $with_lzma_include_dir]) + fi + + if test "$lzma_lib" = "yes" -a "$lzma_h" = "yes" ; then + HAVE_LZMA=yes + fi + +fi + +if test "$HAVE_LZMA" = "yes" ; then + AC_DEFINE(LZMA_SUPPORT,1,[Support LZMA2 compression]) + LIBS="-llzma $LIBS" + + if test "$HAVE_RPATH" = "yes" -a "x$with_lzma_lib_dir" != "x" ; then + LIBDIR="-R $with_lzma_lib_dir $LIBDIR" + fi + +fi + dnl --------------------------------------------------------------------------- dnl Should 8/12 bit jpeg mode be enabled? dnl --------------------------------------------------------------------------- @@ -863,6 +914,7 @@ LOC_MSG([ JPEG support: ${HAVE_JPEG}]) LOC_MSG([ Old JPEG support: ${HAVE_OJPEG}]) LOC_MSG([ JPEG 8/12 bit dual mode: ${HAVE_JPEG12}]) LOC_MSG([ ISO JBIG support: ${HAVE_JBIG}]) +LOC_MSG([ LZMA2 support: ${HAVE_LZMA}]) LOC_MSG() LOC_MSG([ C++ support: ${HAVE_CXX}]) LOC_MSG() diff --git a/libtiff/tif_codec.c b/libtiff/tif_codec.c index ffcda6c8..e2016673 100644 --- a/libtiff/tif_codec.c +++ b/libtiff/tif_codec.c @@ -1,4 +1,4 @@ -/* $Id: tif_codec.c,v 1.14 2010-03-10 18:56:48 bfriesen Exp $ */ +/* $Id: tif_codec.c,v 1.15 2010-12-14 12:53:00 dron Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -69,6 +69,9 @@ static int NotConfigured(TIFF*, int); #ifndef LOGLUV_SUPPORT #define TIFFInitSGILog NotConfigured #endif +#ifndef LZMA_SUPPORT +#define TIFFInitLZMA NotConfigured +#endif /* * Compression schemes statically built into the library. @@ -95,6 +98,7 @@ TIFFCodec _TIFFBuiltinCODECS[] = { { "PixarLog", COMPRESSION_PIXARLOG, TIFFInitPixarLog }, { "SGILog", COMPRESSION_SGILOG, TIFFInitSGILog }, { "SGILog24", COMPRESSION_SGILOG24, TIFFInitSGILog }, + { "LZMA", COMPRESSION_LZMA, TIFFInitLZMA }, { NULL, 0, NULL } }; diff --git a/libtiff/tif_config.h.in b/libtiff/tif_config.h.in index b69eb2d1..cfb16fd3 100644 --- a/libtiff/tif_config.h.in +++ b/libtiff/tif_config.h.in @@ -195,6 +195,9 @@ */ #undef LT_OBJDIR +/* Support LZMA2 compression */ +#undef LZMA_SUPPORT + /* Support LZW algorithm */ #undef LZW_SUPPORT diff --git a/libtiff/tif_lzma.c b/libtiff/tif_lzma.c new file mode 100644 index 00000000..f54016e0 --- /dev/null +++ b/libtiff/tif_lzma.c @@ -0,0 +1,476 @@ +/* $Id: tif_lzma.c,v 1.1 2010-12-14 12:53:00 dron Exp $ */ + +/* + * Copyright (c) 2010, Andrey Kiselev + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef LZMA_SUPPORT +/* + * TIFF Library. + * + * LZMA2 Compression Support + * + * You need an LZMA2 SDK to link with. See http://tukaani.org/xz/ for details. + * + * The codec is derived from ZLIB codec (tif_zip.c). + */ + +#include "tif_predict.h" +#include "lzma.h" + +#include + +/* + * State block for each open TIFF file using LZMA2 compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + lzma_stream stream; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_options_delta opt_delta; /* delta filter options */ + lzma_options_lzma opt_lzma; /* LZMA2 filter options */ + int preset; /* compression level */ + lzma_check check; /* type of the integrity check */ + int state; /* state flags */ +#define LSTATE_INIT_DECODE 0x01 +#define LSTATE_INIT_ENCODE 0x02 + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} LZMAState; + +#define LState(tif) ((LZMAState*) (tif)->tif_data) +#define DecoderState(tif) LState(tif) +#define EncoderState(tif) LState(tif) + +static int LZMAEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s); +static int LZMADecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s); + +static const char * +LZMAStrerror(lzma_ret ret) +{ + switch (ret) { + case LZMA_OK: + return "operation completed successfully"; + case LZMA_STREAM_END: + return "end of stream was reached"; + case LZMA_NO_CHECK: + return "input stream has no integrity check"; + case LZMA_UNSUPPORTED_CHECK: + return "cannot calculate the integrity check"; + case LZMA_GET_CHECK: + return "integrity check type is now available"; + case LZMA_MEM_ERROR: + return "cannot allocate memory"; + case LZMA_MEMLIMIT_ERROR: + return "memory usage limit was reached"; + case LZMA_FORMAT_ERROR: + return "file format not recognized"; + case LZMA_OPTIONS_ERROR: + return "invalid or unsupported options"; + case LZMA_DATA_ERROR: + return "data is corrupt"; + case LZMA_BUF_ERROR: + return "no progress is possible (stream is truncated or corrupt)"; + case LZMA_PROG_ERROR: + return "programming error"; + default: + return "unindentified liblzma error"; + } +} + +static int +LZMAFixupTags(TIFF* tif) +{ + (void) tif; + return 1; +} + +static int +LZMASetupDecode(TIFF* tif) +{ + LZMAState* sp = DecoderState(tif); + + assert(sp != NULL); + + /* if we were last encoding, terminate this mode */ + if (sp->state & LSTATE_INIT_ENCODE) { + lzma_end(&sp->stream); + sp->state = 0; + } + + sp->state |= LSTATE_INIT_DECODE; + return 1; +} + +/* + * Setup state for decoding a strip. + */ +static int +LZMAPreDecode(TIFF* tif, uint16 s) +{ + static const char module[] = "LZMAPreDecode"; + LZMAState* sp = DecoderState(tif); + lzma_ret ret; + + (void) s; + assert(sp != NULL); + + if( (sp->state & LSTATE_INIT_DECODE) == 0 ) + tif->tif_setupdecode(tif); + + sp->stream.next_in = tif->tif_rawdata; + sp->stream.avail_in = (size_t) tif->tif_rawcc; + if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc) { + TIFFErrorExt(tif->tif_clientdata, module, + "Liblzma cannot deal with buffers this size"); + return 0; + } + + /* + * Disable memory limit when decoding. UINT64_MAX is a flag to disable + * the limit, we are passing (uint64_t)-1 which should be the same. + */ + ret = lzma_stream_decoder(&sp->stream, (uint64_t)-1, 0); + if (ret != LZMA_OK) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error initializing the stream decoder, %s", + LZMAStrerror(ret)); + return 0; + } + return 1; +} + +static int +LZMADecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) +{ + static const char module[] = "LZMADecode"; + LZMAState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_DECODE); + + sp->stream.next_out = op; + sp->stream.avail_out = (size_t) occ; + if ((tmsize_t)sp->stream.avail_out != occ) { + TIFFErrorExt(tif->tif_clientdata, module, + "Liblzma cannot deal with buffers this size"); + return 0; + } + + do { + /* + * Save the current stream state to properly recover from the + * decoding errors later. + */ + const uint8_t *next_in = sp->stream.next_in; + size_t avail_in = sp->stream.avail_in; + + lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN); + if (ret == LZMA_STREAM_END) + break; + if (ret == LZMA_MEMLIMIT_ERROR) { + lzma_ret r = lzma_stream_decoder(&sp->stream, + lzma_memusage(&sp->stream), 0); + if (r != LZMA_OK) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error initializing the stream decoder, %s", + LZMAStrerror(r)); + break; + } + sp->stream.next_in = next_in; + sp->stream.avail_in = avail_in; + continue; + } + if (ret != LZMA_OK) { + TIFFErrorExt(tif->tif_clientdata, module, + "Decoding error at scanline %lu, %s", + (unsigned long) tif->tif_row, LZMAStrerror(ret)); + break; + } + } while (sp->stream.avail_out > 0); + if (sp->stream.avail_out != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %lu (short %lu bytes)", + (unsigned long) tif->tif_row, (unsigned long) sp->stream.avail_out); + return 0; + } + return 1; +} + +static int +LZMASetupEncode(TIFF* tif) +{ + LZMAState* sp = EncoderState(tif); + + assert(sp != NULL); + if (sp->state & LSTATE_INIT_DECODE) { + lzma_end(&sp->stream); + sp->state = 0; + } + + sp->state |= LSTATE_INIT_ENCODE; + return 1; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +LZMAPreEncode(TIFF* tif, uint16 s) +{ + static const char module[] = "LZMAPreEncode"; + LZMAState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + if( sp->state != LSTATE_INIT_ENCODE ) + tif->tif_setupencode(tif); + + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (size_t)tif->tif_rawdatasize; + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) { + TIFFErrorExt(tif->tif_clientdata, module, + "Liblzma cannot deal with buffers this size"); + return 0; + } + return (lzma_stream_encoder(&sp->stream, sp->filters, sp->check) == LZMA_OK); +} + +/* + * Encode a chunk of pixels. + */ +static int +LZMAEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + static const char module[] = "LZMAEncode"; + LZMAState *sp = EncoderState(tif); + + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_ENCODE); + + (void) s; + sp->stream.next_in = bp; + sp->stream.avail_in = (size_t) cc; + if ((tmsize_t)sp->stream.avail_in != cc) { + TIFFErrorExt(tif->tif_clientdata, module, + "Liblzma cannot deal with buffers this size"); + return 0; + } + do { + lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN); + if (ret != LZMA_OK) { + TIFFErrorExt(tif->tif_clientdata, module, + "Encoding error at scanline %lu, %s", + (unsigned long) tif->tif_row, LZMAStrerror(ret)); + return 0; + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (size_t)tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in LZMAPreEncode */ + } + } while (sp->stream.avail_in > 0); + return 1; +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +LZMAPostEncode(TIFF* tif) +{ + static const char module[] = "LZMAPostEncode"; + LZMAState *sp = EncoderState(tif); + lzma_ret ret; + + sp->stream.avail_in = 0; + do { + ret = lzma_code(&sp->stream, LZMA_FINISH); + switch (ret) { + case LZMA_STREAM_END: + case LZMA_OK: + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) { + tif->tif_rawcc = + tif->tif_rawdatasize - sp->stream.avail_out; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (size_t)tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in ZIPPreEncode */ + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, "Liblzma error: %s", + LZMAStrerror(ret)); + return 0; + } + } while (ret != LZMA_STREAM_END); + return 1; +} + +static void +LZMACleanup(TIFF* tif) +{ + LZMAState* sp = LState(tif); + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + lzma_end(&sp->stream); + sp->state = 0; + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +LZMAVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + LZMAState* sp = LState(tif); + + switch (tag) { + case TIFFTAG_LZMAPRESET: + sp->preset = (int) va_arg(ap, int); + if ( sp->state & LSTATE_INIT_ENCODE ) + lzma_lzma_preset(&sp->opt_lzma, sp->preset); + return 1; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int +LZMAVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + LZMAState* sp = LState(tif); + + switch (tag) { + case TIFFTAG_LZMAPRESET: + *va_arg(ap, int*) = sp->preset; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return 1; +} + +static const TIFFField lzmaFields[] = { + { TIFFTAG_LZMAPRESET, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, + FIELD_PSEUDO, TRUE, FALSE, "LZMA2 Compression Preset", NULL }, +}; + +int +TIFFInitLZMA(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitLZMA"; + LZMAState* sp; + lzma_stream tmp_stream = LZMA_STREAM_INIT; + + assert( scheme == COMPRESSION_LZMA ); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, lzmaFields, TIFFArrayCount(lzmaFields))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging LZMA2 codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8*) _TIFFmalloc(sizeof(LZMAState)); + if (tif->tif_data == NULL) + goto bad; + sp = LState(tif); + memcpy(&sp->stream, &tmp_stream, sizeof(lzma_stream)); + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = LZMAVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = LZMAVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->preset = LZMA_PRESET_DEFAULT; /* default comp. level */ + sp->check = LZMA_CHECK_NONE; + sp->state = 0; + + /* Data filters. So far we are using delta and LZMA2 filters only. */ + sp->opt_delta.type = LZMA_DELTA_TYPE_BYTE; + /* + * The sample size in bytes seems to be reasonable distance for delta + * filter. + */ + sp->opt_delta.dist = (tif->tif_dir.td_bitspersample % 8) ? + 1 : tif->tif_dir.td_bitspersample / 8; + sp->filters[0].id = LZMA_FILTER_DELTA; + sp->filters[0].options = &sp->opt_delta; + + lzma_lzma_preset(&sp->opt_lzma, sp->preset); + sp->filters[1].id = LZMA_FILTER_LZMA2; + sp->filters[1].options = &sp->opt_lzma; + + sp->filters[2].id = LZMA_VLI_UNKNOWN; + sp->filters[2].options = NULL; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = LZMAFixupTags; + tif->tif_setupdecode = LZMASetupDecode; + tif->tif_predecode = LZMAPreDecode; + tif->tif_decoderow = LZMADecode; + tif->tif_decodestrip = LZMADecode; + tif->tif_decodetile = LZMADecode; + tif->tif_setupencode = LZMASetupEncode; + tif->tif_preencode = LZMAPreEncode; + tif->tif_postencode = LZMAPostEncode; + tif->tif_encoderow = LZMAEncode; + tif->tif_encodestrip = LZMAEncode; + tif->tif_encodetile = LZMAEncode; + tif->tif_cleanup = LZMACleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return 1; +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for LZMA2 state block"); + return 0; +} +#endif /* LZMA_SUPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ diff --git a/libtiff/tiff.h b/libtiff/tiff.h index 4c95eda6..40592de2 100644 --- a/libtiff/tiff.h +++ b/libtiff/tiff.h @@ -1,4 +1,4 @@ -/* $Id: tiff.h,v 1.65 2010-03-10 18:56:49 bfriesen Exp $ */ +/* $Id: tiff.h,v 1.66 2010-12-14 12:53:00 dron Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -187,6 +187,7 @@ typedef enum { #define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ #define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ #define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */ +#define COMPRESSION_LZMA 34925 /* LZMA2 */ #define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ #define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ #define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ @@ -567,6 +568,7 @@ typedef enum { #define TIFFTAG_SGILOGENCODE 65561 /* SGILog data encoding control*/ #define SGILOGENCODE_NODITHER 0 /* do not dither encoded values*/ #define SGILOGENCODE_RANDITHER 1 /* randomly dither encd values */ +#define TIFFTAG_LZMAPRESET 65562 /* LZMA2 preset (compression level) */ /* * EXIF tags diff --git a/man/tiffcp.1 b/man/tiffcp.1 index e2f03d9f..b351f5fd 100644 --- a/man/tiffcp.1 +++ b/man/tiffcp.1 @@ -1,4 +1,4 @@ -.\" $Id: tiffcp.1,v 1.10 2010-06-03 17:01:02 fwarmerdam Exp $ +.\" $Id: tiffcp.1,v 1.11 2010-12-14 12:53:00 dron Exp $ .\" .\" Copyright (c) 1988-1997 Sam Leffler .\" Copyright (c) 1991-1997 Silicon Graphics, Inc. @@ -83,10 +83,12 @@ for no compression, for PackBits compression, .B lzw for Lempel-Ziv & Welch compression, -.B jpeg -for baseline JPEG compression, .B zip for Deflate compression, +.B lzma +for LZMA compression, +.B jpeg +for baseline JPEG compression, .B g3 for CCITT Group 3 (T.4) compression, and @@ -118,16 +120,16 @@ list to the ``g3'' option; e.g. .B "\-c g3:2d:fill" to get 2D-encoded data with byte-aligned EOL codes. .IP -.SM LZW +.SM LZW, Deflate +and +.SM LZMA compression can be specified together with a .I predictor value. -A predictor value of 2 causes -each scanline of the output image to undergo horizontal -differencing before it is encoded; a value -of 1 forces each scanline to be encoded without differencing. -LZW-specific options are specified by appending a ``:''-separated -list to the ``lzw'' option; e.g. +A predictor value of 2 causes each scanline of the output image to undergo +horizontal differencing before it is encoded; a value of 1 forces each +scanline to be encoded without differencing. LZW-specific options are +specified by appending a ``:''-separated list to the ``lzw'' option; e.g. .B "\-c lzw:2" for .SM LZW diff --git a/tools/tiffcp.c b/tools/tiffcp.c index f7ab4538..a444d8ba 100644 --- a/tools/tiffcp.c +++ b/tools/tiffcp.c @@ -1,4 +1,4 @@ -/* $Id: tiffcp.c,v 1.47 2010-06-25 12:24:13 dron Exp $ */ +/* $Id: tiffcp.c,v 1.48 2010-12-14 12:53:00 dron Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -371,6 +371,11 @@ processCompressOptions(char* opt) if (cp) defpredictor = atoi(cp+1); defcompression = COMPRESSION_ADOBE_DEFLATE; + } else if (strneq(opt, "lzma", 4)) { + char* cp = strchr(opt, ':'); + if (cp) + defpredictor = atoi(cp+1); + defcompression = COMPRESSION_LZMA; } else if (strneq(opt, "jbig", 4)) { defcompression = COMPRESSION_JBIG; } else if (strneq(opt, "sgilog", 6)) { @@ -403,6 +408,7 @@ char* stuff[] = { "", " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding", " -c zip[:opts] compress output with deflate encoding", +" -c lzma[:opts] compress output with LZMA encoding", " -c jpeg[:opts] compress output with JPEG encoding", " -c jbig compress output with ISO JBIG encoding", " -c packbits compress output with packbits encoding", @@ -423,7 +429,7 @@ char* stuff[] = { " r output color image as RGB rather than YCbCr", "For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality", "", -"LZW and deflate options:", +"LZW, Deflate (ZIP) and LZMA options:", " # set predictor value", "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing", "", @@ -698,6 +704,7 @@ tiffcp(TIFF* in, TIFF* out) case COMPRESSION_LZW: case COMPRESSION_ADOBE_DEFLATE: case COMPRESSION_DEFLATE: + case COMPRESSION_LZMA: if (predictor != (uint16)-1) TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); else @@ -1234,7 +1241,7 @@ DECLAREreadFunc(readSeparateStripsIntoBuffer) if (!scanlinesize) return 0; - scanline = _TIFFmalloc(scanlinesize); + scanline = _TIFFmalloc(scanlinesize); if (!scanline) return 0; _TIFFmemset(scanline, 0, scanlinesize);