首页 > 其他分享 >DevExpress(WinForms & WPF)中文教程 - 如何减小文档文件大小?

DevExpress(WinForms & WPF)中文教程 - 如何减小文档文件大小?

时间:2024-07-10 10:10:21浏览次数:10  
标签:DevExpress image shape WinForms 文档 PictureFormat 图像 WPF document

DevExpress拥有.NET开发需要的所有平台控件,包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。屡获大奖的软件开发平台DevExpress近期重要版本v24.1已正式发布,该版本拥有众多新产品和数十个具有高影响力的功能,可为桌面、Web和移动应用提供直观的解决方案,全面解决各种使用场景问题。

减小文档文件大小可以改善文档导入/处理相关操作,它还可以帮助最小化数据库和云服务器中的文件存储需求。在这篇文章中,我们将使用DevExpress(WinForms & WPF) Word Processing API来减少Microsoft Word文档文件大小的不同策略。

重要提示:下面列出的策略涉及删除文档内容,删除的内容将无法恢复。

获取DevExpress v24.1正式版下载

DevExpress技术交流群10:532598169      欢迎一起进群讨论

简化文档

虽然显而易见,文档简化是减少/优化文件大小的最佳方法,简化策略包括:

  • 在可能的情况下,使用一组有限的样式来格式化文档内容。
  • 将文档从DOCM格式转换为DOCX格式来消除宏,您也可以使用RichEditDocumentServer.Options.DocumentCapabilities.Macros 选项来禁用宏。
  • 在保存文档之前禁用跟踪更改,RichEditDocumentServer包含RichEditDocumentServer.Options.DocumentCapabilities.TrackChanges属性用于禁用跟踪。
  • 减少图像内容。
  • 使用链接OLE对象代替嵌入OLE对象,如果无法使用链接的OLE对象,可以减小嵌入OLE对象的大小或在保存之前将其删除。有关OLE对象支持的其他信息,请参阅以下文章:OLE Objects in Word Documents
  • 减少字段和内容控件的使用,在保存之前取消链接或删除字段。
  • 用压缩图像替换图表。
  • 删除额外的元数据(XML数据、文档属性、注释、RTF主题数据)。
  • 将长表划分为多个短表,在大多数情况下,长表不会影响文件大小,但会减慢文档呈现和布局计算。
使用OpenXML格式替代传统格式

OpenXML格式(DOCX)是现代的、开放的、跨多个平台兼容的,虽然在某些情况下更有效,但遗留格式(如DOC、RTF)是专有的,灵活性较差。OpenXML文件本质上是带有XML文件和附加资源(如图像和样式)的ZIP存档,因此DOCX文件更容易存储在数据库中,您可以使用RichEditDocumentServer.Save 方法将文档转换为所需的文件格式。

不要嵌入字体

DevExpress Word Processing Document API允许您在文档中嵌入字体,虽然具有嵌入式字体的文档在不同的计算设备上保持外观特征,但这些文档的大小要大得多。如果您的解决方案在受控/托管环境中显示文档,我们建议使用DevExpress DXFontRepository类。有关更多信息,请参阅以下帮助主题:Load and Use Custom Fonts Without Installation on the System

减小图像大小

您可以使用第三方应用程序来压缩文档图像,一旦压缩,只需要调用PictureFormat.SetPicture方法将原始图像替换为其压缩后的等效图像。

下面的代码片段将原始图像替换为压缩后的等效图像:

using (RichEditDocumentServer wordProcessor = new RichEditDocumentServer()) {
wordProcessor.LoadDocument("doc_with_images.docx");
Document document = wordProcessor.Document;
Shape shape = document.Shapes[0];
DXImage sourceImage = shape.PictureFormat.Picture.DXImage;
MemoryStream imageStream = new MemoryStream();
sourceImage.Save(stream);
//Compress the image saved in the stream
//...
DXImage compressedImage = DXImage.FromStream(updatedImageStream);
shape.PictureFormat.SetPicture(compressedImage);
}

另一个技巧是不要裁剪图像,使用保存的预裁剪版本。您可以使用PictureFormat.SourceRect属性在代码中裁剪图像,然后保存输出,PictureFormatSetPicture方法允许您将图像替换为裁剪后的版本。

下面的代码片段裁剪图像,保存它,然后用裁剪后的等效图像替换原始图像:

using (RichEditDocumentServer wordProcessor = new RichEditDocumentServer()) {
wordProcessor.LoadDocument("CroppedImages.docx");
Document document = wordProcessor.Document;
Shape shape = document.Shapes[0];
if (shape.PictureFormat != null) {
DXBitmap image = shape.PictureFormat.Picture.DXImage as DXBitmap;
var rectOffset = shape.PictureFormat.SourceRect;
RectangleF imageRect = new RectangleF(image.Width * rectOffset.LeftOffset,
image.Height * rectOffset.TopOffset,
image.Width - image.Width * rectOffset.LeftOffset - image.Width * rectOffset.RightOffset,
image.Height - image.Height * rectOffset.TopOffset - image.Height * rectOffset.BottomOffset);
MemoryStream imageStream = new MemoryStream();
image.Crop(imageRect).Save(imageStream, image.ImageFormat);
DocumentImageSource source = DocumentImageSource.FromStream(imageStream);
shape.PictureFormat.SetPicture(source);
shape.PictureFormat.SourceRect = new RectangleOffset();
}
}

如果需要使用大图像,并且应用程序架构允许您单独存储图像,则可以采用以下解决方案。迭代文档的形状集合,并将所有图像保存到具有唯一标识符的数据库中。完成后,用空图像或DOCVARIABLE字段(用于动态图像替换)替换原始文档图像,或者删除图像并用书签标记其在文档中的位置。通过使用此策略,您将能够保存文档的轻量级版本,并在必要时恢复原始文档图像:

Document document = wordProcessor.Document;
// iterate through document images, save them to the database
// and replace original images with an empty image
int imageID = 1; // generate an image ID as you require
DocumentImageSource emptyImageSource = DocumentImageSource.FromImage(new DXBitmap(1, 1));
for (int i = document.Shapes.Count - 1; i >= 0; i--)
{
Shape shape = document.Shapes[i];
if (shape.PictureFormat != null)
{
DXBitmap image = shape.PictureFormat.Picture.DXImage as DXBitmap;
using (MemoryStream imageStream = new MemoryStream()) {
image.Save(imageStream, image.ImageFormat);
byte[] imageBytes = imageStream.ToArray();
// save image bytes to the database with the specified image ID
// ...
// change the image name (if required) to identify it later
shape.Name = "Image " + imageID.ToString();
// replace the current image with the empty image
shape.PictureFormat.SetPicture(emptyImageSource);
}
imageID++;
}
}
// save the document with dummy images
using (MemoryStream documentStream = new MemoryStream())
document.SaveDocument(documentStream, DocumentFormat.OpenXml);

//...
// restore document images
richEditControl.LoadDocument(documentStream, DocumentFormat.OpenXml);
Document document = richEditControl.Document;
for (int i = document.Shapes.Count - 1; i >= 0; i--)
{
Shape shape = document.Shapes[i];
if (shape.PictureFormat != null)
{
string imageName = shape.Name;
// extract the required image from the database by name
byte[] imageBytes = ...;
using(MemoryStream imageStream = new MemoryStream(imageBytes))
{
// replace the empty image with the original image
DocumentImageSource imageSource = DocumentImageSource.FromStream(imageStream);
shape.PictureFormat.SetPicture(imageSource);
}
}
}

标签:DevExpress,image,shape,WinForms,文档,PictureFormat,图像,WPF,document
From: https://www.cnblogs.com/AABBbaby/p/18293307

相关文章

  • Simple WPF: WPF实现一个MINIO等S3兼容对象存储上传文件的小工具
    最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。创作不易,如果觉得有用请在Github上为博主点亮一颗小星星吧!目的之前在阿里云ECS99元/年的活动实例上搭建了一个测试用的MINIO服务,以前都是直接当基础设施来使用的,这次准备自己学一下S3兼容API相关的对象存储开......
  • Simple WPF: C# Task异步任务的取消初探
    最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。创作不易,如果觉得有用请在Github上为博主点亮一颗小星星吧!C#中提供了CancellationTokenSource来实现Task的取消,方法就是在Task异步循环中检测任务是否被取消。最近正在学习C#的任务异步模型,因此撰文以记之。......
  • WPF MouseWheel MouseDown MouseUp MouseMove mapped in mvvm via behavior
    //xaml<Windowx:Class="WpfApp201.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mi......
  • DevExpress WinForms中文教程 - 如何在Grid控件中集成语义相似性搜索?
    许多用户都知道Microsoft的DanielRoth和SteveSanderson引入的.NET智能组件——AI驱动的UI控件,许多人都喜欢这个控件原因归结为以下几点:由于它的简单性,开发人员可以在本地“驾驭AI”,而无需获得Azure或OpenAIPhD-智能功能使用单个NuGet包即可使用。“智能搜索”是通过本地嵌......
  • Simple WPF: WPF自定义一个可以定义步长的SpinBox
    最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。通过WPF的按钮、文本输入框实现了一个简单的SpinBox数字输入用户组件并可以通过数据绑定数值和步长。本文中介绍了通过Xaml代码实现自定义组件的布局,依赖属性的定义和使用等知识点。完整代码见Github组合Xaml......
  • 01.一个基于pism的wpf模块框架
      1.导航数据,每个xml就是一个程序部分,可以以菜单,导航吧,树形,汉堡菜单显示,,根据自己需要吧。。    2.程序显示绿色就是显示全部模块。每个菜单对应AllMenus的定义。如果点下“汉堡菜单”,如下显示,对应就是 ......
  • 将WPF内部绑定的控件和数据拉取出来
    一般最简单的ItemsControl的写法是<ItemsControlItemsSource="{BindingStudents}"><ItemsControl.ItemTemplate><DataTemplate><TextBlockText="{BindingName}"/>......
  • WPF ComboBox数据绑定:初始化动态加载ItemsSource后首次赋值Text不显示问题解决
    原来:<ComboBoxText="{BindingItem}"ItemsSource="{BindingItemLists}"></ComboBox>privatevoidParas_Init(){ItemLists=newObservableCollection<string>();ItemLists.Add("111......
  • Simple WPF: WPF 实现按钮的长按,短按功能
    最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。实现了一个支持长短按得按钮组件,单击可以触发Click事件,长按可以触发LongPressed事件,长按松开时触发LongClick事件。源码请自取:Github长按阈值属性的建立为了方便在xaml中使用,我们先配置一个DependencyProperty......
  • Halcon学习笔记(3):WPF 框架搭建,MaterialDesign+Prism
    目录前言环境Nuget安装新建WPF类库项目初始化PrismApp启动页初始化重写MainView前言其实我更喜欢CommunityToolkit.mvvm+HandyControl。但是因为找工作,你不能去抗拒新事物。这里就当体验一下完整的流程好了。环境windows11.netcore8.0Nuget安装新建WPF类库项目新......