我试图将Drawing.Bitmap转换为Imaging.Metafile,以便将图元文件插入到Forms.RichTextBox中。(作为参考,在图元文件中嵌入位图是将位图放入富文本的推荐做法(参见richtext (RTF)规范版本1.9.1,第149页)。不幸的是,它似乎也是将图像嵌入到Forms.RichTextBox中的唯一方法,因为我无法让任何与设备相关或与设备无关的方法将位图插入到RichTextBox中。)
稍后,我必须从图元文件中检索像素数据。我要求图元文件的像素与位图的像素完全匹配。然而,当我执行转换时,像素会略有改变。(可能是由于GDI图像颜色管理(ICM)?)
以下是我的技巧:
public static Imaging.Metafile BitmapToMetafileViaGraphicsDrawImage(Forms.RichTextBox rtfBox, Drawing.Bitmap bitmap)
{
Imaging.Metafile metafile;
using (IO.MemoryStream stream = new IO.MemoryStream())
using (Drawing.Graphics rtfBoxGraphics = rtfBox.CreateGraphics())
{
IntPtr pDeviceContext = rtfBoxGraphics.GetHdc();
metafile = new Imaging.Metafile(stream, pDeviceContext);
using (Drawing.Graphics imageGraphics = Drawing.Graphics.FromImage(metafile))
{
//imageGraphics.DrawImage(bitmap, new Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
imageGraphics.DrawImageUnscaled(bitmap, new Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
}
rtfBoxGraphics.ReleaseHdc(pDeviceContext);
}
return metafile;
}在这种情况下,我以这种方式访问图元文件的像素:
metafile.Save(stream, Imaging.ImageFormat.Png);
Bitmap bitmap = new Bitmap(stream, false);
bitmap.GetPixel(x, y);我也尝试过使用BitBlt技术,但没有成功。
BitBlt技术:
[System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
static extern int BitBlt(
IntPtr hdcDest, // handle to destination DC (device context)
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
System.Int32 dwRop // raster operation code
);
public static Imaging.Metafile BitmapToMetafileViaBitBlt(Forms.RichTextBox rtfBox, Drawing.Bitmap bitmap)
{
const int SrcCopy = 0xcc0020;
Graphics bitmapGraphics = Graphics.FromImage(bitmap);
IntPtr pBitmapDeviceContext = bitmapGraphics.GetHdc();
RectangleF rect = new RectangleF(new PointF(0, 0), new SizeF(bitmap.Width, bitmap.Height));
Imaging.Metafile metafile = new Imaging.Metafile(pBitmapDeviceContext, rect);
Graphics metafileGraphics = Graphics.FromImage(metafile);
IntPtr metafileDeviceContext = metafileGraphics.GetHdc();
BitBlt(pBitmapDeviceContext, 0, 0, bitmap.Width, bitmap.Height,
metafileDeviceContext, 0, 0, SrcCopy);
return metafile;
}我甚至不确定这种技术是否正确地复制像素数据。如果以后尝试访问图元文件中的数据,此技术将失败:
IntPtr h = metafile.GetHenhmetafile(); // ArgumentException "Parameter is not valid."
byte[] data;
uint size = GetEnhMetaFileBits(h, 0, out data);
data = new byte[size];
GetEnhMetaFileBits(h, size, out data);
stream = new IO.MemoryStream(data);如何在不改变像素的情况下将位图转换为图元文件,然后再检索像素数据?谢谢!
设置位图分辨率
这就是我如何尝试设置位图分辨率,以便图元文件的分辨率匹配:
Drawing.Bitmap bitmap = new Drawing.Bitmap(width, height,
Imaging.PixelFormat.Format32bppArgb); // Use 32-bit pixels so that each component (ARGB) matches up with a byte
// Try setting the resolution to see if that helps with conversion to/from metafiles
Drawing.Graphics rtfGraphics = rtfBox.CreateGraphics();
bitmap.SetResolution(rtfGraphics.DpiX, rtfGraphics.DpiY);
// Set the pixel data
...
// Return the bitmap
return bitmap;rtfBox是同一个发送给BitmapToMetafileViaGraphicsDrawImage的。
发布于 2010-10-04 17:59:54
您可以手动创建和处理图元文件(例如枚举其记录),在这种情况下,您实际上可以将包含其确切数据的位图插入到元文件流中。然而,这并不像听起来那么简单。
当使用GDI图元文件时,所有操作都在内部转换为GDI+,这实际上是一个完全不同的API,它处理许多事情都是不同的。不幸的是,一旦图元文件具有某种复杂性或需要转换输出,它的内置方式就是让GDI在低分辨率位图上呈现图元文件,然后绘制它,这永远不会给出您想要的结果。
对于一个项目(关闭源代码-所以不要麻烦地询问源代码;),我必须实现一个完整的GDI- to -GDI+回放引擎类似于EMFExplorer的功能,但只使用托管代码,并与单一字符重新对齐,以准确的文本输出。这只是说这是可以做到的,如果您愿意投入一些时间来处理您需要的所有元文件记录(这应该只是一个小子集,但仍然如此)。
编辑以解决评论中提出的问题:
图元文件只不过是一系列绘图指令,基本上是GDI(+)操作的记录。因此,您应该能够将图元文件构造为二进制数据,基本上只由头和位图组成,在这种情况下(因为您不需要通过钻操作,而是始终在二进制级别处理位图),您将能够从您写入的图元文件中检索完全相同的数据。
幸运的是,自几年以来,微软一直在记录它们的文件格式和协议,并将其提供给公众,这样就可以获得WMF/EMF文件格式的精确文档。图元文件格式由MS在这里解释:http://msdn.microsoft.com/en-us/library/cc230514(PROT.10).aspx
It结构概述如下:http://msdn.microsoft.com/en-us/library/cc230516(v=PROT.10).aspx
位图记录在这里描述:http://msdn.microsoft.com/en-us/library/cc231160(v=PROT.10).aspx
使用这些信息,您应该能够将二进制数据(可能使用BinaryWriter)放在一起,然后加载/枚举文件以获取数据(例如,在图元文件中再次查找位图并从中提取所需的数据)。
发布于 2010-10-04 17:46:52
这只是在黑暗中的一次尝试,但是看看一些ImageFlags标志值,看看它们是否可以合并到元文件的生成或呈现中。
发布于 2010-10-04 23:00:54
这是一个很有趣的解决方法,但是如果你只需要把它放在RichTextBox中-你可以使用剪贴板:
private void button1_Click(object sender, EventArgs e)
{
System.Drawing.Bitmap bmp = new Bitmap("g.bmp");
Clipboard.SetData(DataFormats.Bitmap, bmp);
richTextBox1.Paste();
}但我不确定相反的方法(从RTF文本中读取位图)
https://stackoverflow.com/questions/3846448
复制相似问题