Skip to content

Writing a tiled TIFF image with multipages and subIFDs #127

@LionelArn2

Description

@LionelArn2

Hi :)

I've been trying out libtiff.net and it's been working great so far.

I would like to write a tiled TIFF image with multiples pages and subIFDs, are SubIFDs writing supported? I haven't found any such example online, and all my attempts resulted in a corrupted output file where the first 4 bytes do not correspond to a tiff file.

Here's the code I'm working with, could you point me towards anything wrong?

static void Main()
{
    const string path = @"path\to\output\file.tiff";
    const int tileSize = 256;

    using Tiff tiffFile = Tiff.Open(path, "w");

    // Base IFD (full resolution)
    int baseW = 1024;
    int baseH = 1024;
    SetCommonTags(tiffFile, baseW, baseH, tileSize);
    tiffFile.SetField(TiffTag.SUBFILETYPE, FileType.PAGE);

    int subCount = 2;
    int[] subOffsets = new int[subCount]; // placeholders (all zeros)
    tiffFile.SetField(TiffTag.SUBIFD, (short)subCount, subOffsets);

    WriteAllBlackTiles(tiffFile, baseW, baseH, tileSize);
    tiffFile.WriteDirectory();

    // SubIDFs (reduced resolutions)
    int w2 = baseW, h2 = baseH;
    for (int i = 0; i < subCount; i++)
    {
        // next reduced size
        w2 = Math.Max(1, w2 / 2);
        h2 = Math.Max(1, h2 / 2);

        tiffFile.CreateDirectory();

        SetCommonTags(tiffFile, w2, h2, tileSize);
        tiffFile.SetField(TiffTag.SUBFILETYPE, FileType.REDUCEDIMAGE);

        WriteAllBlackTiles(tiffFile, w2, h2, tileSize);
        tiffFile.WriteDirectory();
    }
}

static void SetCommonTags(Tiff t, int width, int height, int tile)
{
    t.SetField(TiffTag.IMAGEWIDTH, width);
    t.SetField(TiffTag.IMAGELENGTH, height);
    t.SetField(TiffTag.SAMPLESPERPIXEL, 1);
    t.SetField(TiffTag.BITSPERSAMPLE, 8);
    t.SetField(TiffTag.SAMPLEFORMAT, SampleFormat.UINT);
    t.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
    t.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
    t.SetField(TiffTag.COMPRESSION, Compression.LZW);
    t.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);

    // tiled layout
    t.SetField(TiffTag.TILEWIDTH, tile);
    t.SetField(TiffTag.TILELENGTH, tile);

    // (optional) resolution metadata
    t.SetField(TiffTag.XRESOLUTION, 72.0);
    t.SetField(TiffTag.YRESOLUTION, 72.0);
    t.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);

}

static void WriteAllBlackTiles(Tiff t, int width, int height, int tile)
{
    // 8-bit black tile
    byte[] buf = new byte[tile * tile];

    for (int y = 0; y < height; y += tile)
    {
        for (int x = 0; x < width; x += tile)
        {
            int tileIndex = t.ComputeTile(x, y, 0, 0);
            int written = t.WriteEncodedTile(tileIndex, buf, buf.Length);
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions