Skip to content

Commit

Permalink
TIFF: more compression codec support
Browse files Browse the repository at this point in the history
- more codecs have a name defined for them
- you can now use the libtiff defined name for the codec in
  tiff_compression
- you can get a list of defined codes
  • Loading branch information
tonycoz committed Nov 21, 2023
1 parent 79b872d commit 53669e1
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 3 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/libtiff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: install dependencies
run: |
sudo apt-get update ||:
sudo apt-get -y install build-essential automake autoconf libtool m4 git yasm pkgconf libjpeg-turbo8-dev
sudo apt-get -y install build-essential automake autoconf libtool m4 git yasm pkgconf libjpeg-turbo8-dev libwebp-dev liblerc-dev
wget https://download.osgeo.org/libtiff/tiff-${{ matrix.LIBTIFF_RELEASE }}.tar.gz
ls
tar xzf tiff-${{ matrix.LIBTIFF_RELEASE }}.tar.gz
Expand Down Expand Up @@ -57,3 +57,7 @@ jobs:
- name: test
run: |
make -C TIFF test
- name: codecs
run: |
cd TIFF
perl -Mblib -MImager::File::TIFF -E 'say "$_->{code}: $_->{description} ($_->{name})" for sort { $a->{code} <=> $b->{code} } Imager::File::TIFF->codecs'
33 changes: 33 additions & 0 deletions TIFF/TIFF.pm
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,43 @@ Imager::File::TIFF - read and write TIFF files
$img->write(file => "foo.tif")
or die $img->errstr;
my @codecs = Imager::File::TIFF->codecs;
=head1 DESCRIPTION
Imager's TIFF support is documented in L<Imager::Files>.
=head1 CLASS METHODS
=over
=item Imager::File::TIFF->codecs
Returns a list of hashrefs, each hash contains:
=over
=item *
C<code> - the numeric TIFF defined identifier for this compression
codec.
=item *
C<name> - the short name traditionally used by Imager::File::TIFF for
this compression codec. This may be an empty string if
Imager::File::TIFF doesn't have a name for this codec.
=item *
C<description> - the C<libtiff> defined name for this codec. You can
now supply this name in the C<tiff_compression> tag to select this
compression.
=back
=back
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
Expand Down
17 changes: 17 additions & 0 deletions TIFF/TIFF.xs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,23 @@ const char *
i_tiff_builddate(...)
C_ARGS:

void
i_tiff_codecs(class)
PPCODE:
size_t count;
i_tiff_codec *codecs = i_tiff_get_codecs(&count);
EXTEND(SP, count);
for (int i = 0; i < count; ++i) {
i_tiff_codec *codec = codecs + i;
HV *hv = newHV();
hv_stores(hv, "description", newSVpvn(codec->description, strlen(codec->description)));
hv_stores(hv, "name", newSVpv(codec->name, 0));
hv_stores(hv, "code", newSViv(codec->code));
SV *rv = newRV_noinc((SV*)hv);
PUSHs(sv_2mortal(rv));
}
myfree(codecs);

BOOT:
PERL_INITIALIZE_IMAGER_CALLBACKS;
i_tiff_init();
52 changes: 51 additions & 1 deletion TIFF/imtiff.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,23 @@ compress_values[] =
{ "fax4", COMPRESSION_CCITTFAX4 },
{ "t6", COMPRESSION_CCITTFAX4 },
{ "lzw", COMPRESSION_LZW },
{ "oldjpeg", COMPRESSION_OJPEG },
{ "jpeg", COMPRESSION_JPEG },
{ "next", COMPRESSION_NEXT },
{ "packbits", COMPRESSION_PACKBITS },
{ "thunder", COMPRESSION_THUNDERSCAN },
{ "deflate", COMPRESSION_ADOBE_DEFLATE },
{ "zip", COMPRESSION_ADOBE_DEFLATE },
{ "pixarlog", COMPRESSION_PIXARLOG },
{ "oldzip", COMPRESSION_DEFLATE },
{ "ccittrlew", COMPRESSION_CCITTRLEW },
{ "jbig", COMPRESSION_JBIG },
{ "sgilog", COMPRESSION_SGILOG },
{ "sgilog24", COMPRESSION_SGILOG24 },
{ "lerc", COMPRESSION_LERC },
{ "lzma", COMPRESSION_LZMA },
{ "zstd", COMPRESSION_ZSTD },
{ "webp", COMPRESSION_WEBP },
};

static const int compress_value_count =
Expand Down Expand Up @@ -921,10 +932,20 @@ get_compression(i_img *im, tf_uint16 def_compress) {

if (i_tags_find(&im->tags, "tiff_compression", 0, &entry)
&& im->tags.tags[entry].data) {
const char *name = im->tags.tags[entry].data;
tf_uint16 compress;
if (find_compression(im->tags.tags[entry].data, &compress)
if (find_compression(name, &compress)
&& TIFFIsCODECConfigured(compress))
return compress;

TIFFCodec *codecs = TIFFGetConfiguredCODECs();
for (TIFFCodec *c = codecs; c->name; ++c) {
if (strcmp(c->name, name) == 0) {
_TIFFfree(codecs);
return c->scheme;
}
}
_TIFFfree(codecs);
}
if (i_tags_get_int(&im->tags, "tiff_compression", 0, &value)) {
if ((tf_uint16)value == value
Expand Down Expand Up @@ -2728,6 +2749,35 @@ tiffio_context_final(tiffio_context_t *c) {
myfree(c->warn_buffer);
}

i_tiff_codec *
i_tiff_get_codecs(size_t *pcount) {
TIFFCodec *codecs = TIFFGetConfiguredCODECs();

if (!codecs)
return NULL;

int count;
for (count = 0; codecs[count].name; ++count) {
/* just counting */
}
i_tiff_codec *mycodecs = mymalloc(sizeof(i_tiff_codec) * count);
for (int i = 0; i < count; ++i) {
mycodecs[i].description = codecs[i].name;
mycodecs[i].name = "";
for (int j = 0; j < compress_value_count; ++j) {
if (codecs[i].scheme == compress_values[j].tag) {
mycodecs[i].name = compress_values[j].name;
break;
}
}
mycodecs[i].code = codecs[i].scheme;
}
_TIFFfree(codecs);

*pcount = count;
return mycodecs;
}

/*
=back
Expand Down
8 changes: 8 additions & 0 deletions TIFF/imtiff.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@ char const * i_tiff_libversion(void);
char const * i_tiff_builddate(void);
int i_tiff_has_compression(char const *name);

typedef struct {
const char *description;
const char *name;
unsigned code;
} i_tiff_codec;

i_tiff_codec *i_tiff_get_codecs(size_t *pcount);

#endif
35 changes: 34 additions & 1 deletion TIFF/t/t10tiff.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!perl -w
use strict;
use Test::More tests => 247;
use Test::More;
use Imager qw(:all);
use Imager::Test qw(is_image is_image_similar test_image test_image_16 test_image_double test_image_raw);

Expand Down Expand Up @@ -881,3 +881,36 @@ SKIP:
is($tags{tiff_sample_format_name}, "ieeefp", "check sample format name");
}
}

{
my @codecs = Imager::File::TIFF->codecs;

my %codecs = map {; $_->{code} => $_ } @codecs;

is($codecs{1}{description}, "None", "no compression description");
is($codecs{1}{name}, "none", "no compression name");
is($codecs{5}{description}, "LZW", "LZW description");
is($codecs{5}{name}, "lzw", "LZW name");
is($codecs{32773}{description}, "PackBits", "PackBits description");
is($codecs{32773}{name}, "packbits", "PackBits name");
is($codecs{32771}{description}, "CCITT RLE/W", "CCITT RLE/W description");
is($codecs{32771}{name}, "ccittrlew", "CCITT RLE/W name");
}

SKIP:
{
# check compression selection by name works
my @codecs = Imager::File::TIFF->codecs;
grep { $_->{description} eq "AdobeDeflate" } @codecs
or skip "No AdobeDeflate available", 1;
my $im = test_image;
my $data;
ok($im->write(type => "tiff", data => \$data, tiff_compression => "AdobeDeflate"),
"write with AdobeDeflate");
my $im2 = Imager->new(data => \$data);
is_image($im, $im2, "check read image matches");
is($im2->tags(name => "tiff_compression"), "deflate",
"got expected compression");
}

done_testing();

0 comments on commit 53669e1

Please sign in to comment.