迭代图像像素并旋转颜色

我希望能够迭代位图图像并将值增加1,但是目前图像从内存流中返回的质量比之前差,并且变化根本不平滑。

private static Bitmap CyclePalette(Bitmap original) { using (var bitMapStream = new MemoryStream()) { original.Save(bitMapStream, format: ImageFormat.Gif); var newBitmap = new Bitmap(bitMapStream); var newPalette = newBitmap.Palette; for (var i = 0; i < newPalette.Entries.Length - 5; i++) { var oldColor = newPalette.Entries[i]; newPalette.Entries[i] = newPalette.Entries[i + 1]; newPalette.Entries[i + 1] = oldColor; } newBitmap.Palette = newPalette; return newBitmap; } } 

首先谈谈GIF文件和原始解决方案。

让它快速运行是非常简单的,但是,为了好玩,我只是做了我不得不笑 – 现在我知道你的质量降低的意思了!! !!

让我解释一下:GIF文件中有一些选项,但重要的是它是否是抖动。

我已经提到它们只有256种颜色; 看起来不错,他们可以,至少从一定距离,正常的GIF文件使用一个技巧:他们抖动像素块来显示混合颜色! 这很好用,但它完全禁止使用调色板进行颜色旋转。

当然可以关闭抖动,但结果不仅看起来很粗糙和像素化; 使用合适的调色板可以进行旋转,但结果最好是平庸。 我在函数palRotate添加了代码。

这给我们留下了我的原始建议:忘记GIF并继续进行ARGB颜色旋转! 这也允许您使用已计算的全部Ks。但是您需要严格的代码才能使其快速运行。

这是一个完整的测试平台,使用LockBits加载数据并使用它们进行全色循环。 您需要在表单中添加PictureBoxButtonTimer 。 请注意,您需要保持数据大小等于PictureBox的大小。 我已经包含了一个500×500的testdata文件。

 using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.IO; //.. // the data array int[,] Ks; // the offset for cycling int koffset = 0; // a list of colors List colors = new List(); public void paintKs() { if (Ks == null) return; Size s1 = pb_image.ClientSize; pb_image.Image = new Bitmap(s1.Width, s1.Height); Bitmap bmp = new Bitmap(pb_image.Image); PixelFormat fmt1 = bmp.PixelFormat; byte bpp1 = 4; Rectangle rect = new Rectangle(Point.Empty, s1); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt1); int size1 = bmpData.Stride * bmpData.Height; byte[] data = new byte[size1]; System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, size1); for (int y = 0; y < s1.Height; y++) { for (int x = 0; x < s1.Width; x++) { int index = y * bmpData.Stride + x * bpp1; Color c = colors[(Ks[x, y] + koffset) % (colors.Count)]; if (Ks[x, y] == 0) c = Color.Black; data[index + 0] = cB; data[index + 1] = cG; data[index + 2] = cR; data[index + 3] = 255; } } System.Runtime.InteropServices.Marshal.Copy(data, 0, bmpData.Scan0, data.Length); bmp.UnlockBits(bmpData); pb_image.Image = bmp; } void saveKs(string dataFile) { using (BinaryWriter writer = new BinaryWriter(File.Open(dataFile, FileMode.Create))) { for (int y = 0; y < Ks.GetLength(0); y++) for (int x = 0; x < Ks.GetLength(1); x++) writer.Write((Int16)Ks[x, y]); } } void loadKs(string dataFile) { int w = pb_image.ClientSize.Width; if (Ks == null) Ks = new int[w, w]; using (BinaryReader reader = new BinaryReader(File.Open(dataFile, FileMode.Open))) { for (int y = 0; y < Ks.GetLength(0); y++) for (int x = 0; x < Ks.GetLength(1); x++) Ks[x, y] = reader.ReadInt16(); } } private void Test_Click(object sender, EventArgs e) { loadKs("fractalData021.dat"); for (int i = 0; i < 256; i++) { // a very simple and rather awful palette! for (int i = 0; i < 256; i++) colors.Add(Color.FromArgb(255, i, i, 255 - i)); for (int i = 0; i < 100; i++) colors.Add(Color.FromArgb(255, i + 100, 255 -i, 155 - i)); for (int i = 0; i < 100; i++) colors.Add(Color.FromArgb(255, i + i+ 50, 255 - i - i, 155 - i/2)); } paintKs(); timer1.Intervall = 33; // 30 fps timer1.Start(); } private void timer1_Tick(object sender, EventArgs e) { koffset++; if (koffset >= colors.Count) koffset = 0;; paintKs(); } 

以下是一些包含测试数据的文件; 测试文件的大小为500×500像素:

http://www.file-upload.net/download-9796723/fractalData021.dat.html

http://sofzh.miximages.com/c%23/fractalData021.jpg.html

http://www.file-upload.net/download-9796721/fractalData021.txt.html

更新:

这是在非抖动的GIF文件上进行plaette旋转的代码。

 void palRotate() { Bitmap bmp = (Bitmap)pb_image.Image; var pal = bmp.Palette; for (int i = 0; i < 256; i++) pal.Entries[(i + koffset) % 256] = colors[i]; bmp.Palette = pal; pb_image.Image = bmp; } 

为了准备这些调用,将原始调色板颜色提取到颜色列表中:

 pb_image.Image = new Bitmap("d:\\fff.gif"); Bitmap bmp = (Bitmap)pb_image.Image; var pal = bmp.Palette; for (int i = 0; i < 256; i++) colors.Add(pal.Entries[i]); 

为了让这看起来完全蹩脚,托盘必须有某种秩序; 但即便如此,像素化的图像看起来也很可悲。

它将以与来自Timer的其他旋转代码类似的方式调用,该代码提升koffset变量。

这将创建一个平滑旋转颜色的调色板。 发生3 * 85 = 255,为Mset像素留下1个调色板条目。 我没有编写它以适合您的平台(它会更好地编码为结构数组),但你可以看到我一次淡化2个原色。 这避免了泥泞的颜色。

 #include  #include  #define MAXITER 1000 // iteration depth unsigned char pal [256][3]; int Mandelplot (int x, int y) { // return (palette) colour for pixel int c, i=iterate (x, y); // your iteration function if (i >= MAXITER) c = 255; else c = i % 255; return c; } void rotate_palette (void) { // leaves index 255 unchanged for Mset pixels unsigned char r=pal[0][0], g=pal[0][1], b=pal[0][2]; memcpy (&pal[0][0], &pal[1][0], 254 * 3 * sizeof(unsigned char)); pal[254][0] = r; pal[254][1] = g; pal[254][2] = b; } int main (void) { unsigned char r=0, g=0, b=255; int i; for (i=0; i<85; i++) { pal [i][0]= r; pal [i][1]= g; pal [i][2]= b; b -= 3; g += 3; } for (i=85; i<170; i++) { pal [i][0]= r; pal [i][1]= g; pal [i][2]= b; g -= 3; r += 3; } for (i=170; i<255; i++) { pal [i][0]= r; pal [i][1]= g; pal [i][2]= b; r -= 3; b += 3; } pal [255][0] = 0; // black on the Mset pal [255][1] = 0; pal [255][2] = 0; for (i=0; i<256; i++) printf ("%02X %02X %02X, ", pal[i][0], pal[i][1], pal[i][2]); return 0; }