C#WPF BitmapImage的转换RichTextBox中粘贴到二进制 [英] C# WPF convert BitmapImage pasted in richtextbox to binary

查看:403
本文介绍了C#WPF BitmapImage的转换RichTextBox中粘贴到二进制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个RichTextBox,我打算保存到数据库,该数据库可以装载回相同的RichTextBox。我有它的工作,这样我可以节省的FlowDocument为DataFormats.XamlPackage,从而节省了图像,但问题是,文本不可搜索。随着DataFormats.Xaml,我有当然的文字,但没有图像。图像将被最终用户粘贴在,而不是图像包含的应用程序。



我试着使用的XamlWriter让文成XML,然后从抓取图像单独的文件,将它们插入为二进制到XML,但我似乎无法找到一种方式来获得的图像二值...



有没有人有想法如何获取图像转换成二进制,从文本分开?



在此先感谢!



GetImageByteArray( )是那里的问题是



代码:

 私人无效SaveXML()
{
的TextRange documentTextRange =新的TextRange(richTextBox.Document.ContentStart,richTextBox.Document.ContentEnd);
的FlowDocument的FlowDocument = richTextBox.Document;使用(StringWriter的StringWriter的=新的StringWriter())
{
使用
(System.Xml.XmlWriter作家= System.Xml.XmlWriter.Create(StringWriter的))
{
XamlWriter.Save(FlowDocument的,作家);
}

testRTF T =新testRTF();
t.RtfText =新的字节[0];
t.RtfXML = GetImagesXML(FlowDocument的);
t.RtfFullText = stringwriter.ToString();
// t保持到数据库
}
richTextBox.Document.Blocks.Clear();
}


私人字符串GetImagesXML(的FlowDocument的FlowDocument)
{使用

(StringWriter的StringWriter的=新的StringWriter())
{
使用(System.Xml.XmlWriter作家= System.Xml.XmlWriter.Create(StringWriter的))
{

型inlineType;
InlineUIContainer UIC;
System.Windows.Controls.Image replacementImage;
字节[]字节;
System.Text.ASCIIEncoding ENC;

//穿过flowdoc与字节版本
的foreach(B座在flowDocument.Blocks)
{
的foreach(更换图片循环内嵌我((第)二).Inlines)
{
inlineType = i.GetType();

如果(inlineType == typeof运算(运行))
{
//内联是TEXT!
}
,否则如果(inlineType == typeof运算(InlineUIContainer))
{
//内联有一个对象,可能的图像!
UIC =((InlineUIContainer)一);

//如果它是一个图象
如果(uic.Child.GetType()== typeof运算(System.Windows.Controls.Image))
{
//抓取图像
replacementImage =(System.Windows.Controls.Image)uic.Child;

//得到它的字节数组
字节= GetImageByteArray((BitmapImage的)replacementImage.Source);
//写元素
writer.WriteStartElement(图像);
//把字节写入标签
ENC =新System.Text.ASCIIEncoding();
writer.WriteString(enc.GetString(字节));
//关闭元素
writer.WriteEndElement();
}
}
}
}
}

返回stringwriter.ToString();
}
}


//这个函数是哪里出了问题,我需要一种方式来获得字节数组
私人字节[] GetImageByteArray (BitmapImage的BI)
{
的byte []结果=新的字节[0];
使用(MemoryStream的毫秒=新的MemoryStream())
{
XamlWriter.Save(BI,MS);
//结果=新的字节[ms.Length]
结果= ms.ToArray();
}
返回结果;
}



更新



我想我终于找到一个解决方案,我将在下面留言。它采用BmpBitmapEncoder和BmpBitmapDecoder。这使我从位图图像得到二进制文件,将其存储到数据库中,并加载它备份,并显示其右回的FlowDocument。初步测试已经证明是成功的。出于测试目的,我绕过我的数据库一步,基本上通过创建程序,然后以二进制,使之成为一个新的形象,将其添加到FlowDocument的复制图像。唯一的问题是,当我尝试拿走修改的FlowDocument和使用XamlWriter.Save功能,它的错误与新创建的图像无法序列非公开型'System.Windows.Media.Imaging.BitmapFrameDecode。这将需要一些进一步的调查。我不得不息事宁人,现在虽然。

 私人无效SaveXML()
{
的TextRange documentTextRange =新的TextRange(richTextBox.Document.ContentStart,richTextBox.Document.ContentEnd);
的FlowDocument的FlowDocument = richTextBox.Document;

字符串s = GetImagesXML(的FlowDocument); //临时
LoadImagesIntoXML(S);

使用(StringWriter的StringWriter的=新的StringWriter())
{
使用(System.Xml.XmlWriter作家= System.Xml.XmlWriter.Create(StringWriter的))
{
XamlWriter.Save(FlowDocument的,作家); //此处抛出错误
}

}
}

私人字符串GetImagesXML (的FlowDocument的FlowDocument)
{
字符串s =;

使用(StringWriter的StringWriter的=新的StringWriter())
{


型inlineType;
InlineUIContainer UIC;
System.Windows.Controls.Image replacementImage;
字节[]字节;
BitmapImage的双向;

//穿过flowdoc与字节版本
的foreach(B座在flowDocument.Blocks)
{
的foreach(更换图片循环内嵌我((第)二).Inlines)
{
inlineType = i.GetType();

如果(inlineType == typeof运算(运行))
{
//内联是TEXT!
}
,否则如果(inlineType == typeof运算(InlineUIContainer))
{
//内联有一个对象,可能的图像!
UIC =((InlineUIContainer)一);

//如果它是一个图象
如果(uic.Child.GetType()== typeof运算(System.Windows.Controls.Image))
{
//抓取图像
replacementImage =(System.Windows.Controls.Image)uic.Child;
双向=(BitmapImage的)replacementImage.Source;

//得到它的字节数组
字节= GetImageByteArray(BI);

S = Convert.ToBase64String(字节); //临时
}
}
}
}

返回小号;
}
}

私人字节[] GetImageByteArray(BitmapImage的SRC)
{
MemoryStream的流=新的MemoryStream();
BmpBitmapEncoder编码器=新BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create((的BitmapSource)SRC));
encoder.Save(流);
stream.Flush();
返回stream.ToArray();
}


私人无效LoadImagesIntoXML(字符串XML)
{


字节[] = imageArr Convert.FromBase64String( XML);
System.Windows.Controls.Image IMG =新System.Windows.Controls.Image()

MemoryStream的流=新的MemoryStream(imageArr);
BmpBitmapDecoder解码器=新BmpBitmapDecoder(流BitmapCreateOptions.None,BitmapCacheOption.Default);
img.Source = decoder.Frames [0];
img.Stretch = Stretch.None;

款P =新的第();
p.Inlines.Add(IMG);
richTextBox.Document.Blocks.Add(对);
}


解决方案

好消息。我只好上了一会儿别的工作,但是这让我回来了新鲜的一双眼睛。我很快意识到,我可以结合我所了解的是工作。我怀疑这个解决方案会赢得任何奖项,但它的工作原理。我知道,我最多可以换一个的FlowDocument与使用XamlReader文字,保持图像元素,但失去的图像数据。我也知道我可以使用XamlFormat转的FlowDocument成二进制。因此,我不得不服用的FlowDocument,并使用我已经写来遍历它找到图像功能的想法,我把每一个图像,基本上克隆,并把克隆到一个新的FlowDocument。我采取这一当前包含单个图像新的FlowDocument,把它变成二进制,然后取生成的二进制文件,把它变成的base64字符串,并将其贴到图像的原始FlowDocument的标签属性。这样可以使图像数据中的原始的FlowDocument为文本。这样我可以通过与图像数据的FlowDocument(我称之为子格式)到XamlReader得到搜索的文本。当它散发出来的数据库,我拉的FlowDocument出XAML中正常的,但通过每幅图像进行迭代,用XamlFormat提取标签属性的数据,然后创建另一个克隆的图像,为我的实际提供源物业图片。我所提供的步骤去下面子格式为:

  ///<总结> 
///返回SearchableText UI二进制(SUB)字符串格式的FlowDocument。
///< /总结>
///< PARAM NAME =FlowDocument的获得包含图像/ UI格式的FlowDocument转换< /参数>
///<退货和GT;返回的FlowDocument与图像标记属性和LT为Base64字符串图像的字符串表示; /回报>
私人字符串ConvertFlowDocumentToSUBStringFormat(的FlowDocument的FlowDocument)
{
//取流文件和更改所有的图像变成一个base64字符串
的FlowDocument FD = TransformImagesTo64(FlowDocument的);

//使用(StringWriter的StringWriter的=新的StringWriter())
{
使用(System.Xml.XmlWriter作家运用的XamlWriter到新改造的FlowDocument
= System.Xml.XmlWriter.Create(StringWriter的))
{
XamlWriter.Save(FlowDocument的,作家);
}
返回stringwriter.ToString();
}
}

///<总结>
///返回存储在自己的标签属性
的base64与图像的FlowDocument ///< /总结>
///< PARAM NAME =FlowDocument的获得包含图像/ UI格式的FlowDocument转换< /参数>
///<返回>在基地返回的FlowDocument与图像在图像标签属性和LT 64串; /回报>
私人的FlowDocument TransformImagesTo64(的FlowDocument的FlowDocument)
{
的FlowDocument img_flowDocument;
段img_paragraph;
InlineUIContainer img_inline;
System.Windows.Controls.Image newImage;
型inlineType;
InlineUIContainer UIC;
System.Windows.Controls.Image replacementImage;

//穿过flowdoc用的base64版本
的foreach(在flowDocument.Blocks B座)
{
//遍历内联寻找替代图像循环图像
的foreach(内嵌我((段)b).Inlines)
{
inlineType = i.GetType();

/ *如果(inlineType == typeof运算(运行))
{
//内联是TEXT! $$$$$在需要的情况下$$$$$
}
,否则不停* /如果(inlineType == typeof运算(InlineUIContainer))
{
//内联有一个对象,可能的图像!
UIC =((InlineUIContainer)一);

//如果它是一个图象
如果(uic.Child.GetType()== typeof运算(System.Windows.Controls.Image))
{
//抓取图像
replacementImage =(System.Windows.Controls.Image)uic.Child;

//创建一个新的形象被用来获得的base64
newImage =新System.Windows.Controls.Image();
//从的FlowDocument
newImage.Source = replacementImage.Source图像克隆图像;

//创建必需的对象,以获得一个XamlFormat来的FlowDocument获得
img_inline =基地64个新InlineUIContainer(newImage);
img_paragraph =新段(img_inline);
img_flowDocument =新的FlowDocument(img_paragraph);

//获取基本的64版的XamlFormat二进制$ B $乙replacementImage.Tag = TransformImageTo64String(img_flowDocument);
}
}
}
}
返回的FlowDocument;
}

///<总结>
///接受一个包含单个图像的的FlowDocument,并将其转换使用XamlFormat
立足64 ///< /总结>
///< PARAM NAME =FlowDocument的获得包含一个图像和LT的FlowDocument的; /参数>
///<退货和GT;返回基地形象和LT 64代表性; /回报>
私人字符串TransformImageTo64String(的FlowDocument的FlowDocument)
{
的TextRange documentTextRange =新的TextRange(flowDocument.ContentStart,flowDocument.ContentEnd);
使用(MemoryStream的毫秒=新的MemoryStream())
{
documentTextRange.Save(MS,DataFormats.XamlPackage);
ms.Position = 0;
返回Convert.ToBase64String(ms.ToArray());
}
}


I've got a richtextbox, that I plan on saving to a database, which can be loaded back into the same richtextbox. I've got it working so that I can save the flowdocument as DataFormats.XamlPackage, which saves the images, but the issue is that the text isn't searchable. With DataFormats.Xaml, I've got the text of course, but no images. The images will be pasted in by the end user, not images included with the application.

I tried using XamlWriter to get the text into XML, and then grab the images from the document separately and insert them as binary into the XML, but I can't seem to find a way to get the images to binary...

Does anyone have ideas on how to get the images into binary, separate from the text?

Thanks in advance!

GetImageByteArray() is where the issue is.

Code:

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

I think I may have finally found a solution, which I will post below. It uses BmpBitmapEncoder and BmpBitmapDecoder. This allows me to get binary from the bitmap image, store it to the database, and load it back up and display it right back into the FlowDocument. Initial tests have proven successful. For testing purposes I'm bypassing my database step and basically duplicating the image by creating binary, then taking the binary and turning it into a new image and adding it to the FlowDocument. The only issue is that when I try and take the modified FlowDocument and use the XamlWriter.Save function, it errors on the newly created Image with "Cannot serialize a non-public type 'System.Windows.Media.Imaging.BitmapFrameDecode". This will take some further investigation. I'll have to leave it alone for now though.

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);
        }

解决方案

Good news. I had to work on something else for a while, but this allowed me to come back with a fresh pair of eyes. I quickly realized that I could just combine what I knew was working. I doubt this solution will win any awards, but it works. I know that I can wrap a FlowDocument up as text using the XamlReader, keeping the image elements but losing image data. I also knew that I can turn a FlowDocument into binary using XamlFormat. So I had the idea of taking the FlowDocument, and using a function I already wrote to iterate through it to find the images, I take each image, basically clone it and put the clone into a new FlowDocument. I take that new FlowDocument that now contains the single image, turn it into binary, and then take the resulting binary, turn it into base64 string and stick it into the tag property of the image in the original FlowDocument. This keeps image data in the original FlowDocument as text. This way I can pass the FlowDocument with image data (which I call SUBString Format) into the XamlReader to get searchable text. When it comes out of the database, I pull the FlowDocument out of the Xaml as normal, but then iterate through each image, extracting the data from the tag property using XamlFormat, and then creating another clone image to provide the Source property for my actual image. I have provided the steps to get to SUBString format below.

/// <summary>
    /// Returns a FlowDocument in SearchableText UI Binary (SUB)String format.
    /// </summary>
    /// <param name="flowDocument">The FlowDocument containing images/UI formats to be converted</param>
    /// <returns>Returns a string representation of the FlowDocument with images in base64 string in image tag property</returns>
    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();
        }
    }

    /// <summary>
    /// Returns a FlowDocument with images in base64 stored in their own tag property
    /// </summary>
    /// <param name="flowDocument">The FlowDocument containing images/UI formats to be converted</param>
    /// <returns>Returns a FlowDocument with images in base 64 string in image tag property</returns>
    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;
    }

    /// <summary>
    /// Takes a FlowDocument containing a SINGLE Image, and converts to base 64 using XamlFormat
    /// </summary>
    /// <param name="flowDocument">The FlowDocument containing a SINGLE Image</param>
    /// <returns>Returns base 64 representation of image</returns>
    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());
        }
    }

这篇关于C#WPF BitmapImage的转换RichTextBox中粘贴到二进制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆