4

.NETを使用してJPEG圧縮でマルチページTIFFを作成する方法はありますか?LZW圧縮でTIFFを作成できますが、ファイルは非常に大きくなります。列挙EncoderValue型(圧縮を設定するために使用)には適切なメンバーさえないようです。

4

1 に答える 1

6

>>この投稿ご覧ください。ここでは、既存の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を作成するのは、もう少し注意が必要です。私の知る限り、複数ページの編集はハードドライブでのみ可能です。(ただし、新しいバージョンには別の方法があると聞いているので、少し試してみてください。)ただし、次のようにsthを使用できます。

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)とマージする簡単な方法を見つけました(したがって、品質を低下させたり、サイズを大きくしたりすることはありません)。もっと簡単な方法があるかもしれませんが(たぶんあなたはそれを見つけるでしょう)、私は次のコードを使用しました(この例に基づいています):

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;
    }
}
于 2013-02-15T13:45:57.973 に答える