Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用JPEG压缩的TIFF比原始JPEG大得多_C#_Image Processing_Jpeg_Tiff_Freeimage - Fatal编程技术网

C# 使用JPEG压缩的TIFF比原始JPEG大得多

C# 使用JPEG压缩的TIFF比原始JPEG大得多,c#,image-processing,jpeg,tiff,freeimage,C#,Image Processing,Jpeg,Tiff,Freeimage,我正在尝试使用FreeImage.Net和C#将JPEG压缩转换为TIFF。但是,对于低质量的JPGE,TIFF文件比原始文件大很多。我假设TIFF大小不取决于原始JPEG质量,因为输出图像的大小总是相同的 例如(转换屏幕截图): 这种规模的增加对我们公司来说是不可接受的,因为我们的客户和我们正在处理相当多的文件 有趣的是,当我用GIMP转换图像时,我得到了大致相同的结果。现在我想知道:这是根据TIFF标准还是专门针对FreeImage/GIMP的?(我认为两者都使用libtiff.dll) 我

我正在尝试使用FreeImage.Net和C#将JPEG压缩转换为TIFF。但是,对于低质量的JPGE,TIFF文件比原始文件大很多。我假设TIFF大小不取决于原始JPEG质量,因为输出图像的大小总是相同的

例如(转换屏幕截图):

这种规模的增加对我们公司来说是不可接受的,因为我们的客户和我们正在处理相当多的文件

有趣的是,当我用GIMP转换图像时,我得到了大致相同的结果。现在我想知道:这是根据TIFF标准还是专门针对FreeImage/GIMP的?(我认为两者都使用libtiff.dll)

我想还有另一种方法,因为我们公司有一台扫描仪,它可以生成尺寸小得多的JPEG压缩TIFF图像是否有人知道另一个库(免费或非免费)可以更有效地处理此转换,或在FreeImage中实现此转换

更新:

我看了一下,分析了扫描仪生成的文件,并能够编写一个函数,将JPEG包装到一个非常简单的TIFF容器中(也适用于合并到多页TIFF的多个JPEG)

对于那些对TIFF稍有了解的人:我制作了一个新的TIFF文件(根据图像/页面的数量,带有一个或多个IFD),并使用以下字段/条目将现有JPEG图像的原始数据写入一个条带(每个IFD):

NewSubfileType = 0
ImageWidth = //(width of the original JPEG)
ImageLength = //(height of the original JPEG)
BitsPerSample = {8, 8, 8} //(count: 3)
Compression = 7 //(JPEG)
PhotometricInterpretation = 6 //(YCbCr)
StripOffsets = //(offset of raw JPEG data, count: 1)
SamplesPerPixel = 3
RowsPerStrip = //(height of the original JPEG)
StripByteCounts = //(length of raw JPEG data, count: 1)
XResolution = //(horizontal resolution of original JPEG data)
YResolution = //(vertical resolution of original JPEG data)
PlanarConfiguration = 1 (chunky)
ResolutionUnit = 2 //(Inch)
(为了获得原始图像的信息,我使用了FreeImage,但任何其他图像库也应该可以使用。)

我知道有些陷阱我还不知道。它可能不适用于任何JPEG文件。另外,我不确定为什么我必须使用
photommetricinterpretation=6
PlanarConfiguration=1
或其他一些字段的值。然而,它是有效的

我想其他库的问题是,它们生成了一个质量始终相同的全新JPEG(因为您只能将TIFF压缩设置为JPEG,但不能指定任何其他选项),并将其包装到TIFF容器中


我现在也知道,在TIFF中使用JPEG压缩并不是最好的选择(它是有损的、不常见的,而且很少受到支持,除了JPEG压缩的TIFF之外,没有比普通JPEG文件更好的了)。然而,我们的客户要求这样做。让我们看看上面的方法是否合适,或者我是否找到了其他方法。

JPEG压缩不太受支持。如果库中确实包含此压缩类型,则设置(如JPEG质量)通常是固定的,并且原始图像最有可能被重新压缩。然而,我找到了一种方法,将原始JPEG包装在一个简单的TIFF容器中(->请参阅我原始问题中的更新)

记住:这可能不适用于任何JPEG文件例如,FreeImage无法读取包装的渐进式JPEG

这是我使用的C代码:

using System;
using System.Collections.Generic;
using System.IO;
using FreeImageAPI;

namespace Tiff
{
    static class TiffConverter
    {
        /// <summary>
        /// <para>Wraps a list of JPEG images into a simple multi-page TIFF container.</para>
        /// <para>(Might not work with all JPEG formats.)</para>
        /// </summary>
        /// <param name="jpegs">The JPEG-image to convert</param>
        /// <returns></returns>
        public static byte[] WrapJpegs(List<byte[]> jpegs)
        {
            if (jpegs == null || jpegs.Count == 0 || jpegs.FindIndex(b => b.Length == 0) > -1)
                throw new ArgumentNullException("Image data must not be null or empty");

            MemoryStream tiffData = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(tiffData);
            uint offset = 8; // size of header, offset to IFD
            ushort entryCount = 14; // entries per IFD

            #region IFH - Image file header

            // magic number
            if (BitConverter.IsLittleEndian)
                writer.Write(0x002A4949);
            else
                writer.Write(0x4D4D002A);

            // offset to (first) IFD
            writer.Write(offset);

            #endregion IFH

            #region IFD Image file directory

            // write image file directories for each jpeg
            for (int i = 0; offset > 0; i++)
            {
                // get data from jpeg with FreeImage
                FreeImageBitmap jpegImage;
                try
                {
                    jpegImage = new FreeImageBitmap(new MemoryStream(jpegs[i]));
                }
                catch (Exception ex)
                {
                    throw new Exception("Could not load image data at index " + i, ex);
                }
                if (jpegImage.ImageFormat != FREE_IMAGE_FORMAT.FIF_JPEG)
                    throw new ArgumentException("Image data at index " + i + " is not in JPEG format");

                // dta to write in tags
                uint width = (uint)jpegImage.Width;
                uint length = (uint)jpegImage.Height;
                uint xres = (uint)jpegImage.HorizontalResolution;
                uint yres = (uint)jpegImage.VerticalResolution;

                // count of entries:
                writer.Write(entryCount);

                offset += 6 + 12 * (uint)entryCount; // add lengths of entries, entry-count and next-ifd-offset

                // TIFF-fields / IFD-entrys:
                // {TAG, TYPE (3 = short, 4 = long, 5 = rational), COUNT, VALUE/OFFSET}
                uint[,] fields = new uint[,] { 
                    {254, 4, 1, 0}, // NewSubfileType
                    {256, 4, 1, width}, // ImageWidth
                    {257, 4, 1, length}, // ImageLength
                    {258, 3, 3, offset}, // BitsPerSample
                    {259, 3, 1, 7}, // Compression (new JPEG)
                    {262, 3, 1, 6}, //PhotometricInterpretation (YCbCr)
                    {273, 4, 1, offset + 22}, // StripOffsets (offset IFH + entries + values of BitsPerSample & YResolution & XResolution)
                    {277, 3, 1, 3}, // SamplesPerPixel
                    {278, 4, 1, length}, // RowsPerStrip
                    {279, 4, 1, (uint)jpegs[i].LongLength}, // StripByteCounts
                    {282, 5, 1, offset + 6}, // XResolution (offset IFH + entries + values of BitsPerSample)
                    {283, 5, 1, offset + 14}, // YResolution (offset IFH + entries + values of BitsPerSample & YResolution)
                    {284, 3, 1, 1}, // PlanarConfiguration (chunky)
                    {296, 3, 1, 2} // ResolutionUnit
                };

                // write fields
                for (int f = 0; f < fields.GetLength(0); f++)
                {
                    writer.Write((ushort)fields[f, 0]);
                    writer.Write((ushort)fields[f, 1]);
                    writer.Write(fields[f, 2]);
                    writer.Write(fields[f, 3]);
                }

                // offset of next IFD
                if (i == jpegs.Count - 1)
                    offset = 0;
                else
                    offset += 22 + (uint)jpegs[i].LongLength; // add values (of fields) length and jpeg length
                writer.Write(offset);

                #region values of fields

                // BitsPerSample
                writer.Write((ushort)8);
                writer.Write((ushort)8);
                writer.Write((ushort)8);

                // XResolution
                writer.Write(xres);
                writer.Write(1);

                // YResolution
                writer.Write(yres);
                writer.Write(1);

                #endregion values of fields

                // actual image data
                writer.Write(jpegs[i]);
            }
            #endregion IFD

            writer.Close();
            return tiffData.ToArray();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用FreeImageAPI;
名称空间Tiff
{
静态类TIFF转换器
{
/// 
///将JPEG图像列表包装到一个简单的多页TIFF容器中。
///(可能不适用于所有JPEG格式。)
/// 
///要转换的JPEG图像
/// 
公共静态字节[]WrapJPEG(列表JPEG)
{
如果(JPEG==null | | JPEG.Count==0 | | JPEG.FindIndex(b=>b.Length==0)>-1)
抛出新ArgumentNullException(“图像数据不能为null或空”);
MemoryStream tiffData=新的MemoryStream();
BinaryWriter=新的BinaryWriter(tiffData);
uint offset=8;//头的大小,偏移到IFD
ushort entryCount=14;//每个IFD的条目数
#区域IFH-图像文件头
//幻数
if(位转换器.IsLittleEndian)
writer.Write(0x002A4949);
其他的
writer.Write(0x4D002A);
//偏移到(第一个)IFD
writer.Write(偏移量);
#端区IFH
#区域IFD图像文件目录
//为每个jpeg写入图像文件目录
对于(int i=0;偏移量>0;i++)
{
//使用FreeImage从jpeg获取数据
自由图像位图JPEG图像;
尝试
{
jpegImage=新的FreeImageBitmap(新的内存流(JPEG[i]);
}
捕获(例外情况除外)
{
抛出新异常(“无法加载索引“+i,ex”处的图像数据);
}
if(jpegImage.ImageFormat!=自由图像格式.FIF\U JPEG)
抛出新ArgumentException(“索引“+i+”处的图像数据不是JPEG格式”);
//dta写入标记
uint width=(uint)jpegImage.width;
uint length=(uint)jpegImage.Height;
uint xres=(uint)jpegImage.HorizontalResolution;
uint yres=(uint)jpegImage.VerticalResolution;
//参赛人数:
writer.Write(entryCount);
offset+=6+12*(uint)entryCount;//添加条目长度、条目计数和下一个ifd偏移量
//TIFF字段/IFD条目:
//{标记,类型(3=short,4=long,5=rational),计数,值/偏移量}
uint[,]字段=新的uint[,]{
{254,4,1,0},//NewSubfileType
{256,4,1,width},//ImageWidth
{257,4,1,length},//ImageLength
{258,3,3,offset},///BitsPerSample
{259,3,1,7},//压缩(新JPEG)
{262,3,1,6},//测光解释
using System;
using System.Collections.Generic;
using System.IO;
using FreeImageAPI;

namespace Tiff
{
    static class TiffConverter
    {
        /// <summary>
        /// <para>Wraps a list of JPEG images into a simple multi-page TIFF container.</para>
        /// <para>(Might not work with all JPEG formats.)</para>
        /// </summary>
        /// <param name="jpegs">The JPEG-image to convert</param>
        /// <returns></returns>
        public static byte[] WrapJpegs(List<byte[]> jpegs)
        {
            if (jpegs == null || jpegs.Count == 0 || jpegs.FindIndex(b => b.Length == 0) > -1)
                throw new ArgumentNullException("Image data must not be null or empty");

            MemoryStream tiffData = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(tiffData);
            uint offset = 8; // size of header, offset to IFD
            ushort entryCount = 14; // entries per IFD

            #region IFH - Image file header

            // magic number
            if (BitConverter.IsLittleEndian)
                writer.Write(0x002A4949);
            else
                writer.Write(0x4D4D002A);

            // offset to (first) IFD
            writer.Write(offset);

            #endregion IFH

            #region IFD Image file directory

            // write image file directories for each jpeg
            for (int i = 0; offset > 0; i++)
            {
                // get data from jpeg with FreeImage
                FreeImageBitmap jpegImage;
                try
                {
                    jpegImage = new FreeImageBitmap(new MemoryStream(jpegs[i]));
                }
                catch (Exception ex)
                {
                    throw new Exception("Could not load image data at index " + i, ex);
                }
                if (jpegImage.ImageFormat != FREE_IMAGE_FORMAT.FIF_JPEG)
                    throw new ArgumentException("Image data at index " + i + " is not in JPEG format");

                // dta to write in tags
                uint width = (uint)jpegImage.Width;
                uint length = (uint)jpegImage.Height;
                uint xres = (uint)jpegImage.HorizontalResolution;
                uint yres = (uint)jpegImage.VerticalResolution;

                // count of entries:
                writer.Write(entryCount);

                offset += 6 + 12 * (uint)entryCount; // add lengths of entries, entry-count and next-ifd-offset

                // TIFF-fields / IFD-entrys:
                // {TAG, TYPE (3 = short, 4 = long, 5 = rational), COUNT, VALUE/OFFSET}
                uint[,] fields = new uint[,] { 
                    {254, 4, 1, 0}, // NewSubfileType
                    {256, 4, 1, width}, // ImageWidth
                    {257, 4, 1, length}, // ImageLength
                    {258, 3, 3, offset}, // BitsPerSample
                    {259, 3, 1, 7}, // Compression (new JPEG)
                    {262, 3, 1, 6}, //PhotometricInterpretation (YCbCr)
                    {273, 4, 1, offset + 22}, // StripOffsets (offset IFH + entries + values of BitsPerSample & YResolution & XResolution)
                    {277, 3, 1, 3}, // SamplesPerPixel
                    {278, 4, 1, length}, // RowsPerStrip
                    {279, 4, 1, (uint)jpegs[i].LongLength}, // StripByteCounts
                    {282, 5, 1, offset + 6}, // XResolution (offset IFH + entries + values of BitsPerSample)
                    {283, 5, 1, offset + 14}, // YResolution (offset IFH + entries + values of BitsPerSample & YResolution)
                    {284, 3, 1, 1}, // PlanarConfiguration (chunky)
                    {296, 3, 1, 2} // ResolutionUnit
                };

                // write fields
                for (int f = 0; f < fields.GetLength(0); f++)
                {
                    writer.Write((ushort)fields[f, 0]);
                    writer.Write((ushort)fields[f, 1]);
                    writer.Write(fields[f, 2]);
                    writer.Write(fields[f, 3]);
                }

                // offset of next IFD
                if (i == jpegs.Count - 1)
                    offset = 0;
                else
                    offset += 22 + (uint)jpegs[i].LongLength; // add values (of fields) length and jpeg length
                writer.Write(offset);

                #region values of fields

                // BitsPerSample
                writer.Write((ushort)8);
                writer.Write((ushort)8);
                writer.Write((ushort)8);

                // XResolution
                writer.Write(xres);
                writer.Write(1);

                // YResolution
                writer.Write(yres);
                writer.Write(1);

                #endregion values of fields

                // actual image data
                writer.Write(jpegs[i]);
            }
            #endregion IFD

            writer.Close();
            return tiffData.ToArray();
        }
    }
}