【问题标题】:How to read all tiles from TIFF image using LibTiff.Net?如何使用 LibTiff.Net 从 TIFF 图像中读取所有图块?
【发布时间】:2017-11-17 11:44:22
【问题描述】:

我是 TIFF 和 LibTiff.Net 的新手,我想读取平铺的 TIFF 文件并将其写入其他 TIFF 文件。我怎样才能做到这一点? Tiff 文件上的任何材料也将非常有帮助。 提前致谢。

【问题讨论】:

    标签: libtiff.net


    【解决方案1】:

    此代码将迭代 tiff 图像中的图块,然后是图块中的行。生成的数据存储在data 字节数组中——您可以从中创建bitmapsource。以下代码适用于 16 位、8 位、1 位灰度 tiff 图像。

    _tiff = Tiff.Open(filepath, "r");
    
    var data = new byte[header.ImageWidth * header.ImageHeight];
    var buffer = new byte[_tiff.TileSize()];        
    
    for (var row = 0; row < header.ImageHeight; row += header.TileHeight)
    {
        for (var col = 0; col < header.ImageWidth; col += header.TileWidth)
        {
            // Read the tile
            if (_tiff.ReadTile(buffer, 0, col, row, 0, 0) < 0)
            {
                throw new Exception("Error reading data");
            }
    
            var index = 0;
    
            // Iterate the rows in the tile
            for (var i = 0; i < header.TileHeight && i + row < header.ImageHeight; i++)
            {
                var length = header.TileWidth;
    
                // Index of the first position in the row
                var position = (row + i) * data.Width + col;
    
                // Check we are not outside the image
                if (col + length > header.ImageWidth)
                {
                    length = header.ImageWidth - col;
                }
    
                switch (header.BitsPerPixel)
                {
                    case 1:
                    {
                        for (var p = 0; p < (length + 7) / 8; p++)
                        {
                            // Unpack the pixels
                            for (var b = 0; b < 8; b++)
                            {
                                data[position + p * 8 + (7 - b)] = (buffer[index / 8 + p] & (1 << b)) != 0 ? byte.MaxValue : byte.MinValue;
                            }
                        }
    
                        break;
                    }
                    case 8:
                    {
                        for (var p = 0; p < length; p++)
                        {
                            data[position + p] = buffer[index + p];
                        }
    
                        break;
                    }
                    case 16:
                    {
                        for (var p = 0; p < length; p++)
                        {
                            data[position + p] = buffer[index * 2 + p * 2];
                        }
    
                        break;
                    }
                    default:
                    {
                        throw new NotImplementedException();
                    }
                }
    
                index += header.TileWidth;
            }
        }
    }
    

    您可以像这样读取 tiff 标头:

    public class TaggedImageHeader
    {
        public int BitsPerPixel { get; private set; }
        public int Components { get; private set; }
        public string Compression { get; private set; }
        public int ImageHeight { get; private set; }
        public int ImageWidth { get; private set; }
        public string PlanarConfig { get; private set; }
        public int TileHeight { get; private set; }
        public int TileWidth { get; private set; }
    
        internal static TaggedImageHeader Read(Tiff tiff)
        {
            var imageWidth = tiff.GetField(TiffTag.IMAGEWIDTH);
            var imageHeight = tiff.GetField(TiffTag.IMAGELENGTH);
            var bitsPerPixel = tiff.GetField(TiffTag.BITSPERSAMPLE);
            var components = tiff.GetField(TiffTag.SAMPLESPERPIXEL);
            var tileWidth = tiff.GetField(TiffTag.TILEWIDTH);
            var tileHeight = tiff.GetField(TiffTag.TILELENGTH);
            var compression = tiff.GetField(TiffTag.COMPRESSION);
            var planarConfig = tiff.GetField(TiffTag.PLANARCONFIG);
    
            return new TaggedImageHeader
            {
                ImageWidth = imageWidth?[0].ToInt() ?? 0,
                ImageHeight = imageHeight?[0].ToInt() ?? 0,
                BitsPerPixel = bitsPerPixel?[0].ToInt() ?? 0,
                Components = components?[0].ToInt() ?? 0,
                TileWidth = tileWidth?[0].ToInt() ?? 0,
                TileHeight = tileHeight?[0].ToInt() ?? 0,
                Compression = compression?[0].ToString() ?? "",
                PlanarConfig = planarConfig?[0].ToString() ?? ""
            };
        }
    }
    

    如果您在阅读标题之前使用金字塔之类的 tiff 文件,请确保致电 _tiff.SetFrame(frame)

    您可以通过用下面的代码替换数据数组来直接写入WriteableBitmap 后台缓冲区。这将删除不必要的副本。

    var data = new UnsafeBuffer((byte*)bitmap.BackBuffer, bitmap.BackBufferStride, bitmap.PixelHeight); 
    

    不安全缓冲区:

    public unsafe class UnsafeBuffer : Buffer
    {
        private readonly byte* _data;
    
        public UnsafeBuffer(byte* data, int x, int y) : base(x, y)
        {
            _data = data;
        }
    
        public override byte this[int x, int y]
        {
            get => this[y * Width + x];
            set => this[y * Width + x] = value;
        }
    
        public override byte this[int index]
        {
            get => _data[index];
            set => _data[index] = value;
        }
    }
    
    public abstract class Buffer
    {
        protected Buffer(int width, int height)
        {
            Width = width;
            Height = height;
        }
    
        public int Height { get; private set; }
        public int Length => Width * Height;
        public int Width { get; private set; }
    
        public abstract byte this[int x, int y] { get; set; }
    
        public abstract byte this[int index] { get; set; }
    }
    

    一个有用的资源是documentation ,其中包含样本。我还发现这个link 对我开始很有帮助。

    【讨论】:

    • 有趣。我想知道我怎么能在java中做到这一点。太悲伤的文档无法访问...
    • 行 var position = (row + i) * data.Width + col; 出现错误数组中不存在宽度信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-06
    相关资源
    最近更新 更多