使用 .NET 创建采用 JPEG 压缩的多页 TIFF

2024-04-19

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


你可以看看>> 这篇文章 https://stackoverflow.com/a/14877473/2060966,我在其中解释了如何将现有 JPEG 包装在简单的多页 TIFF 容器中。

但还有多种其他可能性。自由图像网 (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),无需更改其原始数据(因此您既不会降低质量,也不会增加其大小)。可能有一种更简单的方法(也许你找到了一个),但我使用了以下代码(基于这个例子 http://bitmiracle.com/libtiff/help/convert-bytes-of-a-multi-strip-tiff-image-to-bytes-of-a-single-strip-one.aspx):

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;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 .NET 创建采用 JPEG 压缩的多页 TIFF 的相关文章

随机推荐