交换位图中的颜色值后文件大小发生变化

File size is changed after swapping color values in bitmap

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

下面是一个测试class我写来测试这个问题,它做了什么,总结一下就是:

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

如果您要打乱所有组件,我不会感到惊讶,您会注意到输出大小的增长甚至比仅打乱红色还要大。

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

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