图片格式转换并按指定调色板修改颜色深铳

regalia 2009-06-18 08:20:50
各位高手你们好:
我现在做一个功能要求如下:
1、将任意图片格式转换成BMP格式图片。
2、转换时同时实现BMP尺寸的缩放。
3、将缩放好的图片按75%进行扩散。
4、将扩散后的BMP按指定的256色调色板(来自TXT文件),压缩成8位索引色图片。


前1、2、项功能已实现3也实现的差不多了,4把图片按指定调色板转换未能实现,请高手们指教,本人是C#的初学者,能提供4的代码 就太感谢了!

...全文
431 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
zgke 2009-06-18
  • 打赏
  • 举报
回复

Bitmap _Bitmap32 = (Bitmap)Image.FormFile("e:\\32位原图.bmp"); //载入原图
Bitmap _BitmapPal = (Bitmap)Image.FormFile("e:\\含颜色板图片.bmp"); //借用调色板

MemoryStream _Mem = new MemoryStream();
_Bitmap32.Save(_Mem, ImageFormat.Gif); //保存成GIF GIF只支持8位 也就是系统自己做减色保存成GIF流
Bitmap _Bitmap8 = (Bitmap)Image.FromStream(_Mem); //重新打开GIF

_Bitmap8.Palette = _BitmapPal.Palette;

_Bitmap8.Save(@"e:\\8位索引图.bmp", ImageFormat.Bmp);


再不明白我就没办法了.
regalia 2009-06-18
  • 打赏
  • 举报
回复
zgke您好:
对不起,我还是没能理解您的意思,可能是我表达的不清楚,我需要将一张32位真彩的位图按指定的颜色表压成8位256索引色,就是使画面质量下降。
您在9楼里说 Bitmap _Bitmap8 = 你的图..
Bitmap _Bitmap32 = 你的图.. 这样就可以了..没必要弄到空图上来.

假设,如下:
32位原图.bmp===是我要进行转换的原图
含颜色板图片.bmp====我用PS转好的指定颜色板的图片(想用它的调色板);
8位索引图.bmp===转换输出的图片

Bitmap _Bitmap32=(Bitmap)Image.FormFile("e:\\32位原图.bmp"); //载入原图
Bitmap _BitmapPal=(Bitmap)Image.FormFile("e:\\含颜色板图片.bmp"); //借用调色板
Bitmap _Bitmap8=(_Bitmap32.Width,_Bitmap32.Height,PixelFormat.Format8bppIndexed); //新建8位空位图

_Bitmap8.Palette= _BitmapPal.Palette; //指定新8位空位图颜色板
//============================================================
请问这中间的该怎么办
如果Bitmap _Bitmap8 = 你的图.. 不就又空了,或是变32位了吗?
还是我一个个的比像素点
//=============================================================
_Bitmap8.save("e:\\8位索引图.bmp",)


ximi82878 2009-06-18
  • 打赏
  • 举报
回复
不会,帮忙顶
zgke 2009-06-18
  • 打赏
  • 举报
回复
Bitmap _Bitmap8 = 你的图..
Bitmap _Bitmap32 = 你的图.. 这样就可以了..没必要弄到空图上来.
outou 2009-06-18
  • 打赏
  • 举报
回复
不知下面的代码可否?代码来自http://bingning.net/free/source/graphics/encoderparameters.html

public static void SaveImage(string fileName, int quality)
{
//读取画像文件
Bitmap bmp= new Bitmap(fileName);

// EncoderParameter对象只能容纳1个
// EncoderParameters类的新instance初始化
//在这里只是指定质量值,所以只需要1个
System.Drawing.Imaging.EncoderParameters eps =
new System.Drawing.Imaging.EncoderParameters(1);
//指定质量
System.Drawing.Imaging.EncoderParameter ep =
new System.Drawing.Imaging.EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, quality);
eps.Param[0] = ep;

//取得ImageEncoder相关的信息
System.Drawing.Imaging.ImageCodecInfo ici;
ici = GetEncoderInfo("image/jpeg");

//取得新文件的扩展名
string ext = ici.FilenameExtension.Split(';')[0];
ext = System.IO.Path.GetExtension(ext).ToLower();

//定保存文件的名称(改变扩展名)
string saveName= System.IO.Path.ChangeExtension(fileName, ext);

//保存
bmp.Save(saveName, ici, eps);
}

private static System.Drawing.Imaging.ImageCodecInfo
GetEncoderInfo(string mineType)
{
//取得所有向GDI+被装入的ImageEncode相关信息
System.Drawing.Imaging.ImageCodecInfo [] encs=
System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
//如果检测到被指定的MimeType,返回
foreach (System.Drawing.Imaging.ImageCodecInfo enc in encs)
if (enc.MimeType == mineType)
return enc;
return null;
}

regalia 2009-06-18
  • 打赏
  • 举报
回复
谢谢楼上的指点,但是功能要求:
A、必须用BMP格式,我也没办法。
B、必须用指定的调色板。
C、您写的办法,只是新建了一个我指定调色板的空位图,请问怎样将我以做好的32位位图的图像,弄到这个空位图中来呢?
本人初学,谢谢!
修改一下昵称 2009-06-18
  • 打赏
  • 举报
回复
路过 , ,帮顶一下。
zgke 2009-06-18
  • 打赏
  • 举报
回复
3 Image.GetThumbnailImage

4 设置调色版

Bitmap _Bitmap8 = new Bitmap(32, 32, PixelFormat.Format8bppIndexed);

ColorPalette _ColorPalette = _Bitmap8.Palette;

for (int i = 0; i != _ColorPalette.Entries.Length; i++)
{
_ColorPalette.Entries[i] = Color.FromArgb("去取你的色彩");
}

_Bitmap8.Palette = _ColorPalette;

如果要保存成8位的色彩..
最笨的方法 可以利用GIF


Bitmap _Bitmap32 = this.Icon.ToBitmap();

MemoryStream _ImageMem = new MemoryStream();

_Bitmap32.Save(_ImageMem, ImageFormat.Gif);

Bitmap _Bitmap8 = (Bitmap)Image.FromStream(_ImageMem);

你也可以自己写抖动算法..
xxyping 2009-06-18
  • 打赏
  • 举报
回复
只能up了,不懂
FlyBee 2009-06-18
  • 打赏
  • 举报
回复
帮顶
regalia 2009-06-18
  • 打赏
  • 举报
回复
刚才不好意思,第一次发帖不知道加分,已加上了100。
希望本帖不要沉,这个功能折磨我一周了。就想找一个,按指定颜色表转换颜色的方法。
  • 打赏
  • 举报
回复
消灭0回复
zgke 2009-06-18
  • 打赏
  • 举报
回复
/// <summary>
/// Convet图形为索引图形
/// </summary>
/// <param name="p_SourceImage">原始图形</param>
/// <param name="p_PixelFormat">格式 之支持 Format4bppIndexed Format1bppIndexed Format8bppIndexed</param>
/// <param name="p_Dithering">原始图形</param>
/// <returns>图形</returns>
public static Bitmap Convert(Bitmap p_SourceImage, bool p_Dithering)
{
int _Width = p_SourceImage.Width;
int _Height = p_SourceImage.Height;

PixelFormat _SetPixFormat = PixelFormat.Format8bppIndexed;

//创建颜色索引表 为2个颜色
Bitmap _NewBitmap = new Bitmap(_Width, _Height, _SetPixFormat);

ColorPalette _Palette = _NewBitmap.Palette;//LoadPalette(p_SourceImage,256);



//重新获取一个原始图形 色彩设置为24色 R G B
Bitmap _Source = new Bitmap(_Width, _Height, PixelFormat.Format24bppRgb);
Graphics _Graphics = Graphics.FromImage(_Source);
_Graphics.DrawImage(p_SourceImage, 0, 0, _Width, _Height);
_Graphics.Dispose();


//获取两个图形的数据
BitmapData _SourceData = _Source.LockBits(new Rectangle(0, 0, _Width, _Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData _NewData = _NewBitmap.LockBits(new Rectangle(0, 0, _Width, _Height), ImageLockMode.WriteOnly, _SetPixFormat);

//复制出图形数据的
byte[] _SourceByte = new byte[_SourceData.Stride * _Height];
byte[] _NewByte = new byte[_NewData.Stride * _Height];
Marshal.Copy(_SourceData.Scan0, _SourceByte, 0, _SourceByte.Length);
Marshal.Copy(_NewData.Scan0, _NewByte, 0, _NewByte.Length);

int _SourceIndex = 0;
int _NewIndex = 0;
//颜色表列
Dictionary<int, byte> _ColorTable = new Dictionary<int, byte>();


Color _SetColor;

for (int i = 0; i != _Height; i++)
{
_NewIndex = i * _NewData.Stride;
_SourceIndex = i * _SourceData.Stride;
for (int z = 0; z != _Width; z++)
{
#region 获取色彩索引
//获取原始图形色彩
_SetColor = Color.FromArgb(0, _SourceByte[_SourceIndex + 2], _SourceByte[_SourceIndex + 1], _SourceByte[_SourceIndex]);
_SourceIndex += 3;

byte _TableIndex = 0;
if (!(_ColorTable.TryGetValue(_SetColor.ToArgb(), out _TableIndex)))
{
//判断颜色是否在颜色表里
_TableIndex = (byte)ConvertTobppFindNearestColor(_SetColor, _Palette.Entries);
_ColorTable.Add(_SetColor.ToArgb(), _TableIndex);
}
#endregion

#region 填充新图形


_NewByte[_NewIndex + z] = _TableIndex;

#endregion

#region 先获取右边 然后获取下边 获取下边的左变和右边的色彩 设置数据

if (!p_Dithering) continue;
int _R = _SetColor.R - _Palette.Entries[_TableIndex].R;
int _G = _SetColor.G - _Palette.Entries[_TableIndex].G;
int _B = _SetColor.B - _Palette.Entries[_TableIndex].B;

int _StarIndex = i * _SourceData.Stride;
int _SourceIndexRVA = 0;
if (z + 1 < _Width)
{
_SourceIndexRVA = (_StarIndex) + ((z + 1) * 3);
//_SourceIndexRVA = _SourceIndex;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_B * 7) >> 4);
_SourceIndexRVA++;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_G * 7) >> 4);
_SourceIndexRVA++;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_R * 7) >> 4);

}
if (i + 1 < _Height)
{
if (z - 1 > 0)
{
_SourceIndexRVA = (_StarIndex) + ((z - 1) * 3) + _SourceData.Stride;
//_SourceIndexRVA = (_SourceIndex - 6) + _SourceData.Stride;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_B * 3) >> 4);
_SourceIndexRVA++;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_G * 3) >> 4);
_SourceIndexRVA++;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_R * 3) >> 4);
}
_SourceIndexRVA = (_StarIndex) + ((z + 0) * 3) + _SourceData.Stride;
//_SourceIndexRVA = (_SourceIndex - 3) + _SourceData.Stride;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_B * 5) >> 4);
_SourceIndexRVA++;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_G * 5) >> 4);
_SourceIndexRVA++;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_R * 5) >> 4);

if (z + 1 < _Width)
{
_SourceIndexRVA = (_StarIndex) + ((z + 1) * 3) + _SourceData.Stride;
// _SourceIndexRVA = _SourceIndex + _SourceData.Stride;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_B * 1) >> 4);
_SourceIndexRVA++;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_G * 1) >> 4);
_SourceIndexRVA++;
_SourceByte[_SourceIndexRVA] = ConvertTobppLimits(_SourceByte[_SourceIndexRVA], (_R * 1) >> 4);
}
}
#endregion
}
}

_Source.UnlockBits(_SourceData);
Marshal.Copy(_NewByte, 0, _NewData.Scan0, _NewByte.Length);
_NewBitmap.UnlockBits(_NewData);
_NewBitmap.Palette = _Palette;
return _NewBitmap;
}
private static int ConvertTobppFindNearestColor(Color p_SetColor, Color[] p_PaletteEntries)
{
int _MinDistanceSquared = 195076; // 255 * 255 + 255 * 255 + 255 * 255 + 1
int _BestIndex = 0;

for (int i = 0; i < p_PaletteEntries.Length; i++)
{
int _ColorR = p_SetColor.R - p_PaletteEntries[i].R;
int _ColorG = p_SetColor.G - p_PaletteEntries[i].G;
int _ColorB = p_SetColor.B - p_PaletteEntries[i].B;

int _DistanceSquared = _ColorR * _ColorR + _ColorG * _ColorG + _ColorB * _ColorB;

if (_DistanceSquared < _MinDistanceSquared)
{
_MinDistanceSquared = _DistanceSquared;
_BestIndex = i;
}
}
return _BestIndex;
}
private static byte ConvertTobppLimits(int p_ColorA, int p_ColorB)
{
return (p_ColorA + p_ColorB) < 0 ? (byte)0 : (p_ColorA + p_ColorB) > 255 ? (byte)255 : (byte)(p_ColorA + p_ColorB);
}



你用这个方法看看..个人感觉如果调色版那里还需要一个方法.. 本来是根据图形生成调色板,我上面是字节用BMP 8位色的调色版..你看这改下把
regalia 2009-06-18
  • 打赏
  • 举报
回复
我的最终目的是BMP,GIF只是没有更好办法的一个折中,我试过了,失真比较严重,就是PS通过GIF再转也一样。
光宇广贞 2009-06-18
  • 打赏
  • 举报
回复
http://hi.baidu.com/takinrul/blog/item/59e4d0c32858e7130ef477a4.html
这是别人一个简单的事例,MSDN上有完整的出色的示例。
光宇广贞 2009-06-18
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 regalia 的回复:]
感谢 zgke的悉心帮助,我明白您的意图了,但这方法我试了,问题有二:
1、GIF系统自行转色后再转,相当于失真后再失真,图像质量下降的很历害。
2、这种颜色表替换,文件头内的的颜色表与我指定的颜色表替换不完全。
谢谢了,再等一天,如果没有更好的方法,明天就结给您了。
[/Quote]

读GIF最好的办法是使用 C# 3.x 里面的 GIFDecoder类对像,可以对多帧的GIF图的每一帧进行读取,分别进行还原。
像图像格式转换这种,只要知道了用什么类对像处理,上MSDN有的是例子和方法可查。
regalia 2009-06-18
  • 打赏
  • 举报
回复
感谢 zgke的悉心帮助,我明白您的意图了,但这方法我试了,问题有二:
1、GIF系统自行转色后再转,相当于失真后再失真,图像质量下降的很历害。
2、这种颜色表替换,文件头内的的颜色表与我指定的颜色表替换不完全。
谢谢了,再等一天,如果没有更好的方法,明天就结给您了。

110,543

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧