Word Interop - Сохранить встроенную форму как изображение - PullRequest
1 голос
/ 30 апреля 2020

Я пытаюсь сохранить внедренную форму как изображение, используя C#.

Если объект внедрен как фактическое изображение (WMF / JPEG), я могу получить изображение без проблем, но когда объект представляет собой встроенную фигуру или объект OLE, который отображается как изображение в Word, я не могу извлечь или извлечь указанный объект, чтобы затем скопировать его в буфер обмена или сохранить указанное изображение.

Вот мой текущий пример кода; либо объект пуст, либо я получаю следующую ошибку:

System.Runtime.InteropServices.ExternalException: 'A generic error occurred in GDI+.'

Любая помощь приветствуется. Спасибо

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ImageMagickSandboxWinForms
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        public static BitmapSource ConvertBitmap(Bitmap source)
        {
            return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                          source.GetHbitmap(),
                          IntPtr.Zero,
                          Int32Rect.Empty,
                          BitmapSizeOptions.FromEmptyOptions());
        }

        public static Bitmap BitmapFromSource(BitmapSource bitmapsource)
        {
            Bitmap bitmap;
            using (var outStream = new MemoryStream())
            {
                BitmapEncoder enc = new BmpBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(bitmapsource));
                enc.Save(outStream);
                bitmap = new Bitmap(outStream);
            }
            return bitmap;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string physicsDocLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
            physicsDocLocation += @"\[Doc path Here].docx";
            var wordApp = new Microsoft.Office.Interop.Word.Application();

            var wordDoc = wordApp.Documents.Open(physicsDocLocation);
            int iCount = wordDoc.InlineShapes.Count;
            for (int i = 1; i < (wordDoc.InlineShapes.Count + 1); i++)
            {
                var currentInlineShape = wordDoc.InlineShapes[i];
                currentInlineShape.Range.Select();
                wordDoc.ActiveWindow.Selection.Range.Copy();
                BitmapSource clipBoardImage = System.Windows.Clipboard.GetImage();
                Bitmap bmpClipImage = BitmapFromSource(clipBoardImage);
                string finalPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), @"TestConversions");
                finalPath += @"\" + Guid.NewGuid().ToString() + ".jpg";
                using (MemoryStream memory = new MemoryStream())
                {
                    using (FileStream fs = new FileStream(finalPath, FileMode.Create, FileAccess.ReadWrite))
                    {
                        bmpClipImage.Save(memory, ImageFormat.Jpeg); <<<---- Error happens here.
                        byte[] bytes = memory.ToArray();
                        fs.Write(bytes, 0, bytes.Length);
                    }
                }
            }
            wordDoc.Close();
            wordApp.Quit();
        }
    }
}

1 Ответ

0 голосов
/ 30 апреля 2020

у меня есть этот код в моей библиотеке, не знаю, где я нашел это, но надеюсь, что вы сделаете всю работу за вас: я использую Clippboard для захвата различных изображений, просто не забудьте, для доступа к буферу обмена необходима нить

       for (var i = 1; i <= wordApplication.ActiveDocument.InlineShapes.Count; i++)
        {

            var inlineShapeId = i; 


            var thread = new Thread(() => SaveInlineShapeToFile(inlineShapeId, wordApplication));

            // STA is needed in order to access the clipboard
            // https://stackoverflow.com/a/518724/700926
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            thread.Join();
        }

   // General idea is based on: https://stackoverflow.com/a/7937590/700926
    protected static void SaveInlineShapeToFile(int inlineShapeId, Application wordApplication)
    {
        // Get the shape, select, and copy it to the clipboard
        var inlineShape = wordApplication.ActiveDocument.InlineShapes[inlineShapeId];
        inlineShape.Select();
        wordApplication.Selection.Copy();

        // Check data is in the clipboard
        if (Clipboard.GetDataObject() != null)
        {
            var data = Clipboard.GetDataObject();

            // Check if the data conforms to a bitmap format
            if (data != null && data.GetDataPresent(DataFormats.Bitmap))
            {
                // Fetch the image and convert it to a Bitmap
                var image = (Image) data.GetData(DataFormats.Bitmap, true);
                var currentBitmap = new Bitmap(image);

                // Save the bitmap to a file
                currentBitmap.Save(@"C:\Users\Username\Documents\" + String.Format("img_{0}.png", inlineShapeId));
            }
        }
    }

следующее, если вы используете Winform или WPF, буфер обмена для изображения действует по-разному:

if (Clipboard.ContainsImage())
{
// ImageUIElement.Source = Clipboard.GetImage(); // does not work
    System.Windows.Forms.IDataObject clipboardData = System.Windows.Forms.Clipboard.GetDataObject();
  if (clipboardData != null)
  {
    if (clipboardData.GetDataPresent(System.Windows.Forms.DataFormats.Bitmap))
    {
        System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)clipboardData.GetData(System.Windows.Forms.DataFormats.Bitmap);
        ImageUIElement.Source =  System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
        Console.WriteLine("Clipboard copied to UIElement");
    }
  }
}

после, если он не функционирует из-за ошибки в переводе формата, есть это решение . Таким образом, это легко, но легко понять логику c использования "DeviceIndependentBitmap"

...