diff --git a/examples/ImageInsert/ImageInsert.lpi b/examples/ImageInsert/ImageInsert.lpi
new file mode 100644
index 0000000..e2490c5
--- /dev/null
+++ b/examples/ImageInsert/ImageInsert.lpi
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/ImageInsert/ImageInsert.lpr b/examples/ImageInsert/ImageInsert.lpr
new file mode 100644
index 0000000..8ad4a93
--- /dev/null
+++ b/examples/ImageInsert/ImageInsert.lpr
@@ -0,0 +1,95 @@
+{ fpOdf "Image Insert" Example
+
+ Copyright (c) 2013-2019 Daniel F.Gaspary
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to
+ deal in the Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+}
+
+program ImageInsert;
+
+uses
+ classes, odf_types, base64;
+
+const
+ cStyle = 'Standard';
+
+ cInputFile = '/tmp/image1.png';
+ cOutputFile = '/tmp/output.fodt';
+
+function EncodeStreamBase64(AInputStream: TStream):String;
+var
+ Outstream : TStringStream;
+ Encoder : TBase64EncodingStream;
+begin
+ Outstream:=TStringStream.Create('');
+ try
+ Encoder:=TBase64EncodingStream.create(outstream);
+ try
+ Encoder.CopyFrom(AInputStream, AInputStream.Size);
+ finally
+ Encoder.Free;
+ end;
+ Result:=Outstream.DataString;
+ finally
+ Outstream.free;
+ end;
+end;
+
+var
+ doc: TOdfTextDocument;
+ p: TOdfParagraph;
+ eDrawFrame, eDrawImage, eBinaryData: TOdfElement;
+
+ fs: TFileStream;
+ s: string;
+begin
+ doc:=TOdfTextDocument.Create;
+
+ doc.AddParagraph(cStyle).TextContent:='p1';
+ p:=doc.AddParagraph(cStyle);
+
+ eDrawFrame:=p.AppendOdfElement(oetDrawFrame);
+
+ eDrawFrame.SetAttributes(
+ [oatDrawStyleName, oatDrawName, oatTextAnchorType, oatSvgWidth, oatSvgHeight, oatDrawZIndex],
+ ['fr1', 'Image1', 'paragraph', '5.80in', '3.6in', '0']);
+
+ eDrawImage:=eDrawFrame.AppendOdfElement(oetDrawImage);
+
+ eBinaryData:=eDrawImage.AppendOdfElement(oetOfficeBinaryData);
+
+ try
+ fs:=TFileStream.Create(cInputFile, fmOpenRead);
+ s:=EncodeStreamBase64(fs);
+ finally
+ fs.Free;
+ end;
+
+ eBinaryData.TextContent:=s;
+
+ doc.AddParagraph(cStyle).TextContent:='p2';
+
+ try
+ doc.SaveToSingleXml(cOutputFile);
+
+ finally
+ doc.Free;
+ end;
+end.
+
diff --git a/examples/ImageInsert/ImageInsert.lps b/examples/ImageInsert/ImageInsert.lps
new file mode 100644
index 0000000..a976f7e
--- /dev/null
+++ b/examples/ImageInsert/ImageInsert.lps
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/TableInsert/TableInsert.lpi b/examples/TableInsert/TableInsert.lpi
new file mode 100644
index 0000000..5b2f72c
--- /dev/null
+++ b/examples/TableInsert/TableInsert.lpi
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/TableInsert/TableInsert.lpr b/examples/TableInsert/TableInsert.lpr
new file mode 100644
index 0000000..99fad44
--- /dev/null
+++ b/examples/TableInsert/TableInsert.lpr
@@ -0,0 +1,126 @@
+{ fpOdf "Table Insert" Example
+
+ Copyright (c) 2013-2019 Daniel F.Gaspary
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to
+ deal in the Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+}
+
+program TableInsert;
+
+uses
+ Classes, sysutils, odf_types;
+
+const
+ cStyle = 'Standard';
+ cOutputFile = '/tmp/output.fodt';
+ cTableStyle = 'Table1';
+ cTableColumnStyle = 'Table1.A';
+ cTableCellStyle = 'Table1.A';
+
+ cTableCellStyle2 = 'CellStyle2';
+
+ cRowCount = 3;
+ cColCount = 3;
+
+
+var
+ doc: TOdfTextDocument;
+ p: TOdfParagraph;
+ e, vTable, vRow, vCell: TOdfElement;
+
+ s, t: string;
+
+ i, j: integer;
+
+procedure CreateStyles;
+begin
+ e:=doc.CreateStyle(cTableStyle, sfvTble);
+ doc.AutomaticStyles.AppendChild(e);
+ e:=e.AppendOdfElement(oetStyleTableProperties, oatStyleWidth, '6.6931in');
+ e.SetAttribute(oatTableAlign, 'margins');
+
+ e:=doc.CreateStyle(cTableColumnStyle, sfvTableColumn);
+ doc.AutomaticStyles.AppendChild(e);
+ e:=e.AppendOdfElement(oetStyleTableColumnProperties, oatStyleWidth, '3.346in');
+ e.SetAttribute(oatStyleRelColumnWidth, '32767*');
+
+ e:=doc.CreateOdfElement(oetStyleDefaultStyle, oatStyleFamily, 'table');
+ doc.Styles.AppendChild(e);
+ e:=e.AppendOdfElement(oetStyleTableProperties, oatTableBorderModel, 'collapsing');
+
+ e:=doc.CreateOdfElement(oetStyleDefaultStyle, oatStyleFamily, 'table-row');
+ doc.Styles.AppendChild(e);
+ e:=e.AppendOdfElement(oetStyleTableRowProperties, oatFoKeepTogether, 'auto');
+
+ e:=doc.CreateStyle(cTableCellStyle2, sfvParagraph);
+ e.SetAttribute(oatStyleParentStyleName, cStyle);
+ doc.Styles.AppendChild(e);
+ e:=e.AppendOdfElement(oetStyleTextProperties, oatFoFontWeight, 'bold');
+ e.SetAttributes([oatStyleFontWeightAsian, oatStyleFontWeightComplex], ['bold', 'bold']);
+end;
+
+begin
+ doc:=TOdfTextDocument.Create;
+
+ CreateStyles;
+
+ doc.AddParagraph(cStyle).TextContent:='p1';
+ p:=doc.AddParagraph(cStyle);
+
+ //Create Table
+ vTable:=doc.CreateOdfElement(oetTableTable);
+ vTable.SetAttributes([oatTableName, oatTableStyleName], ['Table1', cTableStyle]);
+
+ //Create table column description.
+ e:=vTable.AppendOdfElement(oetTableTableColumn, oatTableStyleName, cTableColumnStyle);
+ e.SetAttribute(oatTableNumberColumnsRepeated, IntToStr(cColCount));
+
+ //create rows and cells
+ for i:=1 to cRowCount do
+ begin
+ vRow:=vTable.AppendOdfElement(oetTableTableRow);
+
+ for j:=1 to cColCount do
+ begin
+ vCell:=vRow.AppendOdfElement(oetTableTableCell, oatTableStyleName, cTableCellStyle);
+ vCell.SetAttribute(oatOfficeValueType, 'string');
+
+ if i=j
+ then
+ s:=cTableCellStyle2
+ else
+ s:=cStyle;
+
+ t:=Format('%d%d', [i,j]);
+ vCell.AppendOdfElement(oetTextP, oatTextStyleName, s).TextContent:=t;
+ end;
+ end;
+
+ doc.Text.AppendChild(vTable);
+
+ doc.AddParagraph(cStyle).TextContent:='p2';
+
+ try
+ doc.SaveToSingleXml(cOutputFile);
+
+ finally
+ doc.Free;
+ end;
+end.
+
diff --git a/examples/TableInsert/TableInsert.lps b/examples/TableInsert/TableInsert.lps
new file mode 100644
index 0000000..2669014
--- /dev/null
+++ b/examples/TableInsert/TableInsert.lps
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/odf_types.pas b/odf_types.pas
index 7b5d81e..3a2d136 100644
--- a/odf_types.pas
+++ b/odf_types.pas
@@ -3,7 +3,7 @@
fpOdf is a library used to help users to create and to modify OpenDocument
Files(ODF)
- Copyright (C) 2013-2019 Daniel F. Gaspary https://github.com/dgaspary
+ Copyright (C) 2013-2021 Daniel F. Gaspary https://github.com/dgaspary
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
@@ -41,7 +41,7 @@
interface
uses
- Classes, SysUtils, FileUtil, LazFileUtils, zipper, zstream, fgl, LazUTF8, Graphics,
+ Classes, SysUtils, FileUtil, LazFileUtils, zipper, zstream, fgl, LazUTF8, FPCanvas,
{ $Define ODF_LOGGING}
@@ -249,6 +249,7 @@ TOdfElementTypeSet = class(specialize TFPGList)
TOdfXmlFiles = ofManifestRdf .. High(TOdfFile);
+
const
OdfXmlFileRoot: array[TOdfXmlFiles] of TElementType =
(
@@ -384,6 +385,25 @@ TConfigConfigItemSet = class(TOdfElement)
{$INCLUDE incs/styles-decl.inc}
type
+
+ TOdfColor = record
+ Red,
+ Green,
+ Blue: Byte;
+ end;
+
+ { TOdfFont }
+
+ TOdfFont = class(TFPCustomFont)
+ private
+ FColor: TOdfColor;
+ public
+ property Color: TOdfColor read FColor write FColor;
+ end;
+
+ { TODO : Odf Font Style has different items than TFontStyle }
+ TOdfFontStyles = set of TOdfFontStyle;
+
TOdfNodeSet = TNodeSet;
TOdfXPathNsResolver = class;
@@ -392,6 +412,9 @@ TOdfXPathNsResolver = class;
TOdfDocument = class
private
+ FTempDir: string;
+ FRemoveTempDir: boolean;
+
FXmlDocument: TXMLDocument;
//Document Root Elements (Ref: Table 7)
@@ -406,7 +429,7 @@ TOdfDocument = class
FMasterStyles: TDOMElement;
FBody: TDOMElement;
- FManifest: TDOMElement;
+ FManifest: TXMLDocument;
FManifestRdf: TDOMElement;
FXPathNsResolver: TOdfXPathNsResolver;
@@ -419,6 +442,8 @@ TOdfDocument = class
procedure FindOdfRootElements;virtual;
procedure InitBodyContent; virtual; abstract;
+ procedure ResetRootElements; virtual;
+
function GetMimeType: TOdfMimetype;
procedure SetCreationMeta;
@@ -438,14 +463,21 @@ TOdfDocument = class
constructor Create;
destructor Destroy; override;
+ class function GetMimeType(ADoc: TXMLDocument): TOdfMimetype;
+
class function ElementOdfClassByType(et: TElementType): TOdfElementClass;
class function ConvertOdfElement(AClass: TOdfElementClass;
e: TDOMElement): TOdfElement;
+ class function CreateDocument(AMimeType: TOdfMimetype): TOdfDocument;
+
class function LoadFromFile(AFilename: string): TOdfDocument;
class function LoadFromZipFile(AFilename, TempDir: string): TOdfDocument;
- class function LoadFromSingleXml(AFilename: string): TOdfDocument;
+
+ class function CreateFromXml(ADoc: TXMLDocument): TOdfDocument;
+ class function LoadFromSingleXml(AStream: TStream): TOdfDocument; overload;
+ class function LoadFromSingleXml(AFilename: string): TOdfDocument; overload;
class procedure SaveToSingleXml(AOdf: TOdfDocument;
AFilename: string); overload;
@@ -461,7 +493,7 @@ TOdfDocument = class
AParentStyle: TOdfStyleStyle): TOdfStyleStyle;
- function CreateSpan(AText: string; FontStyles: TFontStyles): TSpan;
+ function CreateSpan(AText: string; FontStyles: TOdfFontStyles): TSpan;
function SearchText(AText: string; AParent: TDOMElement;
Accepted: TElementTypeArray;
@@ -501,10 +533,13 @@ TOdfDocument = class
function GetStyleElementByName(AStyleName: string): TDOMElement;
- function GetStyleByProperties(AFamily: TStyleFamilyValue;
- AFontSize: integer; AFontSizeUnit: string;
- AFontStyle: TOdfFontStyle; AFontWeigth: TOdfFontWeight;
- AStyleFamily: string): TStrings;
+ //Params with default values will be ignored in search.
+ //Example: 0 for AFontSize, '' for AStyleFamily and fwNone for AFontWeight
+ function GetStyleByProperties(AFontSize: integer; AFontSizeUnit: string;
+ AFontStyle: TOdfFontStyle; AFontWeight: TOdfFontWeight;
+ AFontUnderlineStyle: string): TStrings;
+
+ function Clone: TOdfDocument; virtual;
property Settings: TDOMElement read FSettings write FSettings;
property Scripts: TDOMElement read FScripts write FScripts;
@@ -513,8 +548,10 @@ TOdfDocument = class
property AutomaticStyles: TDOMElement read FAutomaticStyles write FAutomaticStyles;
property MasterStyles: TDOMElement read FMasterStyles write FMasterStyles;
- property Manifest: TDOMElement read FManifest write FManifest;
+ property Manifest: TXMLDocument read FManifest write FManifest;
property ManifestRdf: TDOMElement read FManifestRdf write FManifestRdf;
+
+ property RemoveTempDir: boolean read FRemoveTempDir write FRemoveTempDir;
end;
@@ -540,12 +577,12 @@ TOdfParagraph = class(TOdfContent)
private
public
- function AddSpan(AText: string; FontStyles: TFontStyles): TSpan;overload;
- function AddSpan(AText: string; aFont: TFont;const doc: TOdfDocument): TSpan;
+ function AddSpan(AText: string; FontStyles: TOdfFontStyles): TSpan;overload;
+ function AddSpan(AText: string; aFont: TOdfFont;const doc: TOdfDocument): TSpan;
overload;
function AddSpan(AText: string; aStyle: string): TSpan;overload;
- function AddBookmark(AText: string; FontStyles: TFontStyles;aBMName:string): TSpan;
- function AddLink(AText: string; FontStyles: TFontStyles;aBMName:string): THyperLink;
+ function AddBookmark(AText: string; FontStyles: TOdfFontStyles;aBMName:string): TSpan;
+ function AddLink(AText: string; FontStyles: TOdfFontStyles;aBMName:string): THyperLink;
//p1-7.4.15
{ TODO : Text input can also be included on Span, oetTextH, etc }
@@ -560,8 +597,8 @@ TSpan = class(TOdfContent)
public
class function CreateSpan(doc: TXMLDocument; AText: string): TSpan;
- procedure SetStyle(fs: TFontStyles);overload;
- procedure SetStyle(const doc: TOdfDocument; aFont: TFont); overload;
+ procedure SetStyle(fs: TOdfFontStyles);overload;
+ procedure SetStyle(const doc: TOdfDocument; aFont: TOdfFont); overload;
procedure SetStyle(aStyleName: string);overload;
end;
@@ -593,6 +630,8 @@ TOdfTextDocument = class(TOdfDocument)
FText: TDOMElement;
procedure InitXmlDocument; override;
+ procedure ResetRootElements; override;
+
procedure InitBodyContent; override;
Procedure GenerateAutoStyles;
public
@@ -928,14 +967,15 @@ constructor TOdfElementTypeSet.Create(EtArray: TElementTypeArray);
{ TOdfParagraph }
-function TOdfParagraph.AddSpan(AText: string; FontStyles: TFontStyles): TSpan;
+function TOdfParagraph.AddSpan(AText: string; FontStyles: TOdfFontStyles
+ ): TSpan;
begin
result:=TSpan.CreateSpan(self.OwnerDocument as TXMLDocument, AText);
result.SetStyle(FontStyles);
AppendChild(result);
end;
-function TOdfParagraph.AddSpan(AText: string; aFont: TFont;
+function TOdfParagraph.AddSpan(AText: string; aFont: TOdfFont;
const doc: TOdfDocument): TSpan;
begin
result:=TSpan.CreateSpan(self.OwnerDocument as TXMLDocument, AText);
@@ -950,7 +990,7 @@ function TOdfParagraph.AddSpan(AText: string; aStyle: string): TSpan;
AppendChild(result);
end;
-function TOdfParagraph.AddBookmark(AText: string; FontStyles: TFontStyles;
+function TOdfParagraph.AddBookmark(AText: string; FontStyles: TOdfFontStyles;
aBMName: string): TSpan;
begin
result := TBookMark.CreateBookmark(self.OwnerDocument as TXMLDocument,AText,aBMName);
@@ -958,7 +998,7 @@ function TOdfParagraph.AddBookmark(AText: string; FontStyles: TFontStyles;
AppendChild(result);
end;
-function TOdfParagraph.AddLink(AText: string; FontStyles: TFontStyles;
+function TOdfParagraph.AddLink(AText: string; FontStyles: TOdfFontStyles;
aBMName: string): THyperLink;
begin
result := THyperLink.CreateLink(self.OwnerDocument as TXMLDocument,AText,aBMName);
@@ -1033,9 +1073,9 @@ procedure THyperLink.SetLink(aBMName: string);
{ TSpan }
-procedure TSpan.SetStyle(fs: TFontStyles);
+procedure TSpan.SetStyle(fs: TOdfFontStyles);
var
- lfs: TFontStyle;
+ lfs: TOdfFontStyle;
lFsName: string;
lFsVal: Integer;
begin
@@ -1048,7 +1088,7 @@ procedure TSpan.SetStyle(fs: TFontStyles);
SetAttribute(oatTextStyleName,lFsName);
end;
-procedure TSpan.SetStyle(const doc: TOdfDocument; aFont: TFont);
+procedure TSpan.SetStyle(const doc: TOdfDocument; aFont: TOdfFont);
var
lStyle: TOdfStyleStyle;
lStyleprop: TOdfElement;
@@ -1069,16 +1109,15 @@ procedure TSpan.SetStyle(const doc: TOdfDocument; aFont: TFont);
if not assigned(lFontdcls) then
begin
lFontdcls := CreateOdfElement(oetStyleFontFace,oatStyleName,afont.Name);
- TOdfElement(lFontdcls).SetAttribute(oatSvgFontFamily,afont.Name.QuotedString(''''));
+ TOdfElement(lFontdcls).SetAttribute(oatSvgFontFamily, QuotedStr(afont.Name));
FontFaceDecls.AppendChild(lFontdcls);
end;
lStyleprop.SetAttribute(oatStyleFontName,afont.Name) ;
end;
- if afont.Color <>clDefault then
+// if afont.Color <>clDefault then { TODO : There is no "default" color for TFpColor.. }
begin
- RedGreenBlue(afont.Color,lR,lG,lB);
- lStyleprop.SetAttribute(oatFoColor,'#'+IntToHex(Integer(RGBToColor(lb,lg,lr)),6)) ;
-
+ with aFont.Color do
+ lStyleprop.SetAttribute(oatFoColor,'#'+Format('%2.2x%2.2x%2.2x', [Red, Green, Blue])) ;
end;
if afont.Size>0 then
lStyleprop.SetAttribute(oatFoFontSize,inttostr(afont.Size)+'pt') ;
@@ -1244,6 +1283,13 @@ procedure TOdfTextDocument.InitXmlDocument;
MimeType:=omtText;
end;
+procedure TOdfTextDocument.ResetRootElements;
+begin
+ inherited ResetRootElements;
+
+ FText:=nil;
+end;
+
procedure TOdfTextDocument.InitBodyContent;
begin
if Assigned(FText)
@@ -1725,6 +1771,7 @@ function TOdfDocument.StylesUsed(AParent: TDomElement): TStrings;
s+='//' + AParent.TagName + '//@' + OdfGetAttributeQName(att);
end;
+ { TODO : Maybe the correct is to search starting from BODY element }
if XPathSearch(s, FXmlDocument.DocumentElement, [], StylesFound)
then
begin
@@ -1765,11 +1812,8 @@ class function TOdfDocument.ParseXmlFile(AStream: TStream): TXMLDocument;
end;
function TOdfDocument.GetMimeType: TOdfMimetype;
-var
- s: string;
begin
- s:=XmlDocument.DocumentElement.GetAttributeNS(GetURI(onsOffice), 'mimetype');
- result:=OdfGetMimeTypeByName(s);
+ Result:=GetMimeType(XmlDocument);
end;
class function TOdfDocument.LoadFromFile(AFilename: string): TOdfDocument;
@@ -2043,18 +2087,25 @@ class procedure TOdfDocument.ReadPackage(ADir: String; AOdf: TOdfDocument);
LoadXml('settings.xml');
AOdf.Settings:=MoveElem(vNsURI, 'settings');
- vDoc.Free;
+ LoadXml(IncludeTrailingPathDelimiter('META-INF') + 'manifest.xml');
- DeleteDirectory(ADir, false);
+ AOdf.Manifest:=vDoc;
+ vDoc:=nil;
AOdf.InitBodyContent;
end;
procedure TOdfDocument.SetXmlDocument(AValue: TXMLDocument);
begin
- if assigned(FXmlDocument) then
- FreeAndNil(FXmlDocument);
- FXmlDocument:=AValue;
+ if Assigned(FXmlDocument)
+ then
+ begin
+ FreeAndNil(FXmlDocument);
+
+ ResetRootElements;
+ end;
+
+ FXmlDocument:=AValue;
end;
function OdfCreateManifestRdfFile: TXMLDocument;
@@ -2138,9 +2189,9 @@ function OdfCreateManifestFile: TXMLDocument;
AddFileEntry('manifest.rdf', 'application/rdf+xml');
AddFileEntry('styles.xml', 'text/xml');
AddFileEntry('meta.xml', 'text/xml');
- AddFileEntry('Thumbnails/thumbnail.png', 'image/png');
+{ AddFileEntry('Thumbnails/thumbnail.png', 'image/png');
AddFileEntry('Thumbnails/');
-
+}
{ TODO : Configurations2 seems to be an OpenOffice specific directory. }
AddFileEntry('Configurations2/accelerator/current.xml');
@@ -2190,7 +2241,7 @@ class procedure TOdfDocument.WritePackage(DestFile: String;
if not OdfXPathSearch(vXPath, xmlDoc.DocumentElement,
FoundElements)
then
- Raise Exception.Create('No Styles Found at destiny file.');
+ Raise Exception.Create('No Styles Found at dOdfXPathSearchestiny file.');
if FoundElements.Count>0
then
@@ -2239,7 +2290,13 @@ class procedure TOdfDocument.WritePackage(DestFile: String;
nsSet:=[];
case f of
ofManifestRdf : vDoc:=OdfCreateManifestRdfFile;
- ofManifest : vDoc:=OdfCreateManifestFile;
+ ofManifest : begin
+ if Assigned(AOdf.Manifest)
+ then
+ vDoc:=AOdf.Manifest
+ else
+ vDoc:=OdfCreateManifestFile;
+ end
else
begin
vDoc:=TXMLDocument.Create;
@@ -2292,7 +2349,101 @@ class procedure TOdfDocument.WritePackage(DestFile: String;
z.Entries.AddFileEntry(ATempDir + vFilename, vFilename);
- vDoc.Free;
+ if (f<>ofManifest) // ?? or ( (f=ofManifest) and (AOdf.Manifest=nil))
+ then
+ vDoc.Free;
+ end;
+
+ procedure UpdateManifest(ASubDir, AFileName: string);
+ var
+ vNode: TDOMNode;
+ vElement: TDOMElement;
+ vMediaType: string;
+ begin
+ if not Assigned(AOdf.Manifest)
+ then
+ begin
+ { TODO : Create manifest }
+ end;
+
+ ASubDir:=ExcludeTrailingPathDelimiter(ASubDir);
+
+ vNode:=AOdf.Manifest.DocumentElement.FirstChild;
+ while Assigned(vNode) do
+ begin
+ if (vNode is TDOMElement)
+ then
+ begin
+ vElement:=(vNode as TDOMElement);
+
+ if TOdfElement.SameType(vElement, oetManifestFileEntry) and
+ (TOdfElement(vElement).GetAttributeString(oatManifestFullPath) = ASubDir + '/' + AFileName)
+ then
+ break;
+ end;
+
+ vElement:=nil;
+
+ vNode:=vNode.NextSibling;
+ end;
+
+ if vElement=nil
+ then
+ begin
+ vElement:=TOdfElement.CreateDomElement(oetManifestFileEntry, AOdf.Manifest,
+ oatManifestFullPath, ASubDir + '/' + AFileName);
+
+
+ { TODO : The Discovering of media type should have a dedicated procedure/classes }
+ vMediaType:=ExtractFileExt(AFileName);
+ if vMediaType='jpg'
+ then
+ vMediaType:='jpeg';
+
+
+ if (vMediaType='jpeg') or (vMediaType='png')
+ then
+ vMediaType:='image/' + vMediaType;
+
+ TOdfElement(vElement).SetAttribute(oatManifestMediaType, vMediaType);
+
+ AOdf.Manifest.DocumentElement.AppendChild(vElement);
+ end;
+
+ end;
+
+ procedure AddFilesToZipper(ASubDir: string);
+ var
+ FileInfo : TSearchRec;
+ vBaseDir, vFile: string;
+ begin
+ vBaseDir:=IncludeTrailingPathDelimiter(AOdf.FTempDir);
+
+ if (AOdf.FTempDir='') or (not DirectoryExistsUTF8(vBaseDir + ASubDir))
+ then
+ exit;
+
+ ASubDir:=IncludeTrailingPathDelimiter(ASubDir);
+
+ if FindFirst (vBaseDir + ASubDir + '*',faAnyFile,FileInfo)=0
+ then
+ begin
+ repeat
+ With FileInfo do
+ begin
+ if (Attr and faDirectory) = faDirectory
+ then
+ Continue;
+
+ vFile:=vBaseDir + ASubDir + Name;
+ zfe:=z.Entries.AddFileEntry(vFile, ASubDir + Name);
+ //(zfe as TZipFileEntry).CompressionLevel:=Tcompressionlevel.clnone;
+
+ UpdateManifest(ASubDir, Name);
+ end;
+ until FindNext(FileInfo)<>0;
+ FindClose(FileInfo);
+ end;
end;
begin
@@ -2318,6 +2469,11 @@ class procedure TOdfDocument.WritePackage(DestFile: String;
vBodyStyles:=AOdf.StylesUsed(AOdf.Body);
+ { TODO : List and extract filenames using XPath, avoiding hardcoded directories.
+ Example Element: ''
+ then
+ vConditions+=' and ';
+
+ vConditions+='@' + OdfGetAttributeQName(Att) + '=' + QuotedStr(AValue);
+ end;
+
begin
- { TODO : To be done.. }
+ Result:=TStringList.Create;
+
+ vConditions:='';
+
+ { TODO : Include Complex and Asian font attributes? }
+ if AFontSize>0
+ then
+ AddCondition(oatFoFontSize, IntToStr(AFontSize) + AFontSizeUnit);
+
+ if AFontStyle<>ofsNone
+ then
+ AddCondition(oatFoFontStyle, OdfGetFontStyleValue(AFontStyle));
+
+ if AFontWeight<>fwNone
+ then
+ AddCondition(oatFoFontWeight, OdfGetFontWeightValue(AFontWeight));
+
+ if AFontUnderlineStyle<>''
+ then
+ AddCondition(oatStyleTextUnderlineStyle, AFontUnderlineStyle);
+
+ if vConditions=''
+ then
+ exit;
+
+ try
+ { TODO : Automatic styles and Parent resolution }
+
+ //s:=Format('//style:text-properties[%s]', [s]);
+ s:='//style:text-properties[' + vConditions + ']';
+
+ PropertiesFound:=nil;
+ if XPathSearch(s, FStyles, [], PropertiesFound)
+ then
+ for p in PropertiesFound do
+ if TObject(p) is TDOMElement
+ then
+ begin
+ AStyle:=TDOMElement(p).ParentNode as TDOMElement;
+ s:=OdfGetAttributeValue(oatStyleName, AStyle);
+
+ if (s<>'') and (Result.IndexOf(s)<0)
+ then
+ Result.Add(s);
+
+ end;
+ finally
+ if Assigned(PropertiesFound)
+ then
+ PropertiesFound.Free;
+ end;
+end;
+
+function TOdfDocument.Clone: TOdfDocument;
+var
+ vDoc: TXMLDocument;
+ e: TDOMElement;
+begin
+ vDoc:=TXMLDocument.Create;
+ e:=FXmlDocument.DocumentElement.CloneNode(true, vDoc) as TDOMElement;
+ vDoc.AppendChild(e);
+
+ Result:=TOdfDocument.CreateFromXml(vDoc);
end;
diff --git a/odf_xmlutils.pas b/odf_xmlutils.pas
index 5cdb0da..a5e6808 100644
--- a/odf_xmlutils.pas
+++ b/odf_xmlutils.pas
@@ -3,7 +3,7 @@
fpOdf is a library used to help users to create and to modify OpenDocument
Files(ODF)
- Copyright (C) 2013-2015 Daniel F. Gaspary https://github.com/dgaspary
+ Copyright (C) 2013-2019 Daniel F. Gaspary https://github.com/dgaspary
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
@@ -52,20 +52,32 @@ interface
;
+procedure OdfWriteXmlToStream(ADoc: TXMLDocument; AStream: TStream);
procedure OdfWriteXmlToFile(ADoc: TXMLDocument; AFilename: string);
function OdfAttributesAsStrings(e: TDOMElement; OnlyNames: boolean = true): TStrings;
implementation
-procedure OdfWriteXmlToFile(ADoc: TXMLDocument; AFilename: string);
+procedure OdfWriteXmlToStream(ADoc: TXMLDocument; AStream: TStream);
begin
{$IfDef UseStaxWriter}
- XmlStreamWrite(ADoc, AFilename, 'utf-8', '1.0');
+ XmlStreamWrite(ADoc, AStream, 'utf-8', '1.0');
{$Else}
- WriteXMLFile(ADoc, AFilename,[xwfPreserveWhiteSpace]);
+ WriteXMLFile(ADoc, AStream,[xwfPreserveWhiteSpace]);
{$EndIf}
+end;
+procedure OdfWriteXmlToFile(ADoc: TXMLDocument; AFilename: string);
+var
+ fs: TFileStream;
+begin
+ try
+ fs:=TFileStream.Create(AFilename, fmCreate);
+ OdfWriteXmlToStream(ADoc, fs);
+ finally
+ fs.Free;
+ end;
end;
function OdfAttributesAsStrings(e: TDOMElement; OnlyNames: boolean): TStrings;
diff --git a/package/fpodf.lpk b/package/fpodf.lpk
index c47fcf5..cf98da7 100644
--- a/package/fpodf.lpk
+++ b/package/fpodf.lpk
@@ -1,59 +1,56 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+http://en.wikipedia.org/wiki/OpenDocument"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+Read the file COPYING.modifiedLGPL.txt for more informations."/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+