TIFF如何有序放置图像

时间:2019-07-03 20:08:00

标签: c# image image-processing tiff libtiff

朋友!我需要将一组小图像作为表格放置在Tiff文件中。

文件在最终文件中应如何显示: enter image description here 我为此使用LibTIFF库。 告诉我如何实施?我用C#实现了解决方案,但是语言无关紧要,因为重写解决方案不是问题。

        var Row = 10;
        var Column = 10;

        var PIXEL_WIDTH = 8810;
        var PIXEL_HEIGHT = 11810;
        //Each small image has a resolution of 881x1181
        using (Tiff tiff = Tiff.Open("big.tif", "w"))
        {
            tiff.SetField(TiffTag.IMAGEWIDTH, PIXEL_WIDTH);
            tiff.SetField(TiffTag.IMAGELENGTH, PIXEL_HEIGHT);
            tiff.SetField(TiffTag.COMPRESSION, Compression.LZW);
            tiff.SetField(TiffTag.PHOTOMETRIC, Photometric.RGB);
            tiff.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);
            tiff.SetField(TiffTag.ROWSPERSTRIP, PIXEL_HEIGHT);

            tiff.SetField(TiffTag.XRESOLUTION, 120);
            tiff.SetField(TiffTag.YRESOLUTION, 120);

            tiff.SetField(TiffTag.BITSPERSAMPLE, 8);
            tiff.SetField(TiffTag.SAMPLESPERPIXEL, 3);

            tiff.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);

            int tileC = 0;

            for (int row = 0; row < Row; row++)
            {
                for (int col = 0; col < Column; col++)
                {
                    Bitmap bitmap = new Bitmap($"{row}x{col}.png");
                    byte[] raster = getImageRasterBytes(bitmap, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                    tiff.WriteEncodedStrip(tileC++, raster, raster.Length);
                }
            }
            tiff.WriteDirectory();
        }

谢谢!

1 个答案:

答案 0 :(得分:0)

首先让我们把问题的TIFF部分放在一边。主要问题是,您需要弄清楚如何组织内存中的像素数据,然后才能将最终图像保存为任何图像类型。

我将提供自己的简单示例来说明如何组织像素数据。


假设我们要在3x3的表格中合并9张图像。
每个图像将为3x3像素和8位单声道(1通道)。
这使得该示例很好用,简单,每个图像有9个字节,每个图像的步幅为每行3个字节。 合并后的图像最终将为9x9像素,总共81个字节。

这些图像分别命名为A,B,C ... I
A0是A像素数据的字节0,A1是字节1,依此类推...

这些图像将像这样在3x3的表格中组织起来:

ABC
DEF
GHI

然后,最终数据布局应如下所示:

byte[] pixelData = [
    A0,A1,A2,B0,B1,B2,C0,C1,C2,
    A3,A4,A5,B3,B4,B5,C3,C4,C5,
    A6,A7,A8,B6,B7,B8,C6,C7,C8,
    D0,D1,D2,E0,E1,E2,F0,F1,F2,
    D3,D4,D5,E3,E4,E5,F3,F4,F5,
    D6,D7,D8,E6,E7,E8,F6,F7,F8,
    G0,G1,G2,H0,H1,H2,I0,I1,I2,
    G3,G4,G5,H3,H4,H5,I3,I4,I5,
    G6,G7,G8,H6,H7,H8,I6,I7,I8
];

然后可以将上面的像素阵列写入所需的任何图像文件。包括TIFF。

在上面的数组中的通知:
当您从索引0到80遍历该数组时,您将在同一行的三张图像之间来回跳转,直到完全到达下一行为止,在同一行中访问该行的下三张图像模式。


要实现这样的内存布局,可以使用几种方法。

  1. TIFF文件支持将大图像分解为相等大小的图块。通过使用libTIFF库将每个图像写入其自己的图块,可以用来满足您的要求。有一个限制,即每个TIFF磁贴的尺寸必须为16的倍数。
  2. Graphics中的System.Drawing类可用于制作一个大的空白图像,然后您可以在任意位置将每个子图像绘制到该大图像中。 (这是获得所需东西的最简单方法,但是可能很慢。)
  3. 手动执行循环:
// For the example I have given above, in pseudo C# code

int composite_stride = image_stride * 3; // 3 is the number of images per row
int composite_size = composite_stride * image_height * 3 // 3 is the number of images per column
byte[] composite_pixels = new byte[composite_size];

// Loop over each image you want to combine
// We need some way to know which row/column the image is from, let that be assigned to table_row and table_col
// We are also assuming all images have the same width and height
foreach (image in table)
{
    int comp_x = table_col * image.width;
    int comp_y = table_row * image.height;

    for (int y=0; y<image.height; y++)
    {
        // Calculate the array index that the current row starts at
        int comp_row_start = comp_y * composite_stride;

        for (int x=0; x<image.width; x++)
        {
            // Calculate the array index in the composite image to write to, and the source image index to copy from
            int comp_index = comp_row_start + ((comp_x + x) * image.bytes_per_pixel);
            int img_index = (y * image.stride) + (x * image.bytes_per_pixel);
            composite_pixels[pixel_index] = image.pixels[img_index];
        }
    }
}