【问题标题】:File size is changed after swapping color values in bitmap在位图中交换颜色值后文件大小发生变化
【发布时间】:2016-08-13 19:42:46
【问题描述】:

我正在尝试交换图像的颜色值,但我似乎发现了一些我不太理解的东西 - 我似乎无法在谷歌上找到关于此事的好读物。我可以完成图像颜色的交换,但与输入文件的大小相比,它也会改变输出文件的大小。

下面是我写的一个测试类来测试这个问题,它的作用,总结就是:

  1. 将位图分配给内存。
  2. 制作一个 RGB 值数组。
  3. 将 RGB 值数组拆分为三个单独的数组(r、g 和 b)。
  4. 用红色交换所有值(r[0] r[1]、r[2] r[3] 等)
  5. 加入三个数组并分配给 RGB 值数组。
  6. 复制回位图。
  7. 释放分配的内存。
  8. 导出文件。

代码如下:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace GraphTheory
{
    class Test
    {
        public Test(Bitmap bmp)
        {

            #region Assign bitmap to memory

            // Rectangle to hold the bmp.
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

            // Lock the bitmap to the rectangle / system memory.
            BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);

            // Get the adress of the first line.
            IntPtr ptr = bmpData.Scan0;

            // Declare an array to hold the bytes of the bitmap.
            int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
            byte[] rgb = new byte[bytes];

            // Copy the RGB values of the bitmap into the array.
            Marshal.Copy(ptr, rgb, 0, bytes);

            #endregion

            #region Split rgb array into three arrays

            // Number of colors in the image.
            int colors = bytes / 3;

            // Declare three arrays to hold the RGB values of the bitmap.
            byte[] r = new byte[colors];
            byte[] g = new byte[colors];
            byte[] b = new byte[colors];

            // Set starting pos of color index.
            int colorIndex = 0;

            // Split the array of RGB values into three seperate arrays.
            for (int i = 0; i < rgb.Length; i += 3)
            {
                int j = i + 1, k = i + 2;

                r[colorIndex] = rgb[k];
                g[colorIndex] = rgb[j];
                b[colorIndex] = rgb[i];

                colorIndex++;
            }

            #endregion

            #region Hide data in the colors of the bitmap

            for (int i = 0; i < colors; i += 2)
            {
                switchBits(ref r[i], ref r[i + 1]);
            }
            #endregion

            #region Join the three arrays into one rgb array

            // Reset color index.
            colorIndex = 0;

            // Replace the values of the rgb array with the values of the r, g and b arrays.
            for (int i = 0; i < rgb.Length; i += 3)
            {
                int j = i + 1, k = i + 2;

                rgb[k] = r[colorIndex];
                rgb[j] = g[colorIndex];
                rgb[i] = b[colorIndex];

                colorIndex++;
            }

            #endregion

            #region Free bitmap from memory and save to file

            // Copy the RGB values back to the bitmap
            Marshal.Copy(rgb, 0, ptr, bytes);

            // Unlock the bits.
            bmp.UnlockBits(bmpData);

            // Export the image.
            bmp.Save("../../output.png");

            #endregion
        }

        private void switchBits(ref byte bit1, ref byte bit2)
        {
            byte tmp = bit1;
            bit1 = bit2;
            bit2 = tmp;
        }
    }
}

我只是不明白为什么这会改变位图的图像大小,因为我没有替换任何颜色值,只是重新排列它们。

输入文件大小:[884 KB]

输出文件大小:[1335 KB]

不,图像不包含 alpha 通道:

Image.IsAlphaPixelFormat(image.PixelFormat) == false

【问题讨论】:

  • 输入输出文件是什么格式的?
  • 输入和输出都是 .png 格式。我将位图加载为:Bitmap bmp = new Bitmap("../../input.png"); 并将其导出为bmp.Save("../../output.png");@Reti43
  • 而如果你加载输入文件并立即保存而不修改,它会和原来一样大小吗?
  • 对 5 个不同大小的不同测试文件测试为阳性,所以结论是:是的。

标签: c# bitmap steganography


【解决方案1】:

PNG 使用(无损)压缩。这意味着输出文件的大小将取决于您提供的数据。压缩利用数据中的冗余,通过删除它可以实现更小的尺寸。图像往往有很多冗余,因为相邻像素是相关的,即它们具有相似的值。在您的情况下发生的事情是您的洗牌在某种程度上干扰了图像的自然模式,从而减少了像素相关性和冗余。因此,在压缩数据时,它们会占用更多空间。

如果您要对所有组件进行洗牌,我不会感到惊讶,您会注意到输出大小比单独洗牌还要大。

【讨论】:

  • 虽然我只对红色组件进行了洗牌,但我对您的输入进行了一些测试,它似乎是答案。感谢您抽出宝贵时间回答我的问题。
  • @MikkelJarlund 啊,是的,我的错误。有那么一刻,我记得好像你已经切换了所有组件。在这种情况下,我预计规模会增长得更多。我已经编辑了答案以正确反映这一点。顺便说一句,如果答案解决了您的问题,您可以选择marking it as accepted
  • 完成并再次感谢您。我刚刚进入 C# 开发(4 个月),这是我的第一个“大”项目,所以我仍在绞尽脑汁试图弄清楚这一切。希望我能像你一样,在几年后经验丰富的时候传授我的知识。
【解决方案2】:

您对 alpha 的检查是针对图像,而不是正在保存的内容。默认情况下 PNG 会保存一个 alpha。试试这个:

WPF - How do I save a PNG without any alpha channel?

【讨论】:

  • 这就是为什么我问他是否加载并保存输入文件而不做任何修改,输出文件是否会改变大小。这是为了捕捉编码器试图包含原始图像所具有的更多信息的情况。但是,OP 说他没有注意到这种差异,所以我认为大小差异是由于他的像素修改造成的。
猜你喜欢
  • 2018-05-13
  • 1970-01-01
  • 1970-01-01
  • 2012-10-15
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-14
相关资源
最近更新 更多