changeset 4:bbd61622856a

Initial implementation of TIFF format read support via libtiff.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 07 Dec 2016 10:37:38 +0200
parents ffcd1967fb5c
children 524eae707ba4
files Makefile bpgenc.c
diffstat 2 files changed, 101 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Wed Dec 07 10:35:38 2016 +0200
+++ b/Makefile	Wed Dec 07 10:37:38 2016 +0200
@@ -48,9 +48,12 @@
 LIBJPEG_CFLAGS:=$(shell pkg-config --cflags libjpeg)
 LIBJPEG_LDFLAGS:=$(shell pkg-config --libs libjpeg)
 
+LIBTIFF_CFLAGS:=$(shell pkg-config --cflags libtiff-4)
+LIBTIFF_LDFLAGS:=$(shell pkg-config --libs libtiff-4)
+
 CFLAGS:=-Os -Wall -MMD -fno-asynchronous-unwind-tables -fdata-sections -ffunction-sections -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -fomit-frame-pointer
 CFLAGS+=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_REENTRANT
-CFLAGS+=-I. $(LIBSDL_CFLAGS) $(LIBPNG_CFLAGS) $(LIBJPEG_CFLAGS)
+CFLAGS+=-I. $(LIBSDL_CFLAGS) $(LIBPNG_CFLAGS) $(LIBJPEG_CFLAGS) $(LIBTIFF_CFLAGS)
 CFLAGS+=-DCONFIG_BPG_VERSION=\"$(shell cat VERSION)\"
 ifdef USE_JCTVC_HIGH_BIT_DEPTH
 CFLAGS+=-DRExt__HIGH_BIT_DEPTH_SUPPORT
@@ -190,7 +193,7 @@
 
 LIBS+=-lm -lpthread
 BPGDEC_LIBS:=$(LIBPNG_LDFLAGS) $(LIBS)
-BPGENC_LIBS+=$(LIBPNG_LDFLAGS) $(LIBJPEG_LDFLAGS) $(LIBS)
+BPGENC_LIBS+=$(LIBPNG_LDFLAGS) $(LIBJPEG_LDFLAGS) $(LIBTIFF_LDFLAGS) $(LIBS)
 BPGVIEW_LIBS:=$(LIBSDL_LDFLAGS) $(LIBS)
 
 endif #!CONFIG_WIN32
--- a/bpgenc.c	Wed Dec 07 10:35:38 2016 +0200
+++ b/bpgenc.c	Wed Dec 07 10:37:38 2016 +0200
@@ -31,6 +31,7 @@
 
 #include <png.h>
 #include <jpeglib.h>
+#include <tiffio.h>
 
 #include "bpgenc.h"
 
@@ -908,6 +909,93 @@
     }
 }
 
+Image *read_tiff(BPGMetaData **pmd, const char *filename,
+    BPGColorSpaceEnum color_space, int out_bit_depth,
+    int limited_range, int premultiplied_alpha)
+{
+    TIFF *tif;
+    Image *img = NULL;
+    BPGImageFormatEnum img_format;
+    uint8_t *buf = NULL;
+    uint32_t img_width, img_height;
+    int img_alpha, img_bpp;
+    size_t img_linesize;
+    uint16_t img_depth, img_spp, img_sfmt, img_pconfig;
+    ColorConvertState cvt;
+    RGBConvertFunc *convert_func;
+
+    *pmd = NULL;
+
+    // Open and read TIFF header etc.
+    if ((tif = TIFFOpen(filename, "rb")) == NULL)
+        return NULL;
+
+    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img_width);
+    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img_height);
+    TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &img_spp);
+    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &img_depth);
+    TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &img_sfmt);
+    TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &img_pconfig);
+
+    // Check basics
+    if ((img_depth != 8 && img_depth != 16) || img_spp > 4)
+        goto err;
+
+    img_linesize = TIFFScanlineSize(tif);
+    img_format = BPG_FORMAT_444;
+    img_bpp = sizeof(uint32_t) * img_depth / 8;
+
+    if (img_spp > 3)
+    {
+        uint16_t img_esmp, *img_esmp_types;
+
+        TIFFGetField(tif, TIFFTAG_EXTRASAMPLES, &img_esmp, &img_esmp_types);
+        img_alpha = img_esmp == 1 && img_esmp_types[0] == EXTRASAMPLE_UNASSALPHA;
+    }
+    else
+        img_alpha = 0;
+
+    // Allocate temporary image space
+    buf = (uint8_t *) _TIFFmalloc(img_linesize * img_spp);
+    if (buf == NULL)
+        goto err;
+
+    // Allocate target image
+    img = image_alloc(img_width, img_height, img_format, img_alpha, color_space, out_bit_depth);
+    if (img == NULL)
+        goto err;
+
+    img->limited_range = limited_range;
+    img->premultiplied_alpha = premultiplied_alpha;
+
+    convert_init(&cvt, img_depth, out_bit_depth, color_space, limited_range);
+
+    int idx = img_depth == 16;
+    convert_func = rgb_to_cs[idx][color_space];
+
+    for (int y = 0; y < img->h; y++)
+    {
+        // Read TIFF image to raster
+        if (!TIFFReadScanline(tif, buf, y, 0))
+            goto err;
+
+        // Convert
+        convert_func(&cvt,
+            (PIXEL *)(img->data[0] + y * img->linesize[0]),
+            (PIXEL *)(img->data[1] + y * img->linesize[1]),
+            (PIXEL *)(img->data[2] + y * img->linesize[2]),
+            buf, img->w, img_spp);
+    }
+
+
+err:
+    if (buf != NULL)
+        _TIFFfree(buf);
+
+    TIFFClose(tif);
+    return img;
+}
+
 Image *read_png(BPGMetaData **pmd,
                 FILE *f, BPGColorSpaceEnum color_space, int out_bit_depth,
                 int limited_range, int premultiplied_alpha)
@@ -1420,6 +1508,10 @@
     return img;
 }
 
+static const char PROBE_TIFF_MAGIC_LE[] = { 'I', 'I', 42, 0 };
+static const char PROBE_TIFF_MAGIC_BE[] = { 'M', 'M', 0, 42 };
+#define PROBE_BUF_SIZE 8
+
 Image *load_image(BPGMetaData **pmd, const char *infilename,
                   BPGColorSpaceEnum color_space, int bit_depth,
                   int limited_range, int premultiplied_alpha)
@@ -1442,6 +1534,10 @@
     if (png_sig_cmp(buf, 0, PROBE_BUF_SIZE) == 0)
         img = read_png(&md, f, color_space, bit_depth, limited_range, premultiplied_alpha);
     else
+    if (memcmp(buf, PROBE_TIFF_MAGIC_LE, sizeof(PROBE_TIFF_MAGIC_LE)) == 0 ||
+        memcmp(buf, PROBE_TIFF_MAGIC_BE, sizeof(PROBE_TIFF_MAGIC_BE)) == 0)
+        img = read_tiff(&md, infilename, color_space, bit_depth, limited_range, premultiplied_alpha);
+    else
         img = read_jpeg(&md, f, bit_depth);
 
 err: