0

I am trying to write tiles on a multi-page tiff (pyramidal tiff) using LibTIFF:

for(int pageNum=0; pageNum<pageCount; pageNum++)
{
    // processing for getting tiles (decode and resize for each page)
    ////

    TIFFSetField(tiff_out, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE);
    TIFFSetField(tiff_out, TIFFTAG_PAGENUMBER, pageNum);
    //TIFFSetField(tiff_out, TIFFTAG_IMAGEWIDTH, imageWidth); // <- cannot be done with en error message(cannot change the value while processing)
    //TIFFSetField(tiff_out, TIFFTAG_IMAGELENGTH, imageHeight); // <- cannot be done with en error message(cannot change the value while processing)
    TIFFWriteEncodedTile(tiff_out, tileNumberOnPage, buff, -1);   
}

When I tried to write only single page, I worked fine. But when trying to do with multi-pages, the result shows overlapped images. It seemed that all pages are shown on the first page.

I checked the resulting TIFF file with the tiffinfo command. It shows that the page number is the last page number, but it only shows the information of the first page (i.e. it shows only one page).

Is there other setting for writing tiles on multi-page, pyramidal TIFF?

(I also tried setting FILETYPE_PAGE as TIFFTAG_SUBFILETYPE.)

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
YJJ
  • 45
  • 10

2 Answers2

1

To create mutliple pages (directories) in the TIFF file, use the TIFFWriteDirectory function. It will write the tags and data as specified up to that point to the current directory, and start a new one. TIFFClose writes the tags and data to the current directory and closes the file.

Thus, to create a file with two directories, you first create a new file, set tags and write tiles, call TIFFWriteDirectory, set tags and write tiles, and call TIFFClose.

For example, you could modify your code to be:

for(int pageNum=0; pageNum<pageCount; pageNum++)
{
    // processing for getting tiles (decode and resize for each page)
    if(pageNum>0) {
        TIFFWriteDirectory(tiff_out);
    }
    TIFFSetField(tiff_out, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE);
    TIFFSetField(tiff_out, TIFFTAG_IMAGEWIDTH, imageWidth);
    TIFFSetField(tiff_out, TIFFTAG_IMAGELENGTH, imageHeight);
    TIFFWriteEncodedTile(tiff_out, tileNumberOnPage, buff, -1);   
}
TIFFClose(tiff_out);
Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • That worked like a charm. Thanks @Cris Luengo. Could I also ask you how to change dpi with libtiff? I set "TIFFTAG_RESOLUTIONUNIT" and "TIFFTAG_XRESOLUTION", but the result on tiffinfo is "Resolution: 0, 0 pixels/inch". whatever values I set for the XRESOLUTION and YRESOLUTION, it doesn't change the value, always showing (0,0). – YJJ Jan 09 '19 at 02:34
  • @YJJ: yes, the LibTIFF API is like that. You need to pass values of the correct type, if you pass an int, its bit sequence will be interpreted as a double or a float or whatever. Not a type-safe interface. You need to read the docs for each tag that you set (or read). – Cris Luengo Jan 09 '19 at 02:54
0

I found this version https://www.asmail.be/msg0055065771.html the most helpful. One warning, make sure to use declared uint16 for spp, bpp, photo, and res_unit, uint32 for width and height, and float for xres and yres. Otherwise the va_args won't get the correct values for your tiff file.

I also found helpful TIFFTAG_SOFTWARE and TIFFTAG_DATETIME which are strings, but is not included in the example below.

I also changed the original for TIFFTAG_IMAGEWIDTH from image_width / spp to just image_width, which was not correct for my color image (3).

#include <stdio.h>
#include "tiffio.h"

#define XSIZE 256
#define YSIZE 256
#define NPAGES 10

int main (int argc, char **argv)
{
    uint32 image_width, image_height;
    float xres, yres;
    uint16 spp, bpp, photo, res_unit;
    TIFF *out;
    int i, j;
    uint16 page;

    unsigned char array[XSIZE * YSIZE];

    for (j = 0; j < YSIZE; j++)
            for(i = 0; i < XSIZE; i++)
                    array[j * XSIZE + i] = (unsigned char)(i * j);

    out = TIFFOpen("out.tif", "w");
    if (!out)
    {
            fprintf (stderr, "Can't open %s for writing\n", argv[1]);
            return 1;
    }
    image_width = XSIZE;
    image_height = YSIZE;
    spp = 1; /* Samples per pixel */
    bpp = 8; /* Bits per sample */
    photo = PHOTOMETRIC_MINISBLACK;

    for (page = 0; page < NPAGES; page++)
    {
        TIFFSetField(out, TIFFTAG_IMAGEWIDTH, image_width);
        TIFFSetField(out, TIFFTAG_IMAGELENGTH, image_height);
        TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bpp);
        TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, spp);
        TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
        TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photo);
        TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
        /* It is good to set resolutions too (but it is not nesessary) */
        xres = yres = 100;
        res_unit = RESUNIT_INCH;
        TIFFSetField(out, TIFFTAG_XRESOLUTION, xres);
        TIFFSetField(out, TIFFTAG_YRESOLUTION, yres);
        TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, res_unit);

        /* We are writing single page of the multipage file */
        TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
        /* Set the page number */
        TIFFSetField(out, TIFFTAG_PAGENUMBER, page, NPAGES);

        for (j = 0; j < image_height; j++)
            TIFFWriteScanline(out, &array[j * image_width], j, 0);

        TIFFWriteDirectory(out);
    }

    TIFFClose(out);

    return 0;
}
codeDr
  • 1,535
  • 17
  • 20