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