使用JPEG压缩.NET创建多页Tiff

时间:2013-02-11 14:36:42

标签: .net jpeg gdi+ tiff

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

1 个答案:

答案 0 :(得分:6)

您可以查看 >> 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;
    }
}