【问题标题】:Saving mostly white space images - high file size, want lower主要保存空白图像 - 文件大小较大,希望较小
【发布时间】:2013-10-25 16:32:53
【问题描述】:

我正在将一些 A4 图像和较小的图像保存到文件中。

我想知道什么是最好的格式。它们仅从灰度扫描中返回。然而,有些图像的尺寸相当大(与我们预期的相比)。

我们已经尝试将它们保存为具有不同质量的 JPEG,但仍然无法将它们保存为我们想要的那么小,JPEG 不是最有效的格式吗?

以质量 8 保存的 A4 将保存为 196KB 以质量 8 保存的较小图像保存为 28KB

由于该图像的大部分是空白区域,我们预计文件大小会小得多。文件大小在这里比图像质量更重要。 我们是不是做错了什么?

这是示例 A4 图片

这是较小的示例图片

我们的代码是用c#编写的

  // Get a bitmap.
    Bitmap bmp1 = new Bitmap(@"c:\TestImageFromScanner.jpg");
    ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg);

    // Create an Encoder object based on the GUID 
    // for the Quality parameter category.
    System.Drawing.Imaging.Encoder myEncoder =
        System.Drawing.Imaging.Encoder.Quality;

    // Create an EncoderParameters object. 
    // An EncoderParameters object has an array of EncoderParameter 
    // objects. In this case, there is only one 
    // EncoderParameter object in the array.
    EncoderParameters myEncoderParameters = new EncoderParameters(1);

    EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder,8L);
    myEncoderParameters.Param[0] = myEncoderParameter;
    bmp1.Save(@"c:\TestJpegQuality8.jpg", jgpEncoder, myEncoderParameters);

【问题讨论】:

  • 你可以在你的测试集上测试编码器。我们将无法为您进行测试。
  • 但是对于灰度和主要是空白的图像,是否有最佳图像格式?
  • TIFF 似乎很受复印机的欢迎。虽然你可能想看看 JBIG2。
  • 您在寻找磁盘空间与质量的对比吗?没有最好的格式。如果有,我们会使用相同的格式,对吗?
  • 你试过PNG吗?当我将您的测试图像缩小为 1 位黑白并保存为 PNG 时,它大约为 61 KiB。

标签: c#


【解决方案1】:

但是对于灰度且大部分为空白的图像,是否有最佳图像格式?

看你的图像是单色的,不是灰度的。如果可以接受单色,您可以使用JBIG2 来压缩您的文档。

它对文本进行了特殊优化(除其他外):

理想情况下,JBIG2 编码器会将输入页面分割成文本区域、半色调图像区域和其他数据区域。既不是文本也不是半色调的区域通常使用称为 QM 编码器的上下文相关算术编码算法进行压缩。文本区域被压缩如下:区域中的前景像素被分组为符号。 然后创建符号字典并对其进行编码,通常也使用上下文相关的算术编码,并且通过描述哪些符号出现在哪里来对区域进行编码。

强调我的。

【讨论】:

    【解决方案2】:

    对于具有大块纯色的图像,请考虑使用 PNG-8。

    但是,ta.speot.ls 在这种情况下的建议看起来会更好地满足您的需求。

    【讨论】:

    • 我很欣赏对我的回答的尊重,但 .NET JBIG2 库很难找到。 PNG8 可能会因为更易于访问而获胜。
    • 如何使用 c# 编码为 PNG8?
    • 是的,我一直在谷歌上搜索 JBIG2 有很多付费的图书馆即将推出。
    • 也试试ImageFormat.Tiff
    【解决方案3】:

    我使用一个函数将图像仅转换为黑色或白色,使用阈值。这大大减小了图像尺寸,而质量并没有大大降低。

        var downsizeImage = ImageTools.ConvertToBitonal(scaledBmp, 500);
                        downsizeImage.Save(string.Format(@"C:\Temp\{0}Downsized.png", betSlipImage.BetSlipID), ImageFormat.Png);
                        var ms = new MemoryStream();
                        downsizeImage.Save(ms, ImageFormat.Png);
    
       public static Bitmap ConvertToBitonal(Bitmap original, int threshold)
            {
                Bitmap source;
    
                // If original bitmap is not already in 32 BPP, ARGB format, then convert
                if (original.PixelFormat != PixelFormat.Format32bppArgb)
                {
                    source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
                    source.SetResolution(original.HorizontalResolution, original.VerticalResolution);
    
                    using (var g = Graphics.FromImage(source))
                    {
                        g.DrawImageUnscaled(original, 0, 0);
                    }
                }
                else
                {
                    source = original;
                }
    
                // Lock source bitmap in memory
                var sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    
                // Copy image data to binary array
                var imageSize = sourceData.Stride * sourceData.Height;
                var sourceBuffer = new byte[imageSize];
                Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);
    
                // Unlock source bitmap
                source.UnlockBits(sourceData);
    
                // Create destination bitmap
                var destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);
                destination.SetResolution(original.HorizontalResolution, original.VerticalResolution);
    
                // Lock destination bitmap in memory
                var destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
    
                // Create destination buffer
                imageSize = destinationData.Stride * destinationData.Height;
                var destinationBuffer = new byte[imageSize];
    
                var sourceIndex = 0;
                var destinationIndex = 0;
                var pixelTotal = 0;
                byte destinationValue = 0;
                var pixelValue = 128;
                var height = source.Height;
                var width = source.Width;
    
                // Iterate lines
                for (var y = 0; y < height; y++)
                {
                    sourceIndex = y * sourceData.Stride;
                    destinationIndex = y * destinationData.Stride;
                    destinationValue = 0;
                    pixelValue = 128;
    
                    // Iterate pixels
                    for (var x = 0; x < width; x++)
                    {
                        // Compute pixel brightness (i.e. total of Red, Green, and Blue values) - Thanks murx
                        //                           B                             G                              R
                        pixelTotal = sourceBuffer[sourceIndex] + sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2];
                        if (pixelTotal > threshold)
                        {
                            destinationValue += (byte)pixelValue;
                        }
                        if (pixelValue == 1)
                        {
                            destinationBuffer[destinationIndex] = destinationValue;
                            destinationIndex++;
                            destinationValue = 0;
                            pixelValue = 128;
                        }
                        else
                        {
                            pixelValue >>= 1;
                        }
                        sourceIndex += 4;
                    }
    
                    if (pixelValue != 128)
                    {
                        destinationBuffer[destinationIndex] = destinationValue;
                    }
                }
    
                // Copy binary image data to destination bitmap
                Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
    
                // Unlock destination bitmap
                destination.UnlockBits(destinationData);
    
                // Dispose of source if not originally supplied bitmap
                if (source != original)
                {
                    source.Dispose();
                }
    
                // Return
                return destination;
            }
    

    【讨论】:

      【解决方案4】:

      无损压缩将相同颜色的像素分组。如果有 100 个白色像素,它会存储“一百个白色像素”而不是“白色像素,白色像素.....”100 次。

      您的图片有大面积的白色。如果你想让它压缩得很好,它必须是完全相同的白色。所以量化你的图像。只是减少颜色的数量。

      我猜你只需要它作为证据的可读性,所以你不需要灰度。

      最好的结果是 1 位深度(黑色和白色 2 种颜色),PNG 和 tiff 效果很好。

      如果您有能力在这方面花费更多时间,您可以进行更多处理,例如去除孤立像素(噪点)。

      避免使用为照片制作的 JPEG。

      【讨论】:

        猜你喜欢
        • 2017-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多