fpspreadsheet: Replace workbook's EmbeddedStream by a more general EmbeddedObj storing image width, height and format as well.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4556 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2016-03-15 12:29:58 +00:00
parent 5879d12600
commit 998c8b0dfc
11 changed files with 209 additions and 118 deletions

View File

@ -39,6 +39,7 @@ begin
MyDir := ExtractFilePath(ParamStr(0)); MyDir := ExtractFilePath(ParamStr(0));
MyWorkbook.WriteToFile(MyDir + 'hfimg.xlsx', sfOOXML, true); MyWorkbook.WriteToFile(MyDir + 'hfimg.xlsx', sfOOXML, true);
MyWorkbook.WriteToFile(MyDir + 'hfimg.ods', sfOpenDocument, true); MyWorkbook.WriteToFile(MyDir + 'hfimg.ods', sfOpenDocument, true);
// MyWorkbook.WriteToFile(MyDir + 'hfimg.xls', sfExcel8, true); // MyWorkbook.WriteToFile(MyDir + 'hfimg.xls', sfExcel8, true);
// MyWorkbook.WriteToFile(MyDir + 'hfimg5.xls', sfExcel5, true); // MyWorkbook.WriteToFile(MyDir + 'hfimg5.xls', sfExcel5, true);
// MyWorkbook.WriteToFile(MyDir + 'hfimg2.xls', sfExcel2, true); // MyWorkbook.WriteToFile(MyDir + 'hfimg2.xls', sfExcel2, true);

View File

@ -201,15 +201,6 @@ type
function Pop: Integer; function Pop: Integer;
end; end;
{ TsEmbeddedStream }
TsEmbeddedStream = class(TMemoryStream)
private
FName: String;
public
constructor Create(AName: String);
property Name: String read FName;
end;
function FindFontInList(AFontList: TFPList; AFontName: String; ASize: Single; function FindFontInList(AFontList: TFPList; AFontName: String; ASize: Single;
AStyle: TsFontStyles; AColor: TsColor; APos: TsFontPosition): Integer; AStyle: TsFontStyles; AColor: TsColor; APos: TsFontPosition): Integer;
@ -1344,17 +1335,6 @@ begin
end; end;
{==============================================================================}
{ TsEmbeddedStream }
{==============================================================================}
constructor TsEmbeddedStream.Create(AName: String);
begin
inherited Create;
FName := AName;
end;
{==============================================================================} {==============================================================================}
{ Utilities } { Utilities }
{==============================================================================} {==============================================================================}

View File

@ -27,6 +27,26 @@ var
itEMF: TsImageType; itEMF: TsImageType;
itPCX: TsImageType; itPCX: TsImageType;
type
{ TsEmbeddedObj }
TsEmbeddedObj = class
private
FStream: TMemoryStream;
FName: String;
FImageType: TsImageType; // image type, see itXXXX
FWidth: Double; // image width, in mm
FHeight: Double; // image height, in mm
public
constructor Create(AName: String);
destructor Destroy; override;
property Name: String read FName;
property ImageType: TsImagetype read FImageType;
property ImageWidth: Double read FWidth;
property ImageHeight: Double read FHeight;
property Stream: TMemoryStream read FStream;
end;
function GetImageInfo(AStream: TStream; out AWidthInches, AHeightInches: Double; function GetImageInfo(AStream: TStream; out AWidthInches, AHeightInches: Double;
AImagetype: TsImageType = itUnknown): TsImageType; overload; AImagetype: TsImageType = itUnknown): TsImageType; overload;
@ -34,6 +54,7 @@ function GetImageInfo(AStream: TStream; out AWidth, AHeight: DWord;
out dpiX, dpiY: Double; AImageType: TsImageType = itUnknown): TsImageType; overload; out dpiX, dpiY: Double; AImageType: TsImageType = itUnknown): TsImageType; overload;
function GetImageMimeType(AImageType: TsImageType): String; function GetImageMimeType(AImageType: TsImageType): String;
function GetImageTypeExt(AImageType: TsImageType): String;
function GetImageTypeFromFileName(const AFilename: String): TsImageType; function GetImageTypeFromFileName(const AFilename: String): TsImageType;
function RegisterImageType(AMimeType, AExt: String; AGetImageSize: TGetImageSizeFunc): TsImageType; function RegisterImageType(AMimeType, AExt: String; AGetImageSize: TGetImageSizeFunc): TsImageType;
@ -735,6 +756,26 @@ begin
Result := ''; Result := '';
end; end;
{@@ ----------------------------------------------------------------------------
Returns the file extension belonging the specified image type. If there
are several extensions the first one is selected. The extension is returned
without a leading period.
-------------------------------------------------------------------------------}
function GetImageTypeExt(AImageType: TsImageType): String;
var
p: Integer;
begin
if InRange(AImageType, 0, High(ImageTypeRegistry)) then
begin
Result := ImageTypeRegistry[AImageType].Ext;
p := pos('|', Result);
if p > 0 then
Result := copy(Result, 1, p-1);
if Result[1] = '.' then Delete(Result, 1, 1);
end else
Result := '';
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Extracts the image file type identifier from the extension of the specified Extracts the image file type identifier from the extension of the specified
file name. file name.
@ -790,6 +831,39 @@ begin
end; end;
{==============================================================================}
{ TsEmbeddedObj }
{==============================================================================}
constructor TsEmbeddedObj.Create(AName: String);
var
w, h: Double;
begin
inherited Create;
FName := AName;
FStream := TMemoryStream.Create;
FStream.LoadFromFile(AName);
FImageType := GetImageInfo(FStream, w, h, GetImageTypefromFileName(AName));
if FImageType <> itUnknown then
begin
FWidth := inToMM(w);
FHeight := inToMM(h);
end else
begin
FreeAndNil(FStream);
abort;
end;
end;
destructor TsEmbeddedObj.Destroy;
begin
FreeAndNil(FStream);
inherited Destroy;
end;
initialization initialization
itPNG := RegisterImageType('image/png', 'png', @GetPNGSize); itPNG := RegisterImageType('image/png', 'png', @GetPNGSize);

View File

@ -3966,6 +3966,7 @@ procedure TsSpreadOpenDocWriter.GetHeaderFooterImageName(
var var
sct: TsHeaderFooterSectionIndex; sct: TsHeaderFooterSectionIndex;
img: TsHeaderFooterImage; img: TsHeaderFooterImage;
ext: String;
begin begin
AHeader := ''; AHeader := '';
AFooter := ''; AFooter := '';
@ -3976,14 +3977,16 @@ begin
if APageLayout.HeaderImages[sct].Index > -1 then if APageLayout.HeaderImages[sct].Index > -1 then
begin begin
img := APageLayout.HeaderImages[sct]; img := APageLayout.HeaderImages[sct];
AHeader := IntToStr(img.Index+1) + ExtractFileExt(FWorkbook.GetEmbeddedStream(img.Index).Name); ext := GetImageTypeExt(FWorkbook.GetEmbeddedObj(img.Index).ImageType);
AHeader := Format('%d.%s', [img.Index+1, ext]);
break; break;
end; end;
for sct in TsHeaderFooterSectionIndex do for sct in TsHeaderFooterSectionIndex do
if APageLayout.FooterImages[sct].Index > -1 then if APageLayout.FooterImages[sct].Index > -1 then
begin begin
img := APageLayout.FooterImages[sct]; img := APageLayout.FooterImages[sct];
AFooter := IntToStr(img.Index+1) + ExtractFileExt(FWorkbook.GetEmbeddedStream(img.Index).Name); ext := GetImageTypeExt(FWorkbook.GetEmbeddedObj(img.Index).Imagetype);
AFooter := Format('%d.%s', [img.Index+1, ext]);
break; break;
end; end;
end; end;
@ -4297,7 +4300,7 @@ var
ext: String; ext: String;
mime: String; mime: String;
imgtype: Integer; imgtype: Integer;
embStream: TsEmbeddedStream; embObj: TsEmbeddedObj;
begin begin
AppendToStream(FSMetaInfManifest, AppendToStream(FSMetaInfManifest,
'<manifest:manifest xmlns:manifest="' + SCHEMAS_XMLNS_MANIFEST + '">'); '<manifest:manifest xmlns:manifest="' + SCHEMAS_XMLNS_MANIFEST + '">');
@ -4311,16 +4314,16 @@ begin
'<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml" />'); '<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml" />');
AppendToStream(FSMetaInfManifest, AppendToStream(FSMetaInfManifest,
'<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="settings.xml" />'); '<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="settings.xml" />');
for i:=0 to FWorkbook.GetEmbeddedStreamCount-1 do for i:=0 to FWorkbook.GetEmbeddedObjCount-1 do
begin begin
embstream := FWorkbook.GetEmbeddedStream(i); embObj := FWorkbook.GetEmbeddedObj(i);
imgtype := GetImageTypeFromFileName(embStream.Name); imgtype := embObj.ImageType;
if imgtype = itUnknown then if imgtype = itUnknown then
continue; continue;
mime := GetImageMimeType(imgtype); mime := GetImageMimeType(imgtype);
ext := ExtractFileExt(embStream.Name); ext := GetImageTypeExt(imgType);
AppendToStream(FSMetaInfManifest, Format( AppendToStream(FSMetaInfManifest, Format(
'<manifest:file-entry manifest:media-type="%s" manifest:full-path="Pictures/%d%s" />', '<manifest:file-entry manifest:media-type="%s" manifest:full-path="Pictures/%d.%s" />',
[mime, i+1, ext] [mime, i+1, ext]
)); ));
end; end;
@ -4357,17 +4360,19 @@ end;
procedure TsSpreadOpenDocWriter.ZipPictures(AZip: TZipper); procedure TsSpreadOpenDocWriter.ZipPictures(AZip: TZipper);
var var
i: Integer; i: Integer;
embStream: TsEmbeddedStream; embObj: TsEmbeddedObj;
embName: String; embName: String;
ext: String;
begin begin
for i:=0 to FWorkbook.GetEmbeddedStreamCount-1 do for i:=0 to FWorkbook.GetEmbeddedObjCount-1 do
begin begin
embStream := FWorkbook.GetEmbeddedStream(i); embObj := FWorkbook.GetEmbeddedObj(i);
// The original ods files have a very long, ranomd, unique (?) filename. // The original ods files have a very long, ranomd, unique (?) filename.
// Test show that a simple, unique, increasing number works as well. // Tests show that a simple, unique, increasing number works as well.
embName := IntToStr(i+1) + ExtractFileExt(embStream.Name); ext := GetImageTypeExt(embObj.ImageType);
embStream.Position := 0; embName := Format('%d.%s', [i+1, ext]);
AZip.Entries.AddFileEntry(embStream, 'Pictures/' + embname); embObj.Stream.Position := 0;
AZip.Entries.AddFileEntry(embObj.Stream, 'Pictures/' + embname);
end; end;
end; end;
@ -5997,7 +6002,7 @@ var
img: TsImage; img: TsImage;
r1,c1,r2,c2: Cardinal; r1,c1,r2,c2: Cardinal;
roffs1,coffs1, roffs2, coffs2: Double; roffs1,coffs1, roffs2, coffs2: Double;
x,y,w,h: Double; x, y, w, h: Double;
begin begin
if ASheet.GetImageCount = 0 then if ASheet.GetImageCount = 0 then
exit; exit;
@ -6013,7 +6018,7 @@ begin
roffs1, coffs1, roffs2, coffs2, // mm roffs1, coffs1, roffs2, coffs2, // mm
x, y, w, h) // mm x, y, w, h) // mm
then begin then begin
FWorkbook.AddErrorMsg('Failure reading image "%s"', [FWorkbook.GetEmbeddedStream(img.Index).Name]); FWorkbook.AddErrorMsg('Failure reading image "%s"', [FWorkbook.GetEmbeddedObj(img.Index).Name]);
continue; continue;
end; end;
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
@ -6021,14 +6026,14 @@ begin
'draw:style-name="gr1" draw:text-style-name="P1" '+ 'draw:style-name="gr1" draw:text-style-name="P1" '+
'svg:width="%.2fmm" svg:height="%.2fmm" '+ 'svg:width="%.2fmm" svg:height="%.2fmm" '+
'svg:x="%.2fmm" svg:y="%.2fmm">' + 'svg:x="%.2fmm" svg:y="%.2fmm">' +
'<draw:image xlink:href="Pictures/%d%s" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad">' + '<draw:image xlink:href="Pictures/%d.%s" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad">' +
'<text:p />' + '<text:p />' +
'</draw:image>' + '</draw:image>' +
'</draw:frame>', [ '</draw:frame>', [
i+1, i+1, i+1, i+1,
w, h, w, h,
x, y, x, y,
img.Index+1, ExtractFileExt(Workbook.GetEmbeddedStream(img.Index).Name) img.Index+1, GetImageTypeExt(Workbook.GetEmbeddedObj(img.Index).ImageType)
], FPointSeparatorSettings)); ], FPointSeparatorSettings));
end; end;

View File

@ -269,12 +269,11 @@ begin
if FWorksheet = nil then if FWorksheet = nil then
raise Exception.Create('[TsPageLayout.AddHeaderImage] Worksheet is nil.'); raise Exception.Create('[TsPageLayout.AddHeaderImage] Worksheet is nil.');
book := TsWorksheet(FWorksheet).Workbook; book := TsWorksheet(FWorksheet).Workbook;
idx := book.FindEmbeddedStream(AFilename); idx := book.FindEmbeddedObj(AFilename);
if idx = -1 then if idx = -1 then
begin idx := book.AddEmbeddedObj(AFilename);
idx := book.AddEmbeddedStream(AFilename); if idx = -1 then // Image not found? Unsupported file format?
book.GetEmbeddedStream(idx).LoadFromFile(AFileName); exit;
end;
FHeaderImages[ASection].Index := idx; FHeaderImages[ASection].Index := idx;
SplitHeaderFooterText(FHeaders[AHeaderIndex], s[hfsLeft], s[hfsCenter], s[hfsRight]); SplitHeaderFooterText(FHeaders[AHeaderIndex], s[hfsLeft], s[hfsCenter], s[hfsRight]);
s[ASection] := s[ASection] + '&G'; s[ASection] := s[ASection] + '&G';
@ -291,12 +290,11 @@ begin
if FWorksheet = nil then if FWorksheet = nil then
raise Exception.Create('[TsPageLayout.AddFooterImage] Worksheet is nil.'); raise Exception.Create('[TsPageLayout.AddFooterImage] Worksheet is nil.');
book := TsWorksheet(FWorksheet).Workbook; book := TsWorksheet(FWorksheet).Workbook;
idx := book.FindEmbeddedStream(AFilename); idx := book.FindEmbeddedObj(AFilename);
if idx = -1 then if idx = -1 then
begin idx := book.AddEmbeddedObj(AFilename);
idx := book.AddEmbeddedStream(AFilename); if idx = -1 then // Image not found? Unsupported file format?
book.GetEmbeddedStream(idx).LoadFromFile(AFileName); exit;
end;
FFooterImages[ASection].Index := idx; FFooterImages[ASection].Index := idx;
SplitHeaderFooterText(FFooters[AFooterIndex], s[hfsLeft], s[hfsCenter], s[hfsRight]); SplitHeaderFooterText(FFooters[AFooterIndex], s[hfsLeft], s[hfsCenter], s[hfsRight]);
s[ASection] := s[ASection] + '&G'; s[ASection] := s[ASection] + '&G';

View File

@ -34,7 +34,7 @@ uses
clocale, clocale,
{$endif}{$endif}{$endif} {$endif}{$endif}{$endif}
Classes, SysUtils, fpimage, AVL_Tree, avglvltree, lconvencoding, Classes, SysUtils, fpimage, AVL_Tree, avglvltree, lconvencoding,
fpsTypes, fpsClasses, fpsNumFormat, fpsPageLayout; fpsTypes, fpsClasses, fpsNumFormat, fpsPageLayout, fpsImages;
type type
{ Forward declarations } { Forward declarations }
@ -654,7 +654,7 @@ type
FFontList: TFPList; FFontList: TFPList;
FNumFormatList: TFPList; FNumFormatList: TFPList;
FCellFormatList: TsCellFormatList; FCellFormatList: TsCellFormatList;
FEmbeddedStreamList: TFPList; FEmbeddedObjList: TFPList;
{ Internal methods } { Internal methods }
class function GetFormatFromFileHeader(const AFileName: TFileName; class function GetFormatFromFileHeader(const AFileName: TFileName;
@ -764,13 +764,13 @@ type
AOperation: TsCopyOperation; AParams: TsStreamParams = []; AOperation: TsCopyOperation; AParams: TsStreamParams = [];
ATransposed: Boolean = false); ATransposed: Boolean = false);
{ Embedded images } { Embedded objects }
function AddEmbeddedStream(const AName: String): Integer; function AddEmbeddedObj(const AName: String): Integer;
function FindEmbeddedStream(const AName: String): Integer; function FindEmbeddedObj(const AName: String): Integer;
function GetEmbeddedStream(AIndex: Integer): TsEmbeddedStream; function GetEmbeddedObj(AIndex: Integer): TsEmbeddedObj;
function GetEmbeddedStreamCount: Integer; function GetEmbeddedObjCount: Integer;
function HasEmbeddedSheetImages: Boolean; function HasEmbeddedSheetImages: Boolean;
procedure RemoveAllEmbeddedStreams; procedure RemoveAllEmbeddedObj;
{ Utilities } { Utilities }
procedure DisableNotifications; procedure DisableNotifications;
@ -829,7 +829,7 @@ uses
Math, StrUtils, DateUtils, TypInfo, lazutf8, lazFileUtils, URIParser, Math, StrUtils, DateUtils, TypInfo, lazutf8, lazFileUtils, URIParser,
fpsStrings, uvirtuallayer_ole, fpsStrings, uvirtuallayer_ole,
fpsUtils, fpsHTMLUtils, fpsRegFileFormats, fpsReaderWriter, fpsUtils, fpsHTMLUtils, fpsRegFileFormats, fpsReaderWriter,
fpsCurrency, fpsExprParser, fpsNumFormatParser, fpsImages; fpsCurrency, fpsExprParser, fpsNumFormatParser;
(* (*
const const
@ -3346,12 +3346,11 @@ function TsWorksheet.CalcImageExtent(AIndex: Integer;
out x,y, AWidth, AHeight: Double): Boolean; // mm out x,y, AWidth, AHeight: Double): Boolean; // mm
var var
img: TsImage; img: TsImage;
stream: TsEmbeddedStream; obj: TsEmbeddedObj;
colW, rowH: Double; colW, rowH: Double;
totH, totW: Double; totH, totW: Double;
r, c: Integer; r, c: Integer;
factor: Double; factor: Double;
imgtype: Integer;
begin begin
img := GetImage(AIndex); img := GetImage(AIndex);
@ -3360,13 +3359,9 @@ begin
ARowOffs1 := img.OffsetX; // millimeters ARowOffs1 := img.OffsetX; // millimeters
AColOffs1 := img.OffsetY; AColOffs1 := img.OffsetY;
stream := FWorkbook.GetEmbeddedStream(img.Index); obj := FWorkbook.GetEmbeddedObj(img.Index);
imgtype := GetImageTypeFromFileName(stream.Name); AWidth := obj.ImageWidth * img.ScaleX;
if GetImageInfo(stream, AWidth, AHeight, imgtype) = itUnknown then // in inches AHeight := obj.ImageHeight * img.ScaleY;
exit(false);
AWidth := inToMM(AWidth*img.ScaleX); // in millimeters now
AHeight := inToMM(AHeight*img.ScaleY);
// Find x coordinate of left image edge, in inches. // Find x coordinate of left image edge, in inches.
factor := FWorkbook.GetDefaultFont.Size/2; // Width of "0" character in pts factor := FWorkbook.GetDefaultFont.Size/2; // Width of "0" character in pts
@ -3438,14 +3433,21 @@ function TsWorksheet.WriteImage(ARow, ACol: Cardinal; AFileName: String;
AScaleX: Double = 1.0; AScaleY: Double = 1.0): Integer; AScaleX: Double = 1.0; AScaleY: Double = 1.0): Integer;
var var
img: PsImage; img: PsImage;
idx: Integer;
begin begin
// Does the image already exist?
idx := Workbook.FindEmbeddedObj(AFileName);
// No? Open and store in embedded object list.
if idx = -1 then
idx := Workbook.AddEmbeddedObj(AFileName);
// An error has occured? Error is already logged. Just exit.
if idx = -1 then
exit;
// Everything ok here...
New(img); New(img);
InitImageRecord(img^, ARow, ACol, AOffsetX, AOffsetY, AScaleX, AScaleY); InitImageRecord(img^, ARow, ACol, AOffsetX, AOffsetY, AScaleX, AScaleY);
img^.Index := Workbook.FindEmbeddedStream(AFileName); img^.Index := idx;
if img^.Index = -1 then begin
img^.Index := Workbook.AddEmbeddedStream(AFileName);
Workbook.GetEmbeddedStream(img^.Index).LoadFromFile(AFileName);
end;
Result := FImages.Add(img); Result := FImages.Add(img);
end; end;
@ -3463,6 +3465,11 @@ begin
FImages.Delete(AIndex); FImages.Delete(AIndex);
end; end;
{@@ ----------------------------------------------------------------------------
Removes all image from the internal image list.
The image streams (stored by the workbook), however, are retained because
images may also be used as header/footer images.
-------------------------------------------------------------------------------}
procedure TsWorksheet.RemoveAllImages; procedure TsWorksheet.RemoveAllImages;
var var
i: Integer; i: Integer;
@ -6836,7 +6843,7 @@ begin
FNumFormatList := TsNumFormatList.Create(FormatSettings, true); FNumFormatList := TsNumFormatList.Create(FormatSettings, true);
FCellFormatList := TsCellFormatList.Create(false); FCellFormatList := TsCellFormatList.Create(false);
FEmbeddedStreamList := TFPList.Create; FEmbeddedObjList := TFPList.Create;
// Add default cell format // Add default cell format
InitFormatRecord(fmt); InitFormatRecord(fmt);
@ -6857,8 +6864,8 @@ begin
RemoveAllFonts; RemoveAllFonts;
FFontList.Free; FFontList.Free;
RemoveAllEmbeddedStreams; RemoveAllEmbeddedObj;
FEmbeddedStreamList.Free; FEmbeddedObjList.Free;
FLog.Free; FLog.Free;
FreeAndNil(FSearchEngine); FreeAndNil(FSearchEngine);
@ -8356,44 +8363,61 @@ end;
Embedded streams are used to store embedded images. AName is normally the Embedded streams are used to store embedded images. AName is normally the
filename of the image. The image will be loaded to the stream later. filename of the image. The image will be loaded to the stream later.
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
function TsWorkbook.AddEmbeddedStream(const AName: String): Integer; function TsWorkbook.AddEmbeddedObj(const AName: String): Integer;
var
obj: TsEmbeddedObj = nil;
w, h: Double;
it: TsImageType;
begin begin
Result := FEmbeddedStreamList.Add(TsEmbeddedStream.Create(AName)); if not FileExists(AName) then
begin
AddErrorMsg(rsFileNotFound, [AName]);
Result := -1;
exit;
end;
try
obj := TsEmbeddedObj.Create(AName);
Result := FEmbeddedObjList.Add(obj);
except
AddErrorMsg(rsFileFormatNotSupported, [AName]);
Result := -1;
end;
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Checks whether an embedded stream with the specified name already exists. Checks whether an embedded object with the specified name already exists.
If yes, returns its index in the stream list, or -1 if no. If yes, returns its index in the object list, or -1 if no.
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
function TsWorkbook.FindEmbeddedStream(const AName: String): Integer; function TsWorkbook.FindEmbeddedObj(const AName: String): Integer;
var var
stream: TsEmbeddedStream; obj: TsEmbeddedObj;
begin begin
for Result:=0 to FEmbeddedStreamList.Count-1 do for Result:=0 to FEmbeddedObjList.Count-1 do
begin begin
stream := TsEmbeddedStream(FEmbeddedStreamList[Result]); obj := TsEmbeddedObj(FEmbeddedObjList[Result]);
if stream.Name = AName then if obj.Name = AName then
exit; exit;
end; end;
Result := -1; Result := -1;
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Returns the embedded stream stored in the embedded stream list at the Returns the embedded object stored in the embedded object list at the
specified index. specified index.
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
function TsWorkbook.GetEmbeddedStream(AIndex: Integer): TsEmbeddedStream; function TsWorkbook.GetEmbeddedObj(AIndex: Integer): TsEmbeddedObj;
begin begin
Result := TsEmbeddedStream(FEmbeddedStreamList[AIndex]); Result := TsEmbeddedObj(FEmbeddedObjList[AIndex]);
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Returns the count of embedded streams Returns the count of embedded objects
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
function TsWorkbook.GetEmbeddedStreamCount: Integer; function TsWorkbook.GetEmbeddedObjCount: Integer;
begin begin
Result := FEmbeddedStreamList.Count; Result := FEmbeddedObjList.Count;
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@ -8415,15 +8439,15 @@ begin
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Removes all embedded streams Removes all embedded objects
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsWorkbook.RemoveAllEmbeddedStreams; procedure TsWorkbook.RemoveAllEmbeddedObj;
var var
i: Integer; i: Integer;
begin begin
for i:= 0 to FEmbeddedStreamList.Count-1 do for i:= 0 to FEmbeddedObjList.Count-1 do
TsEmbeddedStream(FEmbeddedStreamList[i]).Free; TsEmbeddedObj(FEmbeddedObjList[i]).Free;
FEmbeddedStreamList.Clear; FEmbeddedObjList.Clear;
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------

View File

@ -61,6 +61,7 @@ resourcestring
rsIncorrectParamCount = 'Funtion %s requires at least %d and at most %d parameters.'; rsIncorrectParamCount = 'Funtion %s requires at least %d and at most %d parameters.';
rsCircularReference = 'Circular reference found when calculating worksheet formulas'; rsCircularReference = 'Circular reference found when calculating worksheet formulas';
rsFileNotFound = 'File "%s" not found.'; rsFileNotFound = 'File "%s" not found.';
rsFileFormatNotSupported = 'File format of "%s" not supported.';
rsFileAlreadyExists = 'File "%s" already exists.'; rsFileAlreadyExists = 'File "%s" already exists.';
rsWorksheetNotFound = 'Worksheet "%s" not found.'; rsWorksheetNotFound = 'Worksheet "%s" not found.';
rsWorksheetNotFound1 = 'Worksheet not found.'; rsWorksheetNotFound1 = 'Worksheet not found.';
@ -82,6 +83,9 @@ resourcestring
rsCodePageNotSupported = 'Code page "%s" is not supported. Using "cp1252" (Latin 1) instead.'; rsCodePageNotSupported = 'Code page "%s" is not supported. Using "cp1252" (Latin 1) instead.';
rsFormulaNotSupported = 'The formula in cell %s is not supported by this file format: %s'; rsFormulaNotSupported = 'The formula in cell %s is not supported by this file format: %s';
rsCannotSortMerged = 'The cell range cannot be sorted because it contains merged cells.';
// Hyperlinks
rsNoValidHyperlinkInternal = 'The hyperlink "%s" is not a valid cell address.'; rsNoValidHyperlinkInternal = 'The hyperlink "%s" is not a valid cell address.';
rsNoValidHyperlinkURI = 'The hyperlink "%s" is not a valid URI.'; rsNoValidHyperlinkURI = 'The hyperlink "%s" is not a valid URI.';
rsLocalFileHyperlinkAbs = 'The hyperlink "%s" points to a local file. ' + rsLocalFileHyperlinkAbs = 'The hyperlink "%s" points to a local file. ' +
@ -90,8 +94,6 @@ resourcestring
rsODSHyperlinksOfTextCellsOnly = 'Cell %s: OpenDocument supports hyperlinks for text cells only.'; rsODSHyperlinksOfTextCellsOnly = 'Cell %s: OpenDocument supports hyperlinks for text cells only.';
rsStdHyperlinkTooltip = 'Hold the left mouse button down for a short time to activate the hyperlink.'; rsStdHyperlinkTooltip = 'Hold the left mouse button down for a short time to activate the hyperlink.';
rsCannotSortMerged = 'The cell range cannot be sorted because it contains merged cells.';
// PageLayout // PageLayout
rsDifferentSheetPrintRange = 'Print range "%s" requires a different worksheet.'; rsDifferentSheetPrintRange = 'Print range "%s" requires a different worksheet.';
rsFooter = 'Footer'; rsFooter = 'Footer';

View File

@ -4,6 +4,7 @@
unit laz_fpspreadsheet; unit laz_fpspreadsheet;
{$warn 5023 off : no warning about unused units}
interface interface
uses uses

View File

@ -4,6 +4,7 @@
unit laz_fpspreadsheet_visual; unit laz_fpspreadsheet_visual;
{$warn 5023 off : no warning about unused units}
interface interface
uses uses

View File

@ -4,6 +4,7 @@
unit laz_fpspreadsheetexport_visual; unit laz_fpspreadsheetexport_visual;
{$warn 5023 off : no warning about unused units}
interface interface
uses uses

View File

@ -227,7 +227,7 @@ implementation
uses uses
variants, strutils, math, lazutf8, LazFileUtils, uriparser, variants, strutils, math, lazutf8, LazFileUtils, uriparser,
{%H-}fpsPatches, {%H-}fpsPatches,
fpsStrings, fpsStreams, fpsNumFormatParser, fpsClasses, fpsStrings, fpsStreams, fpsNumFormatParser, fpsClasses, fpsImages,
fpsRegFileFormats; fpsRegFileFormats;
const const
@ -3284,7 +3284,7 @@ begin
roffs1, coffs1, roffs2, coffs2, // mm roffs1, coffs1, roffs2, coffs2, // mm
x, y, w, h) // mm x, y, w, h) // mm
then begin then begin
FWorkbook.AddErrorMsg('Failure reading image "%s"', [FWorkbook.GetEmbeddedStream(img.Index).Name]); FWorkbook.AddErrorMsg('Failure reading image "%s"', [FWorkbook.GetEmbeddedObj(img.Index).Name]);
continue; continue;
end; end;
AppendToStream(FSDrawings[FCurSheetNum], AppendToStream(FSDrawings[FCurSheetNum],
@ -3334,7 +3334,7 @@ begin
'</xdr:spPr>'+ '</xdr:spPr>'+
'</xdr:pic>' + '</xdr:pic>' +
'<xdr:clientData/>', [ '<xdr:clientData/>', [
i+2, i+1, ExtractFilename(Workbook.GetEmbeddedStream(img.Index).Name), i+2, i+1, ExtractFilename(Workbook.GetEmbeddedObj(img.Index).Name),
i+1, i+1,
mmToEMU(x), mmToEMU(y), mmToEMU(x), mmToEMU(y),
mmToEMU(w), mmToEMU(h) mmToEMU(w), mmToEMU(h)
@ -3370,9 +3370,9 @@ begin
for i:=0 to AWorksheet.GetImageCount - 1 do for i:=0 to AWorksheet.GetImageCount - 1 do
begin begin
img := AWorksheet.GetImage(i); img := AWorksheet.GetImage(i);
ext := ExtractFileExt(FWorkbook.GetEmbeddedStream(img.Index).Name); ext := GetImageTypeExt(FWorkbook.GetEmbeddedObj(img.Index).Imagetype);
AppendToStream(FSDrawingsRels[FCurSheetNum], Format( AppendToStream(FSDrawingsRels[FCurSheetNum], Format(
' <Relationship Id="rId%d" Type="%s" Target="../media/image%d%s"/>' + LineEnding, [ ' <Relationship Id="rId%d" Type="%s" Target="../media/image%d.%s"/>' + LineEnding, [
i+1, SCHEMAS_IMAGE, img.Index+1, ext i+1, SCHEMAS_IMAGE, img.Index+1, ext
])); ]));
end; end;
@ -3565,8 +3565,7 @@ procedure TsSpreadOOXMLWriter.WriteVMLDrawings_HeaderFooterImages(
FWorkbook.AddErrorMsg(rsIncorrectPositionOfImageInHeaderFooter, [AName]); FWorkbook.AddErrorMsg(rsIncorrectPositionOfImageInHeaderFooter, [AName]);
exit; exit;
end; end;
fn := Workbook.GetEmbeddedStream(AImage.Index).Name; fn := ChangeFileExt(Workbook.GetEmbeddedObj(AImage.Index).Name, '');
fn := ChangeFileExt(ExtractFileName(fn), '');
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
' <v:shape id="%s" o:spid="_x0000_s%d" type="#_x0000_t75"' + LineEnding + ' <v:shape id="%s" o:spid="_x0000_s%d" type="#_x0000_t75"' + LineEnding +
// e.g. "CH" _x0000_s1025 // e.g. "CH" _x0000_s1025
@ -3705,8 +3704,9 @@ begin
img := AWorksheet.PageLayout.HeaderImages[sec]; img := AWorksheet.PageLayout.HeaderImages[sec];
if img.Index = -1 then if img.Index = -1 then
continue; continue;
imgName := FWorkbook.GetEmbeddedStream(img.Index).Name; imgName := FWorkbook.GetEmbeddedObj(img.Index).Name;
imgIdx := FWorkbook.FindEmbeddedStream(imgName); imgIdx := img.Index;
// imgIdx := FWorkbook.FindEmbeddedObj(imgName);
AppendToStream(FSVmlDrawingsRels[fileIndex], Format( AppendToStream(FSVmlDrawingsRels[fileIndex], Format(
' <Relationship Id="rId%d" Target="../media/image%d%s" '+ ' <Relationship Id="rId%d" Target="../media/image%d%s" '+
'Type="' + SCHEMAS_IMAGE + '" />' + LineEnding, [ 'Type="' + SCHEMAS_IMAGE + '" />' + LineEnding, [
@ -3721,8 +3721,9 @@ begin
img := AWorksheet.PageLayout.FooterImages[sec]; img := AWorksheet.PageLayout.FooterImages[sec];
if img.Index = -1 then if img.Index = -1 then
continue; continue;
imgName := FWorkbook.GetEmbeddedStream(img.Index).Name; imgName := FWorkbook.GetEmbeddedObj(img.Index).Name;
imgIdx := FWorkbook.FindEmbeddedStream(imgName); imgIdx := img.Index;
// imgIdx := FWorkbook.FindEmbeddedObj(imgName);
AppendToStream(FSVmlDrawingsRels[fileIndex], Format( AppendToStream(FSVmlDrawingsRels[fileIndex], Format(
' <Relationship Id="rId%d" Target="../media/image%d%s" '+ // ' <Relationship Id="rId%d" Target="../media/image%d%s" '+ //
// e.g. "rId1" "..(media/image1.png" // e.g. "rId1" "..(media/image1.png"
@ -3891,15 +3892,19 @@ end;
procedure TsSpreadOOXMLWriter.WriteMedia(AZip: TZipper); procedure TsSpreadOOXMLWriter.WriteMedia(AZip: TZipper);
var var
i: Integer; i: Integer;
embStream: TsEmbeddedStream; stream: TMemoryStream;
embObj: TsEmbeddedObj;
embName: String; embName: String;
ext: String;
begin begin
for i:=0 to FWorkbook.GetEmbeddedStreamCount-1 do for i:=0 to FWorkbook.GetEmbeddedObjCount-1 do
begin begin
embStream := FWorkbook.GetEmbeddedStream(i); embObj := FWorkbook.GetEmbeddedObj(i);
embStream.Position := 0; stream := embObj.Stream;
embName := Format('image%d', [i+1]) + ExtractFileExt(embStream.Name); stream.Position := 0;
AZip.Entries.AddFileEntry(embStream, OOXML_PATH_XL_MEDIA + embname); ext := GetImageTypeExt(embObj.ImageType);
embName := Format('image%d.%s', [i+1, ext]);
AZip.Entries.AddFileEntry(stream, OOXML_PATH_XL_MEDIA + embname);
end; end;
end; end;
@ -3979,14 +3984,13 @@ begin
AppendToStream(FSContentTypes, Format( AppendToStream(FSContentTypes, Format(
'<Default Extension="vml" ContentType="%s" />' + LineEnding, [MIME_VMLDRAWING])); '<Default Extension="vml" ContentType="%s" />' + LineEnding, [MIME_VMLDRAWING]));
if Workbook.GetEmbeddedStreamCount > 0 then if Workbook.GetEmbeddedObjCount > 0 then
begin begin
imgExt := TStringList.Create; imgExt := TStringList.Create;
try try
for i:=0 to Workbook.GetEmbeddedStreamCount-1 do for i:=0 to Workbook.GetEmbeddedObjCount-1 do
begin begin
ext := ExtractFileExt(Workbook.GetEmbeddedStream(i).Name); ext := GetImageTypeExt(Workbook.GetEmbeddedObj(i).ImageType);
if ext[1] = '.' then Delete(ext, 1, 1);
j := imgExt.IndexOf(ext); j := imgExt.IndexOf(ext);
if j = -1 then if j = -1 then
imgExt.Add(ext); imgExt.Add(ext);