2009-11-30 31 views
6

Tôi có một richtextbox, mà tôi dự định lưu vào cơ sở dữ liệu, có thể được tải lại vào cùng một richtextbox. Tôi đã có nó làm việc để tôi có thể lưu flowdocument như DataFormats.XamlPackage, mà lưu hình ảnh, nhưng vấn đề là văn bản không thể tìm kiếm được. Với DataFormats.Xaml, tôi đã có văn bản tất nhiên, nhưng không có hình ảnh. Các hình ảnh sẽ được dán bởi người dùng cuối, không phải hình ảnh đi kèm với ứng dụng.C# WPF chuyển đổi BitmapImage được dán vào richtextbox thành dạng nhị phân

Tôi đã thử sử dụng XamlWriter để lấy văn bản thành XML, sau đó lấy các hình ảnh từ tài liệu một cách riêng biệt và chèn chúng dưới dạng nhị phân vào XML, nhưng dường như tôi không tìm được cách để đưa hình ảnh vào nhị phân. ..

Có ai có ý tưởng về cách đưa hình ảnh vào nhị phân, tách biệt với văn bản không?

Cảm ơn trước!

GetImageByteArray() là nơi xảy ra sự cố.

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

CẬP NHẬT

Tôi nghĩ rằng tôi có thể cuối cùng đã tìm thấy một giải pháp, mà tôi sẽ đăng dưới đây. Nó sử dụng BmpBitmapEncoder và BmpBitmapDecoder. Điều này cho phép tôi lấy nhị phân từ hình ảnh bitmap, lưu nó vào cơ sở dữ liệu, và tải nó trở lại và hiển thị nó trở lại vào FlowDocument. Các thử nghiệm ban đầu đã chứng minh thành công. Đối với mục đích thử nghiệm, tôi bỏ qua bước cơ sở dữ liệu của mình và sao chép cơ bản hình ảnh bằng cách tạo nhị phân, sau đó lấy nhị phân và biến nó thành một hình ảnh mới và thêm nó vào FlowDocument. Vấn đề duy nhất là khi tôi thử và lấy FlowDocument đã sửa đổi và sử dụng hàm XamlWriter.Save, nó lỗi trên Image vừa tạo với "Không thể tuần tự hóa một kiểu không công khai" System.Windows.Media.Imaging.BitmapFrameDecode ". Điều này sẽ mất một số điều tra thêm. Tôi sẽ phải để nó một mình cho đến bây giờ.

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

có thể muốn thay đổi tiêu đề bài đăng này thành nội dung phù hợp hơn ... có vẻ như bạn đang thực sự hỏi cách lấy byte thô của đối tượng Hình ảnh và lưu trữ trong tài liệu Xml ... –

+0

cảm ơn Nghe có vẻ tốt, tôi đã cố gắng cụ thể nhất có thể trong trường hợp ai đó có ý tưởng khác về cách đạt được hiệu quả tương tự của việc lưu văn bản trong hình ảnh cộng đầy đủ trong nhị phân, nhưng tôi không nghĩ đó là khả năng – JoeSharp

Trả lời

2

Tin tốt. Tôi đã phải làm việc trên một cái gì đó khác trong một thời gian, nhưng điều này cho phép tôi quay trở lại với một đôi mắt mới. Tôi nhanh chóng nhận ra rằng tôi chỉ có thể kết hợp những gì tôi biết là làm việc. Tôi nghi ngờ giải pháp này sẽ giành được bất kỳ giải thưởng nào, nhưng nó hoạt động. Tôi biết rằng tôi có thể bọc một FlowDocument lên như văn bản bằng cách sử dụng XamlReader, giữ các yếu tố hình ảnh nhưng mất dữ liệu hình ảnh. Tôi cũng biết rằng tôi có thể biến FlowDocument thành nhị phân bằng XamlFormat. Vì vậy, tôi đã có ý tưởng lấy FlowDocument và sử dụng một hàm tôi đã viết để lặp qua nó để tìm hình ảnh, tôi lấy từng hình ảnh, về cơ bản sao chép và đặt bản sao vào FlowDocument mới. Tôi lấy FlowDocument mới mà bây giờ chứa hình ảnh đơn, biến nó thành nhị phân, và sau đó lấy kết quả nhị phân, biến nó thành chuỗi base64 và dán nó vào thuộc tính thẻ của hình ảnh trong FlowDocument gốc. Điều này sẽ giữ dữ liệu hình ảnh trong FlowDocument gốc dưới dạng văn bản. Bằng cách này, tôi có thể chuyển FlowDocument với dữ liệu hình ảnh (mà tôi gọi là Định dạng SUBString) vào XamlReader để tìm kiếm văn bản.Khi nó ra khỏi cơ sở dữ liệu, tôi kéo FlowDocument ra khỏi Xaml như bình thường, nhưng sau đó lặp qua từng hình ảnh, trích xuất dữ liệu từ thuộc tính thẻ bằng XamlFormat và sau đó tạo một bản sao khác để cung cấp thuộc tính Nguồn cho thực tế của tôi hình ảnh. Tôi đã cung cấp các bước để truy cập định dạng SUBString bên dưới.

/// <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()); 
     } 
    } 
0

Lưu hình ảnh của bạn vào MemoryStream và ghi luồng đó vào tệp XML của bạn.

Luồng bộ nhớ sẽ chuyển đổi nó thành Byte [].

+1

Cảm ơn bạn đã trả lời Tony . Vấn đề là hình ảnh là một đối tượng System.Windows.Controls.Image. Tôi tiếp tục di chuyển xuống hệ thống phân cấp nhưng không thể tìm thấy đối tượng con nào mà các byte được lưu trữ. Tôi đã thử lưu đối tượng BitmapImage vào luồng bộ nhớ, nhưng tất cả những gì tôi nhận được là thẻ xaml. sử dụng (MemoryStream ms = new MemoryStream()) { XamlWriter.Save (bi, ms); result = ms.ToArray(); } – JoeSharp

+0

Kết quả: JoeSharp

+0

bạn có thể đăng toàn bộ mã không? –

0

Đây là đoạn mã mẫu cho cả hai lời đề nghị của tôi mà tôi đã thực hiện rồi, bị bệnh phải nhìn vào vấn đề tải trọng nếu ví dụ của tôi không làm việc ...

 // 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; 
    } 
+1

Cách đầu tiên dường như không hoạt động. BaseUri là "gói: // payload: ,, wpf2,/Xaml/Document.xaml" và UriSource là "./Image1.bmp". Kết hợp chúng kết quả trong "gói: \ payload: ,, wpf2, \ Xaml \ ./ Image1.bmp". Tôi đã thử một hỗn hợp của việc loại bỏ các dấu chấm trong đường dẫn Image1.bmp. Thậm chí không chắc chắn nơi mà dấu chấm đó được cho là chỉ đến. Giải pháp thứ hai có vẻ như nó bắt đầu hoạt động, nhưng khi mảng byte trở lại, khi tôi cố gắng thêm nó vào XML, tôi thử mã hóa ascii và tôi nhận được lỗi này: '.', Giá trị thập lục phân 0x00 , là một ký tự không hợp lệ. (xem GetImagesXML() của tôi trong câu hỏi) – JoeSharp

+0

Tôi không quá quen thuộc với thuộc tính sải chân. Tôi biết chiều rộng của hình ảnh theo byte, nhưng bạn có thể giải thích ngắn gọn về toán học đang diễn ra trong dòng đó không, "7" xuất phát từ đâu? Cảm ơn – JoeSharp

+1

lỗi xảy ra là vì bạn đang sử dụng mã hóa ASCII để chuyển đổi mảng byte thành dạng ASCII của nó, hãy thử sử dụng Convert.ToBase64String (/ * byte [] * /) để chuyển đổi mảng byte thành chuỗi base64 –

Các vấn đề liên quan