c# - TIFF 如何有序地放置图像
问题描述
朋友们!我有一组小图像,需要在 Tiff 文件中布置为表格。
文件在最终文件中的样子: 我为此使用了 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();
}
提前致谢!
解决方案
首先让我们把你问题的 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 遍历该数组时,您将在同一行上的三个图像之间来回跳转,直到您完全到达下一行,接下来的 3 个图像来自该行行以相同的模式访问。
要实现这样的内存布局,您可以使用多种方法。
- TIFF 文件支持将大图像分解为大小相等的图块。这可用于通过使用 libTIFF 库将每个图像写入其自己的图块来实现您的要求。每个 TIFF 切片的尺寸必须是 16 的倍数,这是一个限制。
- 中的
Graphics
类System.Drawing
可用于制作一个大的空白图像,然后您可以将每个子图像绘制到任意位置的大图像中。(这是得到你想要的最简单的方法,但它可能很慢。) - 使用循环手动执行:
// 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];
}
}
}
推荐阅读
- cordova - Ionic 4 Cordova 相机插件没有打开原生图库,它打开了包括照片在内的所有文件
- c++ - 将 nullptr 设置为 const 变量时使用
- android - 有时滚动变得非常缓慢后,应用程序变慢
- shell - 如何从日志文件夹中仅在当前时间的 2 分钟内找到日志文件
- java - 错误:在类 singleInheritance.A 中找不到主方法,请将主方法定义为:public static void main(String[] args) 或 JavaFX
- abap - ALV 演示程序中缺少数据
- javascript - 如何使 css 仅影响 .js 中的列表项,而不影响我的 .html 中的列表项
- spring-boot - 如何在 Freemarker 中获取布尔变量 DEBUG?
- dns - Ubuntu 18.04 - 如何忽略离线 DNS 服务器?
- python-3.x - 计算真假