]> git.imager.perl.org - imager.git/commitdiff
write paletted images as paletted for tiff
authorTony Cook <tony@develop=help.com>
Sat, 1 Dec 2001 03:25:12 +0000 (03:25 +0000)
committerTony Cook <tony@develop=help.com>
Sat, 1 Dec 2001 03:25:12 +0000 (03:25 +0000)
minor doc fix in freetyp2.c

Changes
TODO
freetyp2.c
t/t106tiff.t
tiff.c

diff --git a/Changes b/Changes
index 04b28960534d9c08408c2c972835654f53600bc8..7414ba3d31d3417a2c1e98c111a99dff52084052 100644 (file)
--- a/Changes
+++ b/Changes
@@ -558,7 +558,8 @@ Revision history for Perl extension Imager.
         - use the error stack value from reading bmp files
         - fix an error message in bmp.c
         - added has_chars() method to Imager::Font::FreeType2
-       - freetype 2 bounding box function didn't know UTF8 (doh!)
+        - freetype 2 bounding box function didn't know UTF8 (doh!)
+        - write paletted images as paletted to tiff
 
 =================================================================
 
diff --git a/TODO b/TODO
index b97b2e32b96c9afb6dda1b8bc449dcd202738a9d..1939efd7fd3eaea649535ea2b98cb597f4c2d149 100644 (file)
--- a/TODO
+++ b/TODO
@@ -55,6 +55,8 @@ New Features:
 - read_multi() needs to handle other multi-image types, such as TIFF 
   (probably the most common)
 
+- write_multi() to save other multi-image types, especially TIFF
+
 - compose channels - build a new image based on channels from several
   images
 
@@ -96,10 +98,12 @@ Format specific issues:
   pbm images which needs ties to the quantization code.
 
 - save paletted images as paletted where that's supported.  Done
-  for gif/tga.  Not done for png/tiff yet.
+  for gif/tga/bmp/tiff.  Not done for png yet.
 
 - read other format paletted images as paletted images.  This has 
-  been done for gif/tga formats but not for tiff/png.
+  been done for gif/tga/bmp/tiff formats but not for png.
+
+- read/write 16-bit/sample images as such for tiff
 
 Documentation:
 - Add to the documentation
index f180d4df60c6065d0e0824f2a9021dab9d9c98df..e155d5258e9392a5a678012e07e5e593d1fbc683 100644 (file)
@@ -13,7 +13,7 @@ freetyp2.c - font support via the FreeType library version 2.
   double matrix[6];
   if (!i_ft2_settransform(font, matrix)) { error }
   int bbox[6];
-  if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox)) { error }
+  if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox, utf8)) { error }
   i_img *im = ...;
   i_color cl;
   if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align,
index 4c6b7b1b01b06d42f2f285a6caaba5620fcc4e87..412b1f59fba9c52af5314af10ec618be8e6b65c3 100644 (file)
@@ -1,5 +1,5 @@
 #!perl -w
-print "1..33\n";
+print "1..43\n";
 use Imager qw(:all);
 $^W=1; # warnings during command-line tests
 $|=1;  # give us some progress in the test harness
@@ -24,7 +24,7 @@ i_box_filled($timg, 2, 2, 18, 18, $trans);
 my $test_num;
 
 if (!i_has_format("tiff")) {
-  for (1..33) {
+  for (1..43) {
     print "ok $_ # skip no tiff support\n";
   }
 } else {
@@ -188,6 +188,22 @@ if (!i_has_format("tiff")) {
   my $bad = Imager->new;
   ok($bad->read(file=>'testimg/comp4bad.tif'), "bad image not returned");
   ok(scalar $bad->tags(name=>'i_incomplete'), "incomplete tag not set");
+  ok($img8->write(file=>'testout/t106_pal8.tif'), "writing 8-bit paletted");
+  ok(my $cmp8 = Imager->new->read(file=>'testout/t106pal8.tif'),
+     "reading 8-bit paletted");
+  ok($cmp8->type eq 'paletted', "pal8 isn't paletted");
+  ok($cmp8->colorcount == 256, "pal8 bad colorcount");
+  $diff = i_img_diff($img8->{IMG}, $cmp8->{IMG});
+  print "# diff $diff\n";
+  ok($diff == 0, "written image doesn't match read");
+  ok($img4->write(file=>'testout/t106_pal4.tif'), "writing 4-bit paletted");
+  ok(my $cmp4 = Imager->new->read(file=>'testout/t106_pal4.tif'),
+     "reading 4-bit paletted");
+  ok($cmp4->type eq 'paletted', "pal4 isn't paletted");
+  ok($cmp4->colorcount == 16, "pal4 bad colorcount");
+  $diff = i_img_diff($img4->{IMG}, $cmp4->{IMG});
+  print "# diff $diff\n";
+  ok($diff == 0, "written image doesn't match read");
 }
 
 sub ok {
diff --git a/tiff.c b/tiff.c
index bd6d8cd024e2eb8554c841b595e1f8bdb50808e5..0535ab4d297ea72338acf48cb24de3fc2c26ecc6 100644 (file)
--- a/tiff.c
+++ b/tiff.c
@@ -65,6 +65,8 @@ static int save_tiff_tags(TIFF *tif, i_img *im);
 
 static void expand_4bit_hl(unsigned char *buf, int count);
 
+static void pack_4bit_hl(unsigned char *buf, int count);
+
 /*
 =item comp_seek(h, o, w)
 
@@ -384,6 +386,9 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
   TIFF* tif;
   int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
   double xres, yres;
+  uint16 bitspersample = 8;
+  uint16 samplesperpixel;
+  uint16 *colors = NULL;
 
   char *cc = mymalloc( 123 );
   myfree(cc);
@@ -400,6 +405,9 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
   case 3:
     photometric = PHOTOMETRIC_RGB;
     if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
+    else if (im->type == i_palette_type) {
+      photometric = PHOTOMETRIC_PALETTE;
+    }
     break;
   default:
     /* This means a colorspace we don't handle yet */
@@ -437,12 +445,60 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
   
   if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   ) { mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width)); return 0; }
   if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  ) { mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height)); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, channels)) { mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", channels)); return 0; }
   if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT)) { mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   8)        ) { mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=8\n")); return 0; }
   if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n")); return 0; }
   if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,   photometric)) { mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric)); return 0; }
   if (!TIFFSetField(tif, TIFFTAG_COMPRESSION,   compression)) { mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression)); return 0; }
+  samplesperpixel = channels;
+  if (photometric == PHOTOMETRIC_PALETTE) {
+    uint16 *out[3];
+    i_color c;
+    int count = i_colorcount(im);
+    int size;
+    int bits;
+    int ch, i;
+    
+    samplesperpixel = 1;
+    if (count > 16)
+      bitspersample = 8;
+    else
+      bitspersample = 4;
+    size = 1 << bitspersample;
+    colors = (uint16 *)_TIFFmalloc(sizeof(uint16) * 3 * size);
+    out[0] = colors;
+    out[1] = colors + size;
+    out[2] = colors + 2 * size;
+    
+    for (i = 0; i < count; ++i) {
+      i_getcolors(im, i, &c, 1);
+      for (ch = 0; ch < 3; ++ch)
+        out[ch][i] = c.channel[ch] * 257;
+    }
+    for (; i < size; ++i) {
+      for (ch = 0; ch < 3; ++ch)
+        out[ch][i] = 0;
+    }
+    if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) { 
+      mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n", 
+              bitspersample)); 
+      return 0;
+    }
+    if (!TIFFSetField(tif, TIFFTAG_COLORMAP, out[0], out[1], out[2])) {
+      mm_log((1, "i_writetiff_wiol: TIFFSetField colormap\n")); 
+      return 0;
+    }
+  }
+  else {
+    if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) { 
+      mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n", 
+              bitspersample)); 
+      return 0;
+    }
+  }
+  if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel)) { 
+    mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", samplesperpixel)); 
+    return 0;
+  }
 
   switch (compression) {
   case COMPRESSION_JPEG:
@@ -467,8 +523,12 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
   }
   
   linebytes = channels * width;
-  linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) > linebytes ?
-                                         linebytes : TIFFScanlineSize(tif) );
+  linebytes = TIFFScanlineSize(tif) > linebytes ? linebytes 
+    : TIFFScanlineSize(tif);
+  /* working space for the scanlines - we go from 8-bit/pixel to 4 */
+  if (photometric == PHOTOMETRIC_PALETTE && bitspersample == 4)
+    linebytes += linebytes + 1;
+  linebuf = (unsigned char *)_TIFFmalloc(linebytes);
   
   if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
     mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
@@ -528,19 +588,34 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
     return 0;
   }
 
-  for (y=0; y<height; y++) {
-    ci = 0;
-    for(x=0; x<width; x++) { 
-      (void) i_gpix(im, x, y,&val);
-      for(ch=0; ch<channels; ch++) linebuf[ci++] = val.channel[ch];
+  if (photometric == PHOTOMETRIC_PALETTE) {
+    for (y = 0; y < height; ++y) {
+      i_gpal(im, 0, width, y, linebuf);
+      if (bitspersample == 4)
+        pack_4bit_hl(linebuf, width);
+      if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
+        mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
+        break;
+      }
     }
-    if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
-      mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
-      break;
+  }
+  else {
+    for (y=0; y<height; y++) {
+      ci = 0;
+      for(x=0; x<width; x++) { 
+        (void) i_gpix(im, x, y,&val);
+        for(ch=0; ch<channels; ch++) 
+          linebuf[ci++] = val.channel[ch];
+      }
+      if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
+        mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
+        break;
+      }
     }
   }
   (void) TIFFClose(tif);
   if (linebuf) _TIFFfree(linebuf);
+  if (colors) _TIFFfree(colors);
   return 1;
 }
 
@@ -721,6 +796,13 @@ static void expand_4bit_hl(unsigned char *buf, int count) {
   }
 }
 
+static void pack_4bit_hl(unsigned char *buf, int count) {
+  int i;
+  while (i < count) {
+    buf[i/2] = (buf[i] << 4) + buf[i+1];
+    i += 2;
+  }
+}
 
 /*
 =back