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正式版下載(Q技術交流: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);
}
}
}