我有代码将图片从剪贴板导入RichtTextBox。
Image i = new Image();
i.Source = Clipboard.GetImage();
paragraph.Inlines.Add(i);
当我尝试删除图像并按下撤销()时,我有例外。
在类型上找不到匹配的构造函数 ' System.Windows.Interop.InteropBitmap&#39 ;.您可以使用参数或 FactoryMethod指令构造此类型。'行号' 1'和 行位置' 226'。
这是因为RichTextBox生成的XAML如下所示:
<Image.Source><swi:InteropBitmap /></Image.Source>
我尝试将BitmapSource的类型更改为BitmapImage。但在这种情况下,我有XAML:
<Image.Source><BitmapImage BaseUri="{x:Null}" /></Image.Source></Image>
删除后,撤消我有异常:
抛出异常:&#39; System.Windows.Markup.XamlParseException&#39;在 PresentationFramework.dll
其他信息:&#39; System.Windows.Media.Imaging.BitmapImage&#39;的初始化抛出异常。&#39;线 数字&#39; 1&#39;和行位置&#39; 243&#39;。
我甚至尝试了来自http://wpftutorial.net/InlineImagesXaml.html
的InlineImage<InlineImage Width="100" Height="100" Stretch="Fill">
<![CDATA[iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAB3RJTUUH2AQP
SFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAAnOSURBVHjaxVcLcBvVFT1vV
ki3Hju3GCQnGjkObONQkJkxCSIHQQGnIdEr5TFs+LaGl7RRCSUvDp8nglH4mDGQ6EwZIm=]]>
</InlineImage>
即使在这种情况下,我在撤消/重做操作中也有例外。有没有可能没有编写自己的撤销/重做操作来处理这种情况。
答案 0 :(得分:1)
我很困惑天气编辑旧答案或添加新答案。所以我要换一个新的。
使用下面的方法我现在可以复制现有的图像文件并将其粘贴到RTB中,我现在也可以从MSPaint,Photoshop复制一些未保存的图像数据并粘贴它。按下“保存”按钮后,将保存rtf文件并按预期在MSWord中正常打开。
Ctrl + Z不起作用,因为图像数据在流中。我正在做。将图像复制为文件时,Ctrl + Z不是问题。
最受欢迎的是怀疑。以下代码完整可以按原样使用。
用于获取存储在剪贴板中的图像的ImageCode.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows;
using System.Runtime.InteropServices;
namespace WpfRichTextBox._32648134
{
public class ImageCode
{
public static ImageSource ImageFromClipboardDibAsSource()
{
MemoryStream ms = Clipboard.GetData("DeviceIndependentBitmap") as MemoryStream;
if (ms != null)
{
byte[] dibBuffer = new byte[ms.Length];
ms.Read(dibBuffer, 0, dibBuffer.Length);
BITMAPINFOHEADER infoHeader =
BinaryStructConverter.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
int infoHeaderSize = infoHeader.biSize;
int fileSize = fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage;
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER();
fileHeader.bfType = BITMAPFILEHEADER.BM;
fileHeader.bfSize = fileSize;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4;
byte[] fileHeaderBytes =
BinaryStructConverter.ToByteArray<BITMAPFILEHEADER>(fileHeader);
MemoryStream msBitmap = new MemoryStream();
msBitmap.Write(fileHeaderBytes, 0, fileHeaderSize);
msBitmap.Write(dibBuffer, 0, dibBuffer.Length);
msBitmap.Seek(0, SeekOrigin.Begin);
BitmapImage img = new BitmapImage();
img.BeginInit();
img.CacheOption = BitmapCacheOption.OnDemand;
img.CreateOptions = BitmapCreateOptions.DelayCreation;
img.StreamSource = msBitmap;
img.EndInit();
return img;
}
return null;
}
public static MemoryStream ImageFromClipboardDibAsStream()
{
MemoryStream ms = Clipboard.GetData("DeviceIndependentBitmap") as MemoryStream;
if (ms != null)
{
byte[] dibBuffer = new byte[ms.Length];
ms.Read(dibBuffer, 0, dibBuffer.Length);
BITMAPINFOHEADER infoHeader =
BinaryStructConverter.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
int infoHeaderSize = infoHeader.biSize;
int fileSize = fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage;
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER();
fileHeader.bfType = BITMAPFILEHEADER.BM;
fileHeader.bfSize = fileSize;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4;
byte[] fileHeaderBytes =
BinaryStructConverter.ToByteArray<BITMAPFILEHEADER>(fileHeader);
MemoryStream msBitmap = new MemoryStream();
msBitmap.Write(fileHeaderBytes, 0, fileHeaderSize);
msBitmap.Write(dibBuffer, 0, dibBuffer.Length);
msBitmap.Seek(0, SeekOrigin.Begin);
return msBitmap;
}
return null;
}
}
public static class BinaryStructConverter
{
public static T FromByteArray<T>(byte[] bytes) where T : struct
{
IntPtr ptr = IntPtr.Zero;
try
{
int size = Marshal.SizeOf(typeof(T));
ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, ptr, size);
object obj = Marshal.PtrToStructure(ptr, typeof(T));
return (T)obj;
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
}
public static byte[] ToByteArray<T>(T obj) where T : struct
{
IntPtr ptr = IntPtr.Zero;
try
{
int size = Marshal.SizeOf(typeof(T));
ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, ptr, true);
byte[] bytes = new byte[size];
Marshal.Copy(ptr, bytes, 0, size);
return bytes;
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
}
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
struct BITMAPFILEHEADER
{
public static readonly short BM = 0x4d42; // BM
public short bfType;
public int bfSize;
public short bfReserved1;
public short bfReserved2;
public int bfOffBits;
}
[StructLayout(LayoutKind.Sequential)]
struct BITMAPINFOHEADER
{
public int biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;
public int biCompression;
public int biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public int biClrUsed;
public int biClrImportant;
}
}
MainWindow.xaml
<Window x:Class="WpfRichTextBox._32648134.Win32648134"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Win32648134" Height="600" Width="700">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="41*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="21*"/>
</Grid.RowDefinitions>
<RichTextBox x:Name="RtbCompose" Width="500" Height="300" ScrollViewer.VerticalScrollBarVisibility="Visible">
<FlowDocument x:Name="FdDocument">
<Paragraph x:Name="Para1"></Paragraph>
</FlowDocument>
</RichTextBox>
<Button x:Name="BtnCopyImgFile" Content="Paste image" HorizontalAlignment="Left" Margin="96,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="75" Click="BtnCopyImgFile_Click"/>
<Button x:Name="BtnSave" Content="Save" HorizontalAlignment="Left" Grid.Row="1" VerticalAlignment="Top" Width="75" Margin="521,10,0,0" Click="BtnSave_Click"/>
<Button x:Name="BtnCopyImgData" Content="Paste image data" HorizontalAlignment="Left" Margin="190,11,0,0" Grid.Row="1" VerticalAlignment="Top" Click="BtnCopyImgData_Click"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Diagnostics;
using System.IO;
namespace WpfRichTextBox._32648134
{
/// <summary>
/// Interaction logic for Win32648134.xaml
/// </summary>
public partial class Win32648134 : Window
{
public Win32648134()
{
InitializeComponent();
}
private void BtnCopyImgFile_Click(object sender, RoutedEventArgs e)
{
Image i = new Image();
if (Clipboard.ContainsFileDropList())
{
StringCollection fileNames = Clipboard.GetFileDropList();
BitmapImage img = new BitmapImage(new Uri(fileNames[0], UriKind.Absolute));
i.Source = img;
Para1.Inlines.Add(i);
}
Para1.Inlines.Add(new Run("first rtb app"));
}
private void BtnSave_Click(object sender, RoutedEventArgs e)
{
TextRange allText = new TextRange(RtbCompose.Document.ContentStart, RtbCompose.Document.ContentEnd);
FileStream stream = new FileStream(@"I:\RTB.rtf", FileMode.Create);
allText.Save(stream, DataFormats.Rtf);
if (stream != null)
stream.Close();
}
private void BtnCopyImgData_Click(object sender, RoutedEventArgs e)
{
bool hasImgData = Clipboard.ContainsImage();
Image i = new Image();
if (hasImgData)
{
BitmapSource imgData = (BitmapSource)ImageCode.ImageFromClipboardDibAsSource();
i.Source = imgData;
Para1.Inlines.Add(i);
}
Para1.Inlines.Add(new Run("rtb app, image comes from image data instead of file"));
}
}
}
答案 1 :(得分:0)
我找到了解决方案。我不得不从RichTextBox源代码中复制类WpfLoad。此代码将Package保存为Stream,其中Image为Content,Uri为文档的源。
因为类WpfPayload是内部的,所以我无权访问此类。我需要创建自己的。
以下是WpfPayLoad类的来源。
NoClassDefFoundError
接下来,如果我们在RichTextBox下面:
Foo bar = new Foo ();
System.out.println(Foo.class.getName());
System.out.println(bar.getClass().getName());
在Button_Click上我们可以从ClipBoard保存我们的图像。首先我得到了包的流,然后我们可以将它转换为XamlReader.Load()。
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Markup;
using System.Windows.Media.Imaging;
namespace YATE
{
internal class WpfPayload
{
private const string XamlPayloadDirectory = "/Xaml"; //
private const string XamlEntryName = "/Document.xaml"; //
private const string XamlContentType = "application/vnd.ms-wpf.xaml+xml";
private const string XamlImageName = "/Image"; //
private const string XamlRelationshipFromPackageToEntryPart = "http://schemas.microsoft.com/wpf/2005/10/xaml/entry";
private const string XamlRelationshipFromXamlPartToComponentPart = "http://schemas.microsoft.com/wpf/2005/10/xaml/component";
internal const string ImageBmpContentType = "image/bmp";
private const string ImageGifContentType = "image/gif";
private const string ImageJpegContentType = "image/jpeg";
private const string ImageTiffContentType = "image/tiff";
private const string ImagePngContentType = "image/png";
private const string ImageBmpFileExtension = ".bmp";
private const string ImageGifFileExtension = ".gif";
private const string ImageJpegFileExtension = ".jpeg";
private const string ImageJpgFileExtension = ".jpg";
private const string ImageTiffFileExtension = ".tiff";
private const string ImagePngFileExtension = ".png";
Package _package = null;
private static BitmapEncoder GetBitmapEncoder(string imageContentType)
{
BitmapEncoder bitmapEncoder;
switch (imageContentType)
{
case ImageBmpContentType:
bitmapEncoder = new BmpBitmapEncoder();
break;
case ImageGifContentType:
bitmapEncoder = new GifBitmapEncoder();
break;
case ImageJpegContentType:
bitmapEncoder = new JpegBitmapEncoder();
//
break;
case ImageTiffContentType:
bitmapEncoder = new TiffBitmapEncoder();
break;
case ImagePngContentType:
bitmapEncoder = new PngBitmapEncoder();
break;
default:
bitmapEncoder = null;
break;
}
return bitmapEncoder;
}
// Returns a file extension corresponding to a given imageContentType
private static string GetImageFileExtension(string imageContentType)
{
string imageFileExtension;
switch (imageContentType)
{
case ImageBmpContentType:
imageFileExtension = ImageBmpFileExtension;
break;
case ImageGifContentType:
imageFileExtension = ImageGifFileExtension;
break;
case ImageJpegContentType:
imageFileExtension = ImageJpegFileExtension;
break;
case ImageTiffContentType:
imageFileExtension = ImageTiffFileExtension;
break;
case ImagePngContentType:
imageFileExtension = ImagePngFileExtension;
break;
default:
imageFileExtension = null;
break;
}
return imageFileExtension;
}
WpfPayload(Package p = null)
{
this._package = p;
}
private Package CreatePackage(Stream stream)
{
_package = Package.Open(stream, FileMode.Create, FileAccess.ReadWrite);
return _package;
}
// Generates a image part Uri for the given image index
private static string GetImageName(int imageIndex, string imageContentType)
{
string imageFileExtension = GetImageFileExtension(imageContentType);
return XamlImageName + (imageIndex + 1) + imageFileExtension;
}
// Generates a relative URL for using from within xaml Image tag.
private static string GetImageReference(string imageName)
{
return "." + imageName; // imageName is supposed to be created by GetImageName method
}
private PackagePart CreateWpfEntryPart()
{
// Define an entry part uri
Uri entryPartUri = new Uri(XamlPayloadDirectory + XamlEntryName, UriKind.Relative);
// Create the main xaml part
PackagePart part = _package.CreatePart(entryPartUri, XamlContentType, CompressionOption.Normal);
// Compression is turned off in this mode.
//NotCompressed = -1,
// Compression is optimized for a resonable compromise between size and performance.
//Normal = 0,
// Compression is optimized for size.
//Maximum = 1,
// Compression is optimized for performance.
//Fast = 2 ,
// Compression is optimized for super performance.
//SuperFast = 3,
// Create the relationship referring to the entry part
PackageRelationship entryRelationship = _package.CreateRelationship(entryPartUri, TargetMode.Internal, XamlRelationshipFromPackageToEntryPart);
return part;
}
private void CreateImagePart(PackagePart sourcePart, BitmapSource imageSource, string imageContentType, int imageIndex)
{
// Generate a new unique image part name
string imagePartUriString = GetImageName(imageIndex, imageContentType);
// Define an image part uri
Uri imagePartUri = new Uri(XamlPayloadDirectory + imagePartUriString, UriKind.Relative);
// Create a part for the image
PackagePart imagePart = _package.CreatePart(imagePartUri, imageContentType, CompressionOption.NotCompressed);
// Create the relationship referring from the enrty part to the image part
PackageRelationship componentRelationship = sourcePart.CreateRelationship(imagePartUri, TargetMode.Internal, XamlRelationshipFromXamlPartToComponentPart);
// Encode the image data
BitmapEncoder bitmapEncoder = GetBitmapEncoder(imageContentType);
bitmapEncoder.Frames.Add(BitmapFrame.Create(imageSource));
// Save encoded image data into the image part in the package
Stream imageStream = imagePart.GetStream();
using (imageStream)
{
bitmapEncoder.Save(imageStream);
}
}
internal PackagePart GetWpfEntryPart()
{
PackagePart wpfEntryPart = null;
// Find a relationship to entry part
PackageRelationshipCollection entryPartRelationships = _package.GetRelationshipsByType(XamlRelationshipFromPackageToEntryPart);
PackageRelationship entryPartRelationship = null;
foreach (PackageRelationship packageRelationship in entryPartRelationships)
{
entryPartRelationship = packageRelationship;
break;
}
// Get a part referred by this relationship
if (entryPartRelationship != null)
{
// Get entry part uri
Uri entryPartUri = entryPartRelationship.TargetUri;
// Get the enrty part
wpfEntryPart = _package.GetPart(entryPartUri);
}
return wpfEntryPart;
}
[System.Security.SecurityCritical]
internal static Stream SaveImage(BitmapSource bitmapSource, string imageContentType)
{
MemoryStream stream = new MemoryStream();
// Create the wpf package in the stream
WpfPayload wpfPayload = new WpfPayload();
using (wpfPayload.CreatePackage(stream))
{
PackagePart xamlEntryPart = wpfPayload.CreateWpfEntryPart();
Stream xamlPartStream = xamlEntryPart.GetStream();
using (xamlPartStream)
{
int imageIndex = 0;
string imageReference = GetImageReference(GetImageName(imageIndex, imageContentType));
StreamWriter xamlPartWriter = new StreamWriter(xamlPartStream);
using (xamlPartWriter)
{
string xamlText =
"<Span xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">" +
"<InlineUIContainer><Image " +
"Width=\"" +
bitmapSource.Width + "\" " +
"Height=\"" +
bitmapSource.Height + "\" " +
"><Image.Source><BitmapImage CacheOption=\"OnLoad\" UriSource=\"" +
imageReference +
"\"/></Image.Source></Image></InlineUIContainer></Span>";
xamlPartWriter.Write(xamlText);
}
wpfPayload.CreateImagePart(xamlEntryPart, bitmapSource, imageContentType, imageIndex);
}
}
return stream;
}
static int _wpfPayloadCount; // used to disambiguate between all acts of loading from different WPF payloads.
internal static object LoadElement(Stream stream)
{
Package package = Package.Open(stream, FileMode.Open, FileAccess.Read);
WpfPayload wpfPayload = new WpfPayload(package);
PackagePart xamlEntryPart = wpfPayload.GetWpfEntryPart();
int newWpfPayoutCount = _wpfPayloadCount++;
Uri payloadUri = new Uri("payload://wpf" + newWpfPayoutCount, UriKind.Absolute);
Uri entryPartUri = PackUriHelper.Create(payloadUri, xamlEntryPart.Uri); // gives an absolute uri of the entry part
Uri packageUri = PackUriHelper.GetPackageUri(entryPartUri); // extracts package uri from combined package+part uri
PackageStore.AddPackage(packageUri, wpfPayload.Package); // Register the package
ParserContext parserContext = new ParserContext();
parserContext.BaseUri = entryPartUri;
object xamlObject = XamlReader.Load(xamlEntryPart.GetStream(), parserContext);
// Remove the temporary uri from the PackageStore
PackageStore.RemovePackage(packageUri);
return xamlObject;
}
public Package Package
{
get { return _package; }
}
};
}
我们可以使用XAMLPackage保存结果。
<RichTextBox x:Name="RtbCompose" Width="500" Height="300">
<FlowDocument x:Name="FdDocument">
<Paragraph x:Name="Para1"></Paragraph>
</FlowDocument>
</RichTextBox>
<Button Content="Paste image" HorizontalAlignment="Left" Margin="96,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
使用此解决方案,Undo()和Redo()可以正常工作:)