Logo Search packages:      
Sourcecode: fbi version File versions  Download package

read-tiff.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <tiffio.h>

#include "readers.h"

struct tiff_state {
    TIFF*          tif;
    char           emsg[1024];
    tdir_t         ndirs;     /* Number of directories                     */
                              /* (could be interpreted as number of pages) */
    uint32         width,height;
    uint16         config,nsamples,depth,fillorder,photometric;
    uint32*        row;
    uint32*        image;
    uint16         resunit;
    float          xres,yres;
};

static void*
tiff_init(FILE *fp, char *filename, unsigned int page,
        struct ida_image_info *i, int thumbnail)
{
    struct tiff_state *h;

    fclose(fp);
    h = malloc(sizeof(*h));
    memset(h,0,sizeof(*h));

    TIFFSetWarningHandler(NULL);
    h->tif = TIFFOpen(filename,"r");
    if (NULL == h->tif)
      goto oops;
    /* Determine number of directories */
    h->ndirs = 1;
    while (TIFFReadDirectory(h->tif))
        h->ndirs++;
    i->npages = h->ndirs;
    /* Select requested directory (page) */
    if (!TIFFSetDirectory(h->tif, (tdir_t)page))
        goto oops;
    
    TIFFGetField(h->tif, TIFFTAG_IMAGEWIDTH,      &h->width);
    TIFFGetField(h->tif, TIFFTAG_IMAGELENGTH,     &h->height);
    TIFFGetField(h->tif, TIFFTAG_PLANARCONFIG,    &h->config);
    TIFFGetField(h->tif, TIFFTAG_SAMPLESPERPIXEL, &h->nsamples);
    TIFFGetField(h->tif, TIFFTAG_BITSPERSAMPLE,   &h->depth);
    TIFFGetField(h->tif, TIFFTAG_FILLORDER,       &h->fillorder);
    TIFFGetField(h->tif, TIFFTAG_PHOTOMETRIC,     &h->photometric);
    h->row = malloc(TIFFScanlineSize(h->tif));
    if (debug)
      fprintf(stderr,"tiff: %" PRId32 "x%" PRId32 ", planar=%d, "
            "nsamples=%d, depth=%d fo=%d pm=%d scanline=%" PRId32 "\n",
            h->width,h->height,h->config,h->nsamples,h->depth,
            h->fillorder,h->photometric,
            TIFFScanlineSize(h->tif));

    if (PHOTOMETRIC_PALETTE   == h->photometric  ||
      PHOTOMETRIC_YCBCR     == h->photometric  ||
      PHOTOMETRIC_SEPARATED == h->photometric  ||
      TIFFIsTiled(h->tif)                      ||
      (1 != h->depth  &&  8 != h->depth)) {
      /* for the more difficuilt cases we let libtiff
       * do all the hard work.  Drawback is that we lose
       * progressive loading and decode everything here */
      if (debug)
          fprintf(stderr,"tiff: reading whole image [TIFFReadRGBAImage]\n");
      h->image=malloc(4*h->width*h->height);
      TIFFReadRGBAImage(h->tif, h->width, h->height, h->image, 0);
    } else {
      if (debug)
          fprintf(stderr,"tiff: reading scanline by scanline\n");
      h->row = malloc(TIFFScanlineSize(h->tif));
    }

    i->width  = h->width;
    i->height = h->height;

    if (TIFFGetField(h->tif, TIFFTAG_RESOLUTIONUNIT,  &h->resunit) &&
      TIFFGetField(h->tif, TIFFTAG_XRESOLUTION,     &h->xres)    &&
      TIFFGetField(h->tif, TIFFTAG_YRESOLUTION,     &h->yres)) {
      switch (h->resunit) {
      case RESUNIT_NONE:
          break;
      case RESUNIT_INCH:
          i->dpi = h->xres;
          break;
      case RESUNIT_CENTIMETER:
          i->dpi = res_cm_to_inch(h->xres);
          break;
      }
    }

    return h;

 oops:
    if (h->tif)
      TIFFClose(h->tif);
    free(h);
    return NULL;
}

static void
tiff_read(unsigned char *dst, unsigned int line, void *data)
{
    struct tiff_state *h = data;
    int s,on,off;

    if (h->image) {
      /* loaded whole image using TIFFReadRGBAImage() */
      uint32 *row = h->image + h->width * (h->height - line -1);
      load_rgba(dst,(unsigned char*)row,h->width);
      return;
    }
    
    if (h->config == PLANARCONFIG_CONTIG) {
      TIFFReadScanline(h->tif, h->row, line, 0);
    } else if (h->config == PLANARCONFIG_SEPARATE) {
      for (s = 0; s < h->nsamples; s++)
          TIFFReadScanline(h->tif, h->row, line, s);
    }

    switch (h->nsamples) {
    case 1:
      if (1 == h->depth) {
          /* black/white */
          on = 0, off = 0;
          if (PHOTOMETRIC_MINISWHITE == h->photometric)
            on = 0, off = 255;
          if (PHOTOMETRIC_MINISBLACK == h->photometric)
            on = 255, off = 0;
#if 0
          /* Huh?  Does TIFFReadScanline handle this already ??? */
          if (FILLORDER_MSB2LSB == h->fillorder)
            load_bits_msb(dst,(unsigned char*)(h->row),h->width,on,off);
          else
            load_bits_lsb(dst,(unsigned char*)(h->row),h->width,on,off);
#else
          load_bits_msb(dst,(unsigned char*)(h->row),h->width,on,off);
#endif
      } else {
          /* grayscaled */
          load_gray(dst,(unsigned char*)(h->row),h->width);
      }
      break;
    case 3:
      /* rgb */
      memcpy(dst,h->row,3*h->width);
      break;
    case 4:
      /* rgb+alpha */
      load_rgba(dst,(unsigned char*)(h->row),h->width);
      break;
    }
}

static void
tiff_done(void *data)
{
    struct tiff_state *h = data;

    TIFFClose(h->tif);
    if (h->row)
      free(h->row);
    if (h->image)
      free(h->image);
    free(h);
}

static struct ida_loader tiff1_loader = {
    magic: "MM\x00\x2a",
    moff:  0,
    mlen:  4,
    name:  "libtiff",
    init:  tiff_init,
    read:  tiff_read,
    done:  tiff_done,
};
static struct ida_loader tiff2_loader = {
    magic: "II\x2a\x00",
    moff:  0,
    mlen:  4,
    name:  "libtiff",
    init:  tiff_init,
    read:  tiff_read,
    done:  tiff_done,
};

static void __init init_rd(void)
{
    load_register(&tiff1_loader);
    load_register(&tiff2_loader);
}

Generated by  Doxygen 1.6.0   Back to index