C#WPF将richtextbox中粘贴的BitmapImage转换为二进制文件

我有一个richtextbox,我计划保存到数据库,可以将其加载回同一个richtextbox。 我已经将它工作,以便我可以将flowdocument保存为DataFormats.XamlPackage,它可以保存图像,但问题是文本无法搜索。 使用DataFormats.Xaml,我当然有文本,但没有图像。 图像将由最终用户粘贴,而不是应用程序附带的图像。

我尝试使用XamlWriter将文本转换为XML,然后分别从文档中获取图像并将它们作为二进制文件插入到XML中,但我似乎无法找到将图像转换为二进制文件的方法…

有没有人有关于如何将图像分成二进制,与文本分开的想法?

提前致谢!

GetImageByteArray()就是问题所在。

码:

private void SaveXML() { TextRange documentTextRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd); FlowDocument flowDocument = richTextBox.Document; using (StringWriter stringwriter = new StringWriter()) { using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(stringwriter)) { XamlWriter.Save(flowDocument, writer ); } testRTF t = new testRTF(); t.RtfText = new byte[0]; t.RtfXML = GetImagesXML(flowDocument); t.RtfFullText = stringwriter.ToString(); //save t to database } richTextBox.Document.Blocks.Clear(); } private string GetImagesXML(FlowDocument flowDocument) { using (StringWriter stringwriter = new StringWriter()) { using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(stringwriter)) { Type inlineType; InlineUIContainer uic; System.Windows.Controls.Image replacementImage; byte[] bytes; System.Text.ASCIIEncoding enc; //loop through replacing images in the flowdoc with the byte versions foreach (Block b in flowDocument.Blocks) { foreach (Inline i in ((Paragraph)b).Inlines) { inlineType = i.GetType(); if (inlineType == typeof(Run)) { //The inline is TEXT!!! } else if (inlineType == typeof(InlineUIContainer)) { //The inline has an object, likely an IMAGE!!! uic = ((InlineUIContainer)i); //if it is an image if (uic.Child.GetType() == typeof(System.Windows.Controls.Image)) { //grab the image replacementImage = (System.Windows.Controls.Image)uic.Child; //get its byte array bytes = GetImageByteArray((BitmapImage)replacementImage.Source); //write the element writer.WriteStartElement("Image"); //put the bytes into the tag enc = new System.Text.ASCIIEncoding(); writer.WriteString(enc.GetString(bytes)); //close the element writer.WriteEndElement(); } } } } } return stringwriter.ToString(); } } //This function is where the problem is, i need a way to get the byte array private byte[] GetImageByteArray(BitmapImage bi) { byte[] result = new byte[0]; using (MemoryStream ms = new MemoryStream()) { XamlWriter.Save(bi, ms); //result = new byte[ms.Length]; result = ms.ToArray(); } return result; } 

UPDATE

我想我可能终于找到了一个解决方案,我将在下面发布。 它使用BmpBitmapEncoder和BmpBitmapDecoder。 这允许我从位图图像中获取二进制文件,将其存储到数据库中,然后将其加载回来并将其显示回FlowDocument。 初步测试certificate是成功的。 出于测试目的,我绕过了我的数据库步骤,基本上通过创建二进制文件来复制图像,然后获取二进制文件并将其转换为新图像并将其添加到FlowDocument中。 唯一的问题是当我尝试使用修改后的FlowDocument并使用XamlWriter.Save函数时,它在新创建的Image上出现错误,“无法序列化非公共类型’System.Windows.Media.Imaging.BitmapFrameDecode”。 这将需要进一步调查。 我现在必须暂时不管它。

 private void SaveXML() { TextRange documentTextRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd); FlowDocument flowDocument = richTextBox.Document; string s = GetImagesXML(flowDocument);//temp LoadImagesIntoXML(s); using (StringWriter stringwriter = new StringWriter()) { using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(stringwriter)) { XamlWriter.Save(flowDocument, writer );//Throws error here } } } private string GetImagesXML(FlowDocument flowDocument) { string s= ""; using (StringWriter stringwriter = new StringWriter()) { Type inlineType; InlineUIContainer uic; System.Windows.Controls.Image replacementImage; byte[] bytes; BitmapImage bi; //loop through replacing images in the flowdoc with the byte versions foreach (Block b in flowDocument.Blocks) { foreach (Inline i in ((Paragraph)b).Inlines) { inlineType = i.GetType(); if (inlineType == typeof(Run)) { //The inline is TEXT!!! } else if (inlineType == typeof(InlineUIContainer)) { //The inline has an object, likely an IMAGE!!! uic = ((InlineUIContainer)i); //if it is an image if (uic.Child.GetType() == typeof(System.Windows.Controls.Image)) { //grab the image replacementImage = (System.Windows.Controls.Image)uic.Child; bi = (BitmapImage)replacementImage.Source; //get its byte array bytes = GetImageByteArray(bi); s = Convert.ToBase64String(bytes);//temp } } } } return s; } } private byte[] GetImageByteArray(BitmapImage src) { MemoryStream stream = new MemoryStream(); BmpBitmapEncoder encoder = new BmpBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create((BitmapSource)src)); encoder.Save(stream); stream.Flush(); return stream.ToArray(); } private void LoadImagesIntoXML(string xml) { byte[] imageArr = Convert.FromBase64String(xml); System.Windows.Controls.Image img = new System.Windows.Controls.Image() MemoryStream stream = new MemoryStream(imageArr); BmpBitmapDecoder decoder = new BmpBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default); img.Source = decoder.Frames[0]; img.Stretch = Stretch.None; Paragraph p = new Paragraph(); p.Inlines.Add(img); richTextBox.Document.Blocks.Add(p); } 

好消息。 我不得不在别的东西上工作一段时间,但这让我带着一双新鲜的眼睛回来。 我很快意识到我可以把我知道的工作结合起来。 我怀疑这个解决方案会赢得任何奖项,但它确实有效。 我知道我可以使用XamlReader将FlowDocument包装为文本,保留图像元素但丢失图像数据。 我也知道我可以使用XamlFormat将FlowDocument转换为二进制文件。 所以我有了获取FlowDocument的想法,并使用我已编写的函数来迭代查找图像,我拍摄每个图像,基本上克隆它并将克隆放入新的FlowDocument中。 我采用现在包含单个图像的新FlowDocument,将其转换为二进制,然后获取生成的二进制文件,将其转换为base64字符串并将其粘贴到原始FlowDocument中的图像的tag属性中。 这会将原始FlowDocument中的图像数据保存为文本。 这样我就可以将带有图像数据的FlowDocument(我称之为SUBString Format)传递到XamlReader中以获取可搜索的文本。 当它从数据库出来时,我正常地将FlowDocument拉出Xaml,但是然后遍历每个图像,使用XamlFormat从tag属性中提取数据,然后创建另一个克隆图像以为我的实际提供Source属性图片。 我已经提供了下面的SUBString格式的步骤。

 ///  /// Returns a FlowDocument in SearchableText UI Binary (SUB)String format. ///  /// The FlowDocument containing images/UI formats to be converted /// Returns a string representation of the FlowDocument with images in base64 string in image tag property private string ConvertFlowDocumentToSUBStringFormat(FlowDocument flowDocument) { //take the flow document and change all of its images into a base64 string FlowDocument fd = TransformImagesTo64(flowDocument); //apply the XamlWriter to the newly transformed flowdocument using (StringWriter stringwriter = new StringWriter()) { using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(stringwriter)) { XamlWriter.Save(flowDocument, writer); } return stringwriter.ToString(); } } ///  /// Returns a FlowDocument with images in base64 stored in their own tag property ///  /// The FlowDocument containing images/UI formats to be converted /// Returns a FlowDocument with images in base 64 string in image tag property private FlowDocument TransformImagesTo64(FlowDocument flowDocument) { FlowDocument img_flowDocument; Paragraph img_paragraph; InlineUIContainer img_inline; System.Windows.Controls.Image newImage; Type inlineType; InlineUIContainer uic; System.Windows.Controls.Image replacementImage; //loop through replacing images in the flowdoc with the base64 versions foreach (Block b in flowDocument.Blocks) { //loop through inlines looking for images foreach (Inline i in ((Paragraph)b).Inlines) { inlineType = i.GetType(); /*if (inlineType == typeof(Run)) { //The inline is TEXT!!! $$$$$ Kept in case needed $$$$$ } else */if (inlineType == typeof(InlineUIContainer)) { //The inline has an object, likely an IMAGE!!! uic = ((InlineUIContainer)i); //if it is an image if (uic.Child.GetType() == typeof(System.Windows.Controls.Image)) { //grab the image replacementImage = (System.Windows.Controls.Image)uic.Child; //create a new image to be used to get base64 newImage = new System.Windows.Controls.Image(); //clone the image from the image in the flowdocument newImage.Source = replacementImage.Source; //create necessary objects to obtain a flowdocument in XamlFormat to get base 64 from img_inline = new InlineUIContainer(newImage); img_paragraph = new Paragraph(img_inline); img_flowDocument = new FlowDocument(img_paragraph); //Get the base 64 version of the XamlFormat binary replacementImage.Tag = TransformImageTo64String(img_flowDocument); } } } } return flowDocument; } ///  /// Takes a FlowDocument containing a SINGLE Image, and converts to base 64 using XamlFormat ///  /// The FlowDocument containing a SINGLE Image /// Returns base 64 representation of image private string TransformImageTo64String(FlowDocument flowDocument) { TextRange documentTextRange = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd); using (MemoryStream ms = new MemoryStream()) { documentTextRange.Save(ms, DataFormats.XamlPackage); ms.Position = 0; return Convert.ToBase64String(ms.ToArray()); } } 

将映像保存到MemoryStream并将该流写入XML文件。

内存流将其转换为Byte []。

以下是我已经提出的两个建议的示例代码,如果我的示例不起作用,我必须查看有效负载问题…

  // get raw bytes from BitmapImage using BaseUri and SourceUri private byte[] GetImageByteArray(BitmapImage bi) { byte[] result = new byte[0]; string strImagePath = Path.Combine(Path.GetDirectoryName(bi.BaseUri.OriginalString), bi.UriSource.OriginalString); byte[] fileBuffer; using (FileStream fileStream = new FileStream(strImagePath, FileMode.Open)) { fileBuffer = new byte[fileStream.Length]; fileStream.Write(fileBuffer, 0, (int)fileStream.Length); } using (MemoryStream ms = new MemoryStream(fileBuffer)) { XamlWriter.Save(bi, ms); //result = new byte[ms.Length]; result = ms.ToArray(); } return result; } // get raw bytes from BitmapImage using BitmapImage.CopyPixels private byte[] GetImageByteArray(BitmapSource bi) { int rawStride = (bi.PixelWidth * bi.Format.BitsPerPixel + 7) / 8; byte[] result = new byte[rawStride * bi.PixelHeight]; bi.CopyPixels(result, rawStride, 0); return result; } private BitmapSource GetImageFromByteArray(byte[] pixelInfo, int height, int width) { PixelFormat pf = PixelFormats.Bgr32; int stride = (width * pf.BitsPerPixel + 7) / 8; BitmapSource image = BitmapSource.Create(width, height, 96, 96, pf, null, pixelInfo, stride); return image; }