0
votes

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.)

2

2 Answers

1
votes

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);
0
votes

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;
}