【问题标题】:Create multipage TIFF with JPEG compression using .NET使用 .NET 使用 JPEG 压缩创建多页 TIFF
【发布时间】:2013-01-26 16:18:23
【问题描述】:

有没有什么方法可以使用 .NET 创建带有 JPEG 压缩的多页 TIFF? 我可以使用 LZW 压缩创建 TIFF,但文件非常大。看起来EncoderValue 枚举(我用来设置压缩)甚至没有合适的成员。

【问题讨论】:

    标签: .net jpeg gdi+ tiff


    【解决方案1】:

    您可以查看 >> this post,我在其中解释了如何将现有 JPEG 包装到一个简单的多页 TIFF 容器中。

    但是还有很多其他的可能性。 FreeImage.Net (freeimage.sourceforge.net) 是一个非常强大的库。您可以像这样创建一个简单的 JPEG 压缩 TIFF:

    using FreeImageAPI;
    // [...]
    FIBITMAP image = FreeImage.Load(FREE_IMAGE_FORMAT.FIF_UNKNOWN, "filename", FREE_IMAGE_LOAD_FLAGS.DEFAULT);
    FreeImage.Save(FREE_IMAGE_FORMAT.FIF_TIFF, image, "filename", FREE_IMAGE_SAVE_FLAGS.TIFF_JPEG)
    

    创建多页 TIFF 有点棘手。据我所知,多页编辑只能在硬盘上进行。 (不过我听说在较新的版本中还有另一种方法,所以也许可以尝试一下。)但是,您可以这样使用:

    using System.IO;
    using FreeImageAPI;
    
    // [...]
    
    public byte[] MergeTiffs(List<byte[]> tiffs)
    {
        byte[] multiPageTiff = null;
        string tmpfile = "... chose any file name ...";
        MemoryStream singleStream = null;
        FIBITMAP fib = FIBITMAP.Zero;
        FIMULTIBITMAP fmb = FIMULTIBITMAP.Zero;
    
        using (singleStream = new MemoryStream(tiffs[0])
        {
            fib = FreeImage.LoadFromStream(singleStream);
            FreeImage.SaveEx(fib, dateiname, FREE_IMAGE_FORMAT.FIF_TIFF, FREE_IMAGE_SAVE_FLAGS.TIFF_JPEG);
            FreeImage.UnloadEx(ref fib);
        }
    
        fmb = FreeImage.OpenMultiBitmap(
            FREE_IMAGE_FORMAT.FIF_TIFF,
            tmpfile,
            false,
            false,
            false,
            FREE_IMAGE_LOAD_FLAGS.TIFF_JPEG);
    
        for (int i = 1; i < tiffs.Count; i++)
        {
            using (singleStream = new MemoryStream(tiffs[i])
            {
                fib = FreeImage.LoadFromStream(singleStream);
                FreeImage.AppendPage(fmb, fib);
            }
        }
    
        FreeImage.CloseMultiBitmapEx(ref fmb);
        multiPageTiff = File.ReadAllBytes(tmpfile);
        File.Delete(tmpfile);
    
        return file;
    }
    

    除此之外,我最近发现了一种简单的方法,可以将现有的 TIFF 与 LibTiff.Net (bitmiracle.com) 合并,而无需更改其原始数据(因此您既失去质量也不会增加它们的尺寸)。可能有更简单的方法(也许你找到了),但我使用了以下代码(基于this example):

    using System.IO
    using BitMiracle.LibTiff.Classic;
    
    // [...]
    
    /// <summary>
    /// Merges multiple TIFFs into one multi-page TIFF
    /// </summary>
    /// <param name="tiffs">The TIFFs' raw data (can also be multi-page)</param>
    /// <returns></returns>
    public static byte[] MergeTiffs(List<byte[]> tiffs)
    {
        // the byteStream will contain the merged tiff's raw data
        MemoryStream byteStream = new MemoryStream();
        // create the output-TIFF (empty stream)
        using (Tiff output = Tiff.ClientOpen("InMemory", "w", byteStream, new TiffStream()))
        {
            for (short i = 0; i < tiffs.Count; i++)
            {
                // provide input-TIFF as custom TiffStream, with byteStream (output-TIFF) as output
                TiffStreamForBytes tiffStream = new TiffStreamForBytes(tiffs[i]);
                using (Tiff input = Tiff.ClientOpen("bytes", "r", null, tiffStream))
                {
                    // *** now copy all the TIFF-data: ***
    
                    // copy all directories (= all pages)
                    int numberOfDirectories = input.NumberOfDirectories();
                    for (short d = 0; d < numberOfDirectories; ++d)
                    {
                        // set this as the current directory (to work in)
                        input.SetDirectory(d);
    
                        // copy all tags
                        for (ushort t = ushort.MinValue; t < ushort.MaxValue; ++t)
                        {
                            TiffTag tag = (TiffTag)t;
                            FieldValue[] tagValue = input.GetField(tag);
                            if (tagValue != null)
                                output.GetTagMethods().SetField(output, tag, tagValue);
                        }
    
                        // copy all strips
                        int numberOfStrips = input.NumberOfStrips();
                        int stripSize = input.StripSize();
                        for (int s = 0; s < numberOfStrips; ++s)
                        {
                            // buffer for the current strip
                            byte[] stripData = new byte[stripSize];
                            // read strip from input image (not decompressed)
                            int length = input.ReadRawStrip(s, stripData, 0, stripData.Length);
                            // write strip to output image (uncompressed)
                            output.WriteRawStrip(s, stripData, 0, length);
                        }
    
                        // add the new directory to output image
                        output.WriteDirectory();
                    }
                }
            }
        }
        // return the new TIFF as byte array
        return byteStream.ToArray();
    }
    
    /// <summary>
    /// Custom read-only stream for byte buffer that can be used
    /// with Tiff.ClientOpen method.
    /// </summary>
    private class TiffStreamForBytes : TiffStream
    {
        private byte[] m_bytes;
        private int m_position;
    
        public TiffStreamForBytes(byte[] bytes)
        {
            m_bytes = bytes;
            m_position = 0;
        }
    
        public override int Read(object clientData, byte[] buffer, int offset, int count)
        {
            if ((m_position + count) > m_bytes.Length)
                return -1;
    
            Buffer.BlockCopy(m_bytes, m_position, buffer, offset, count);
            m_position += count;
            return count;
        }
    
        public override void Write(object clientData, byte[] buffer, int offset, int count)
        {
            throw new InvalidOperationException("This stream is read-only");
        }
    
        public override long Seek(object clientData, long offset, SeekOrigin origin)
        {
            switch (origin)
            {
                case SeekOrigin.Begin:
                    if (offset > m_bytes.Length)
                        return -1;
    
                    m_position = (int)offset;
                    return m_position;
    
                case SeekOrigin.Current:
                    if ((offset + m_position) > m_bytes.Length)
                        return -1;
    
                    m_position += (int)offset;
                    return m_position;
    
                case SeekOrigin.End:
                    if ((m_bytes.Length - offset) < 0)
                        return -1;
    
                    m_position = (int)(m_bytes.Length - offset);
                    return m_position;
            }
    
            return -1;
        }
    
        public override void Close(object clientData)
        {
            // nothing to do
        }
    
        public override long Size(object clientData)
        {
            return m_bytes.Length;
        }
    }
    

    【讨论】:

    • 非常感谢!我对 LibTiff.NET 很满意 :)
    • @QuéPadre 不客气。如果您喜欢它,请投票/选择它作为您选择的答案。谢谢。
    • 看来我太“年轻”了:)
    猜你喜欢
    • 2015-02-23
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 2017-01-16
    • 2011-08-09
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    相关资源
    最近更新 更多