我希望能够迭代位图图像并将值增加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;
}
}
答案 0 :(得分:1)
首先谈谈GIF文件和原始解决方案。
让它快速运行非常简单,但是,为了好玩,我只是笑了 - 我现在知道你的意思是什么质量下降了 !! !!
让我解释一下:GIF文件中有一些选项,但重要的是它是否是抖动。
我已经提到它们只有256种颜色;看起来不错,他们可以,至少从一定距离,正常的GIF文件使用一个技巧:他们抖动像素块,以显示混合颜色!这很好用,但它完全禁止使用调色板进行颜色旋转..
当然可以关闭抖动,但结果不仅看起来很粗糙和像素化;使用合适的调色板可以进行旋转,但结果最好是平庸的。我在函数palRotate
中添加了代码来执行此操作。
这给我们留下了我原来的建议:忘记GIF并去寻找ARGB颜色旋转!这也允许您使用已计算的全部Ks ..但是您需要严格的代码才能使其快速运行。
这是一个完整的测试平台,使用LockBits加载数据并使用它们进行全色循环。
您需要在表单中添加PictureBox
,Button
和Timer
。
请注意,您需要保持数据大小等于PictureBox
的大小。
我已经包含了一个500x500的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<Color> colors = new List<Color>();
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] = c.B;
data[index + 1] = c.G;
data[index + 2] = c.R;
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();
}
以下是一些包含测试数据的文件;测试文件的大小为500x500像素:
http://www.file-upload.net/download-9796723/fractalData021.dat.html
http://www.file-upload.net/download-9796722/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
变量的其他旋转代码类似。
答案 1 :(得分:0)
这会创建一个平滑旋转颜色的调色板。发生3 * 85 = 255,为Mset像素留下1个调色板条目。我没有对它进行编码以适合您的平台(并且它可以更好地编码为结构数组),但您可以看到我一次淡化2个原色。这避免了泥泞的颜色。
#include <stdio.h>
#include <memory.h>
#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;
}