引:
这个系列将会记录工作中遇到的一些疑难问题,并贴出自己的解决方案。因为本人水平仍在入门级别徘徊,如有更好方案,望高手指点。
问题来源:
公司在做的项目中,需要用到文本编辑器,实现粘贴文本、图片等功能,类似网页中的FCKEditor。处理图片时,我们需要缩略显示图片,并把图片发送到服务器。
问题在这里,我们以xaml读取RichTextBox的内容时,发现其图片标签的地址极其怪异,如下:
<BlockUIContainer TextAlignment="Justify">
<Image Width="553" Height="415">
<Image.Source>
<BitmapImage BaseUri="pack://payload:,,wpf1,/Xaml/Document.xaml" UriSource="./Image1.bmp" CacheOption="OnLoad" />
</Image.Source>
</Image>
</BlockUIContainer>
</FlowDocument>
其中有BaseUri="pack://payload:,,wpf1,/Xaml/Document.xaml" UriSource="./Image1.bmp",猜测图片是被保存在某个临时文件夹中 ,但是无法定位。
解决思路一:
既然图片是粘贴进来的,我们应该能在RichTextBox的粘贴命令时即对图片进行处理。于是使用了WPF的ClipBoard,把图片保存到本地后,再插入RichTextBox中。大致代码如下:
{
if (Clipboard.ContainsData(DataFormats.Bitmap))
{
BitmapSource bitmap = Clipboard.GetImage();
System.Drawing.Bitmap b = BitmapToBitmap(bitmap, ".bmp");
string path = Constants.SYSTEM.TEMP_DATA_PATH + Guid.NewGuid().ToString() + ".bmp";
b.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
b.Dispose();
//添加到控件中
InsertImage(path, path, this.Document);
args.Handled = true;
return;
}
}
但这个方案的问题在于,如果我以图文混排方式粘贴的话,文本就会丢失。
有人会说,那你用Clipboard.GetText(); 拿文本嘛。我当然试了,但是这样会把图片和文本分开,即图片和文字的位置关系没办法处理。
解决思路二:
刚刚开始考虑这个问题时想到过RTF,又惮于RTF格式的复杂。
但是RTF给RichTextBox赋值显示又是好的,所以想到一个取巧的办法,先在内存中实例化一个RichTextBox,将ClipBord内的RTF格式数据赋给它,再对它的Document进行解析。
IDataObject iData = Clipboard.GetDataObject();
//内存内实例化一个RichTextBox
System.Windows.Controls.RichTextBox rtb = new System.Windows.Controls.RichTextBox();
//rtf格式
if (iData.GetDataPresent(DataFormats.Rtf))
{
var rtf = iData.GetData(DataFormats.Rtf);
//将rtf载入内存内的RichTextBox
TextRange textRange = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);
using (MemoryStream rtfMemoryStream = new MemoryStream())
{
using (StreamWriter rtfStreamWriter = new StreamWriter(rtfMemoryStream))
{
rtfStreamWriter.Write(rtf);
rtfStreamWriter.Flush();
rtfMemoryStream.Seek(0, SeekOrigin.Begin);
//Load the MemoryStream into TextRange ranging from start to end of RichTextBox.
textRange.Load(rtfMemoryStream, DataFormats.Rtf);
}
}
}
这样就又可以利用 System.Windows.Markup.XamlWriter.Save();将其保存为xaml处理。起码可以分析它的节点了。
这里我们又回到了问题来源时列出的文件格式,在对图片处理时用到了一个转换:
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.BaseUri = new Uri(bmpNode.Attributes["BaseUri"].Value);
bitmap.UriSource = new Uri(bmpNode.Attributes["UriSource"].Value, UriKind.Relative);
bitmap.EndInit();
BitmapSource bsrc = (BitmapSource)bitmap;
PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(bsrc));
imgName = Constants.SYSTEM.TEMP_DATA_PATH + "\\" + bmpNode.Attributes["UriSource"].Value.Replace("./", "");
if (File.Exists(imgName))
{
File.Delete(imgName);
}
using (Stream stream = File.Create(imgName))
{
png.Save(stream);
}
这样图片即是可控的,很方便地对它进行处理。
但是这个方法处理来,性能损耗很大,希望高手能给出更好的解决方案。