fpspreadsheet: Read default column width and row height from biff and ooxml files

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3532 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-09-09 11:42:20 +00:00
parent b60590d691
commit cfb50bf064
8 changed files with 245 additions and 179 deletions

View File

@ -251,7 +251,7 @@ const
FALSE_TRUE: Array[boolean] of String = ('false', 'true');
COLWIDTH_EPS = 1e-2; // for mm
COLWIDTH_EPS = 1e-2; // for mm
ROWHEIGHT_EPS = 1e-2; // for lines
type

View File

@ -1066,11 +1066,13 @@ type
FVirtualCell: TCell;
{@@ Stores if the reader is in virtual mode }
FIsVirtualMode: Boolean;
{ Helper methods }
{@@ Removes column records if all of them have the same column width }
procedure FixCols(AWorksheet: TsWorksheet);
{@@ Removes row records if all of them have the same row height }
procedure FixRows(AWorksheet: TsWorksheet);
{ Record reading methods }
{@@ Abstract method for reading a blank cell. Must be overridden by descendent classes. }
procedure ReadBlank(AStream: TStream); virtual; abstract;
@ -6583,9 +6585,9 @@ end;
{@@
Deletes unnecessary column records as they are written by Office applications
when converting a file to another format.
when they convert a file to another format.
@param AWorksheet The columns in this worksheet are processed.
@param AWorksheet The columns in this worksheet are processed.
}
procedure TsCustomSpreadReader.FixCols(AWorkSheet: TsWorksheet);
const
@ -6593,20 +6595,10 @@ const
var
c: Cardinal;
w: Single;
cLast: Cardinal;
begin
if AWorksheet.Cols.Count = 0 then
if AWorksheet.Cols.Count <= 1 then
exit;
(* Better to avoid this...
// Delete all column records after the last column containing an existing cell.
cLast := AWorksheet.GetLastOccupiedColIndex;
for c := AWorksheet.Cols.Count-1 downto 0 do
if PCol(AWorksheet.Cols[c])^.Col > cLast then
AWorksheet.RemoveCol(c);
*)
// Check whether all columns have the same column width
w := PCol(AWorksheet.Cols[0])^.Width;
for c := 1 to AWorksheet.Cols.Count-1 do
@ -6617,11 +6609,6 @@ begin
// to the DefaultColWidth and delete all column records.
AWorksheet.DefaultColWidth := w;
AWorksheet.RemoveAllCols;
// To do:
// There's probably more to be done here, such as:
// - if all columns have the same width except for a few use their width as
// DefaultColWidth and delete these records.
end;
{@@
@ -6637,18 +6624,9 @@ var
rLast: Cardinal;
h: Single;
begin
if AWorksheet.Rows.Count = 0 then
if AWorksheet.Rows.Count <= 1 then
exit;
(* Better to avoid this...
// Delete all row records after the last row containing an existing cell.
rLast := AWorksheet.GetLastOccupiedRowIndex;
for r := AWorksheet.Rows.Count-1 downto 0 do
if PRow(AWorksheet.Rows[r])^.Row > rLast then
AWorksheet.RemoveRow(r);
*)
// Check whether all rows have the same height
h := PRow(AWorksheet.Rows[0])^.Height;
for r := 1 to AWorksheet.Rows.Count-1 do
@ -6659,11 +6637,6 @@ begin
// to the DefaultRowHeight and delete all row records.
AWorksheet.DefaultRowHeight := h;
AWorksheet.RemoveAllRows;
// To do:
// There's probably more to be done here, such as:
// - if all rows have the same height except for a few use their height as
// DefaultRowHeight and delete these records.
end;
{@@

View File

@ -957,7 +957,8 @@ begin
numBytes := 2;
Move(FBuffer[FBufferIndex], w, numbytes);
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
w := WordLEToN(w);
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d (%f characters)', [w, w/256]),
'Width of the columns in 1/256 of the width of the zero character, using default font (first FONT record in the file)');
numBytes := 2;

View File

@ -66,6 +66,7 @@ type
out ANumberFormat: TsNumberFormat; out ANumberFormatStr: String); override;
procedure ReadBlank(AStream: TStream); override;
procedure ReadColWidth(AStream: TStream);
procedure ReadDefRowHeight(AStream: TStream);
procedure ReadFont(AStream: TStream);
procedure ReadFontColor(AStream: TStream);
procedure ReadFormat(AStream: TStream); override;
@ -161,25 +162,26 @@ uses
const
{ Excel record IDs }
INT_EXCEL_ID_DIMENSIONS = $0000;
INT_EXCEL_ID_BLANK = $0001;
INT_EXCEL_ID_INTEGER = $0002;
INT_EXCEL_ID_NUMBER = $0003;
INT_EXCEL_ID_LABEL = $0004;
INT_EXCEL_ID_ROW = $0008;
INT_EXCEL_ID_BOF = $0009;
{%H-}INT_EXCEL_ID_INDEX = $000B;
INT_EXCEL_ID_FORMAT = $001E;
INT_EXCEL_ID_FORMATCOUNT= $001F;
INT_EXCEL_ID_COLWIDTH = $0024;
INT_EXCEL_ID_WINDOW2 = $003E;
INT_EXCEL_ID_XF = $0043;
INT_EXCEL_ID_IXFE = $0044;
INT_EXCEL_ID_FONTCOLOR = $0045;
INT_EXCEL_ID_DIMENSIONS = $0000;
INT_EXCEL_ID_BLANK = $0001;
INT_EXCEL_ID_INTEGER = $0002;
INT_EXCEL_ID_NUMBER = $0003;
INT_EXCEL_ID_LABEL = $0004;
INT_EXCEL_ID_ROW = $0008;
INT_EXCEL_ID_BOF = $0009;
{%H-}INT_EXCEL_ID_INDEX = $000B;
INT_EXCEL_ID_FORMAT = $001E;
INT_EXCEL_ID_FORMATCOUNT = $001F;
INT_EXCEL_ID_COLWIDTH = $0024;
INT_EXCEL_ID_DEFROWHEIGHT = 00025;
INT_EXCEL_ID_WINDOW2 = $003E;
INT_EXCEL_ID_XF = $0043;
INT_EXCEL_ID_IXFE = $0044;
INT_EXCEL_ID_FONTCOLOR = $0045;
{ BOF record constants }
INT_EXCEL_SHEET = $0010;
{%H-}INT_EXCEL_CHART = $0020;
INT_EXCEL_SHEET = $0010;
{%H-}INT_EXCEL_CHART = $0020;
{%H-}INT_EXCEL_MACRO_SHEET = $0040;
type
@ -423,9 +425,7 @@ var
c, c1, c2: Cardinal;
w: Word;
col: TCol;
sheet: TsWorksheet;
begin
sheet := Workbook.GetFirstWorksheet;
// read column start and end index of column range
c1 := AStream.ReadByte;
c2 := AStream.ReadByte;
@ -433,9 +433,21 @@ begin
w := WordLEToN(AStream.ReadWord);
// calculate width in units of "characters"
col.Width := w / 256;
// assign width to columns
for c := c1 to c2 do
sheet.WriteColInfo(c, col);
// assign width to columns, but only if different from default column width.
if not SameValue(col.Width, FWorksheet.DefaultColWidth) then
for c := c1 to c2 do
FWorksheet.WriteColInfo(c, col);
end;
procedure TsSpreadBIFF2Reader.ReadDefRowHeight(AStream: TStream);
var
hw: word;
h : Single;
begin
hw := WordLEToN(AStream.ReadWord);
h := TwipsToPts(hw and $8000) / FWorkbook.GetDefaultFontSize;
if h > ROW_HEIGHT_CORRECTION then
FWorksheet.DefaultRowHeight := h - ROW_HEIGHT_CORRECTION;
end;
procedure TsSpreadBIFF2Reader.ReadFont(AStream: TStream);
@ -509,22 +521,24 @@ begin
CurStreamPos := AStream.Position;
case RecordType of
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_FONT : ReadFont(AStream);
INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
INT_EXCEL_ID_INTEGER : ReadInteger(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_XF : ReadXF(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_EOF : BIFF2EOF := True;
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_FONT : ReadFont(AStream);
INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
INT_EXCEL_ID_INTEGER : ReadInteger(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream);
INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_DEFROWHEIGHT: ReadDefRowHeight(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_XF : ReadXF(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_EOF : BIFF2EOF := True;
else
// nothing
end;

View File

@ -82,13 +82,14 @@ type
FCurrentWorksheet: Integer;
protected
{ Record writing methods }
procedure ReadBoundsheet(AStream: TStream);
procedure ReadFont(const AStream: TStream);
procedure ReadFormat(AStream: TStream); override;
procedure ReadLabel(AStream: TStream); override;
procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook);
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
procedure ReadBoundsheet(AStream: TStream);
procedure ReadRichString(AStream: TStream);
procedure ReadStandardWidth(AStream: TStream; ASheet: TsWorksheet);
procedure ReadStringRecord(AStream: TStream); override;
procedure ReadXF(AStream: TStream);
public
@ -221,38 +222,39 @@ const
// see: in xlscommon
{ BOF record constants }
INT_BOF_BIFF5_VER = $0500;
INT_BOF_WORKBOOK_GLOBALS= $0005;
{%H-}INT_BOF_VB_MODULE = $0006;
INT_BOF_SHEET = $0010;
{%H-}INT_BOF_CHART = $0020;
{%H-}INT_BOF_MACRO_SHEET = $0040;
{%H-}INT_BOF_WORKSPACE = $0100;
INT_BOF_BUILD_ID = $1FD2;
INT_BOF_BUILD_YEAR = $07CD;
INT_BOF_BIFF5_VER = $0500;
INT_BOF_WORKBOOK_GLOBALS = $0005;
{%H-}INT_BOF_VB_MODULE = $0006;
INT_BOF_SHEET = $0010;
{%H-}INT_BOF_CHART = $0020;
{%H-}INT_BOF_MACRO_SHEET = $0040;
{%H-}INT_BOF_WORKSPACE = $0100;
INT_BOF_BUILD_ID = $1FD2;
INT_BOF_BUILD_YEAR = $07CD;
{ Record IDs }
INT_EXCEL_ID_STANDARDWIDTH = $0099;
{ FONT record constants }
INT_FONT_WEIGHT_NORMAL = $0190;
{%H-}BYTE_ANSILatin1 = $00;
{%H-}BYTE_SYSTEM_DEFAULT = $01;
{%H-}BYTE_SYMBOL = $02;
{%H-}BYTE_Apple_Roman = $4D;
{%H-}BYTE_ANSILatin1 = $00;
{%H-}BYTE_SYSTEM_DEFAULT = $01;
{%H-}BYTE_SYMBOL = $02;
{%H-}BYTE_Apple_Roman = $4D;
{%H-}BYTE_ANSI_Japanese_Shift_JIS = $80;
{%H-}BYTE_ANSI_Korean_Hangul = $81;
{%H-}BYTE_ANSI_Korean_Johab = $81;
{%H-}BYTE_ANSI_Korean_Hangul = $81;
{%H-}BYTE_ANSI_Korean_Johab = $81;
{%H-}BYTE_ANSI_Chinese_Simplified_GBK = $86;
{%H-}BYTE_ANSI_Chinese_Traditional_BIG5 = $88;
{%H-}BYTE_ANSI_Greek = $A1;
{%H-}BYTE_ANSI_Turkish = $A2;
{%H-}BYTE_ANSI_Vietnamese = $A3;
{%H-}BYTE_ANSI_Hebrew = $B1;
{%H-}BYTE_ANSI_Arabic = $B2;
{%H-}BYTE_ANSI_Baltic = $BA;
{%H-}BYTE_ANSI_Cyrillic = $CC;
{%H-}BYTE_ANSI_Thai = $DE;
{%H-}BYTE_ANSI_Latin2 = $EE;
{%H-}BYTE_OEM_Latin1 = $FF;
{%H-}BYTE_ANSI_Greek = $A1;
{%H-}BYTE_ANSI_Turkish = $A2;
{%H-}BYTE_ANSI_Vietnamese = $A3;
{%H-}BYTE_ANSI_Hebrew = $B1;
{%H-}BYTE_ANSI_Arabic = $B2;
{%H-}BYTE_ANSI_Baltic = $BA;
{%H-}BYTE_ANSI_Cyrillic = $CC;
{%H-}BYTE_ANSI_Thai = $DE;
{%H-}BYTE_ANSI_Latin2 = $EE;
{%H-}BYTE_OEM_Latin1 = $FF;
{ FORMULA record constants }
{%H-}MASK_FORMULA_RECALCULATE_ALWAYS = $0001;
@ -1160,22 +1162,24 @@ begin
case RecordType of
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_RSTRING : ReadRichString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard.
INT_EXCEL_ID_RK : ReadRKValue(AStream); //(RK) This record represents a cell that contains an RK value (encoded integer or floating-point value). If a floating-point value cannot be encoded to an RK value, a NUMBER record will be written. This record replaces the record INTEGER written in BIFF2.
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_SHAREDFMLA: ReadSharedFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_EOF : SectionEOF := True;
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_RSTRING : ReadRichString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard.
INT_EXCEL_ID_RK : ReadRKValue(AStream); //(RK) This record represents a cell that contains an RK value (encoded integer or floating-point value). If a floating-point value cannot be encoded to an RK value, a NUMBER record will be written. This record replaces the record INTEGER written in BIFF2.
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_STANDARDWIDTH : ReadStandardWidth(AStream, FWorksheet);
INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_EOF : SectionEOF := True;
{$IFDEF FPSPREADDEBUG} // Only write out if debugging
else
@ -1291,6 +1295,20 @@ begin
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
end;
{ Reads the default column width that is used when a bit in the GCW bit structure
is set for the corresponding column. The GCW is ignored here. The column
width read from the STANDARDWIDTH record overrides the one from the
DEFCOLWIDTH record. }
procedure TsSpreadBIFF5Reader.ReadStandardWidth(AStream: TStream; ASheet: TsWorksheet);
var
w: Word;
begin
// read width in 1/256 of the width of "0" character
w := WordLEToN(AStream.ReadWord);
// calculate width in units of "characters" and use it as DefaultColWidth
ASheet.DefaultColWidth := w / 256;
end;
{ Reads a STRING record which contains the result of string formula. }
procedure TsSpreadBIFF5Reader.ReadStringRecord(AStream: TStream);
var

View File

@ -1430,30 +1430,31 @@ begin
case RecordType of
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_SHAREDFMLA: ReadSharedFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
//(RSTRING) This record stores a formatted text cell (Rich-Text).
// In BIFF8 it is usually replaced by the LABELSST record. Excel still
// uses this record, if it copies formatted text cells to the clipboard.
INT_EXCEL_ID_RSTRING : ReadRichString(AStream);
INT_EXCEL_ID_RSTRING : ReadRichString(AStream);
// (RK) This record represents a cell that contains an RK value
// (encoded integer or floating-point value). If a floating-point
// value cannot be encoded to an RK value, a NUMBER record will be written.
// This record replaces the record INTEGER written in BIFF2.
INT_EXCEL_ID_RK : ReadRKValue(AStream);
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_LABELSST : ReadLabelSST(AStream); //BIFF8 only
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_EOF : SectionEOF := True;
INT_EXCEL_ID_RK : ReadRKValue(AStream);
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_LABELSST : ReadLabelSST(AStream); //BIFF8 only
INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream);
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_EOF : SectionEOF := True;
else
// nothing
end;

View File

@ -22,50 +22,52 @@ uses
const
{ RECORD IDs which didn't change across versions 2-8 }
INT_EXCEL_ID_EOF = $000A;
INT_EXCEL_ID_SELECTION = $001D;
INT_EXCEL_ID_CONTINUE = $003C;
INT_EXCEL_ID_PANE = $0041;
INT_EXCEL_ID_CODEPAGE = $0042;
INT_EXCEL_ID_DATEMODE = $0022;
INT_EXCEL_ID_WINDOW1 = $003D;
INT_EXCEL_ID_EOF = $000A;
INT_EXCEL_ID_SELECTION = $001D;
INT_EXCEL_ID_CONTINUE = $003C;
INT_EXCEL_ID_DATEMODE = $0022;
INT_EXCEL_ID_WINDOW1 = $003D;
INT_EXCEL_ID_PANE = $0041;
INT_EXCEL_ID_CODEPAGE = $0042;
INT_EXCEL_ID_DEFCOLWIDTH = $0055;
{ RECORD IDs which did not change across versions 2, 5, 8}
INT_EXCEL_ID_FORMULA = $0006; // BIFF3: $0206, BIFF4: $0406
INT_EXCEL_ID_FONT = $0031; // BIFF3-4: $0231
INT_EXCEL_ID_FORMULA = $0006; // BIFF3: $0206, BIFF4: $0406
INT_EXCEL_ID_FONT = $0031; // BIFF3-4: $0231
{ RECORD IDs which did not change across version 3-8}
INT_EXCEL_ID_COLINFO = $007D; // does not exist in BIFF2
INT_EXCEL_ID_SHEETPR = $0081; // does not exist in BIFF2
INT_EXCEL_ID_COUNTRY = $008C; // does not exist in BIFF2
INT_EXCEL_ID_PALETTE = $0092; // does not exist in BIFF2
INT_EXCEL_ID_DIMENSIONS = $0200; // BIFF2: $0000
INT_EXCEL_ID_BLANK = $0201; // BIFF2: $0001
INT_EXCEL_ID_NUMBER = $0203; // BIFF2: $0003
INT_EXCEL_ID_LABEL = $0204; // BIFF2: $0004
INT_EXCEL_ID_STRING = $0207; // BIFF2: $0007
INT_EXCEL_ID_ROW = $0208; // BIFF2: $0008
INT_EXCEL_ID_INDEX = $020B; // BIFF2: $000B
INT_EXCEL_ID_WINDOW2 = $023E; // BIFF2: $003E
INT_EXCEL_ID_RK = $027E; // does not exist in BIFF2
INT_EXCEL_ID_STYLE = $0293; // does not exist in BIFF2
INT_EXCEL_ID_COLINFO = $007D; // does not exist in BIFF2
INT_EXCEL_ID_SHEETPR = $0081; // does not exist in BIFF2
INT_EXCEL_ID_COUNTRY = $008C; // does not exist in BIFF2
INT_EXCEL_ID_PALETTE = $0092; // does not exist in BIFF2
INT_EXCEL_ID_DIMENSIONS = $0200; // BIFF2: $0000
INT_EXCEL_ID_BLANK = $0201; // BIFF2: $0001
INT_EXCEL_ID_NUMBER = $0203; // BIFF2: $0003
INT_EXCEL_ID_LABEL = $0204; // BIFF2: $0004
INT_EXCEL_ID_STRING = $0207; // BIFF2: $0007
INT_EXCEL_ID_ROW = $0208; // BIFF2: $0008
INT_EXCEL_ID_INDEX = $020B; // BIFF2: $000B
INT_EXCEL_ID_DEFROWHEIGHT= $0225; // BIFF2: $0025
INT_EXCEL_ID_WINDOW2 = $023E; // BIFF2: $003E
INT_EXCEL_ID_RK = $027E; // does not exist in BIFF2
INT_EXCEL_ID_STYLE = $0293; // does not exist in BIFF2
{ RECORD IDs which did not change across version 4-8 }
INT_EXCEL_ID_PAGESETUP = $00A1; // does not exist before BIFF4
INT_EXCEL_ID_FORMAT = $041E; // BIFF2-3: $001E
INT_EXCEL_ID_PAGESETUP = $00A1; // does not exist before BIFF4
INT_EXCEL_ID_FORMAT = $041E; // BIFF2-3: $001E
{ RECORD IDs which did not change across versions 5-8 }
INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs, does not exist before 5
INT_EXCEL_ID_MULRK = $00BD; // does not exist before BIFF5
INT_EXCEL_ID_MULBLANK = $00BE; // does not exist before BIFF5
INT_EXCEL_ID_XF = $00E0; // BIFF2:$0043, BIFF3:$0243, BIFF4:$0443
INT_EXCEL_ID_RSTRING = $00D6; // does not exist before BIFF5
INT_EXCEL_ID_SHAREDFMLA = $04BC; // does not exist before BIFF5
INT_EXCEL_ID_BOF = $0809; // BIFF2:$0009, BIFF3:$0209; BIFF4:$0409
INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs, does not exist before 5
INT_EXCEL_ID_MULRK = $00BD; // does not exist before BIFF5
INT_EXCEL_ID_MULBLANK = $00BE; // does not exist before BIFF5
INT_EXCEL_ID_XF = $00E0; // BIFF2:$0043, BIFF3:$0243, BIFF4:$0443
INT_EXCEL_ID_RSTRING = $00D6; // does not exist before BIFF5
INT_EXCEL_ID_SHAREDFMLA = $04BC; // does not exist before BIFF5
INT_EXCEL_ID_BOF = $0809; // BIFF2:$0009, BIFF3:$0209; BIFF4:$0409
{ FONT record constants }
INT_FONT_WEIGHT_NORMAL = $0190;
INT_FONT_WEIGHT_BOLD = $02BC;
INT_FONT_WEIGHT_NORMAL = $0190;
INT_FONT_WEIGHT_BOLD = $02BC;
{ CODEPAGE record constants }
WORD_ASCII = 367;
@ -82,8 +84,8 @@ const
WORD_CP_1258_Latin1_BIFF2_3 = 32769; // BIFF2-BIFF3
{ DATEMODE record, 5.28 }
DATEMODE_1900_BASE=1; //1/1/1900 minus 1 day in FPC TDateTime
DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime
DATEMODE_1900_BASE = 1; //1/1/1900 minus 1 day in FPC TDateTime
DATEMODE_1904_BASE = 1462; //1/1/1904 in FPC TDateTime
{ WINDOW1 record constants - BIFF5-BIFF8 }
MASK_WINDOW1_OPTION_WINDOW_HIDDEN = $0001;
@ -245,6 +247,10 @@ type
procedure ReadColInfo(const AStream: TStream);
// Figures out what the base year for dates is for this file
procedure ReadDateMode(AStream: TStream);
// Reads the default column width
procedure ReadDefColWidth(AStream: TStream);
// Reas the default row height
procedure ReadDefRowHeight(AStream: TStream);
// Read FORMAT record (cell formatting)
procedure ReadFormat(AStream: TStream); virtual;
// Read FORMULA record
@ -963,6 +969,8 @@ end;
Valid for BIFF3-BIFF8.
For BIFF2 use the records COLWIDTH and COLUMNDEFAULT. }
procedure TsSpreadBiffReader.ReadColInfo(const AStream: TStream);
const
EPS = 1E-2; // allow for large epsilon because col width calculation is not very well-defined...
var
c, c1, c2: Cardinal;
w: Word;
@ -975,9 +983,10 @@ begin
w := WordLEToN(AStream.ReadWord);
// calculate width in units of "characters"
col.Width := w / 256;
// assign width to columns
for c := c1 to c2 do
FWorksheet.WriteColInfo(c, col);
// assign width to columns, but only if different from default column width
if not SameValue(col.Width, FWorksheet.DefaultColWidth, EPS) then
for c := c1 to c2 do
FWorksheet.WriteColInfo(c, col);
end;
procedure TsSpreadBIFFReader.ReadDateMode(AStream: TStream);
@ -1002,6 +1011,30 @@ begin
end;
end;
// Reads the default column width
procedure TsSpreadBIFFReader.ReadDefColWidth(AStream: TStream);
begin
// The file contains the column width in characters
FWorksheet.DefaultColWidth := WordLEToN(AStream.ReadWord);
end;
// Reads the default row height
// Valid for BIFF3 - BIFF8 (override for BIFF2)
procedure TsSpreadBIFFReader.ReadDefRowHeight(AStream: TStream);
var
options, hw: Word;
h: Single;
begin
// Options
AStream.ReadWord;
// Height, in Twips (1/20 pt).
hw := WordLEToN(AStream.ReadWord);
h := TwipsToPts(hw) / FWorkbook.GetDefaultFontSize;
if h > ROW_HEIGHT_CORRECTION then
FWorksheet.DefaultRowHeight := h - ROW_HEIGHT_CORRECTION;
end;
// Read the FORMAT record for formatting numerical data
procedure TsSpreadBIFFReader.ReadFormat(AStream: TStream);
begin

View File

@ -80,6 +80,7 @@ type
procedure ReadPalette(ANode: TDOMNode);
procedure ReadRowHeight(ANode: TDOMNode; AWorksheet: TsWorksheet);
procedure ReadSharedStrings(ANode: TDOMNode);
procedure ReadSheetFormatPr(ANode: TDOMNode; AWorksheet: TsWorksheet);
procedure ReadSheetList(ANode: TDOMNode; AList: TStrings);
procedure ReadSheetViews(ANode: TDOMNode; AWorksheet: TsWorksheet);
procedure ReadThemeElements(ANode: TDOMNode);
@ -866,6 +867,8 @@ begin
end;
procedure TsSpreadOOXMLReader.ReadCols(ANode: TDOMNode; AWorksheet: TsWorksheet);
const
EPS = 1e-2;
var
colNode: TDOMNode;
col, col1, col2: Cardinal;
@ -884,11 +887,10 @@ begin
s := GetAttrValue(colNode, 'max');
if s <> '' then col2 := StrToInt(s)-1 else col2 := col1;
s := GetAttrValue(colNode, 'width');
if s <> '' then begin
w := StrToFloat(s, FPointSeparatorSettings);
for col := col1 to col2 do
AWorksheet.WriteColWidth(col, w);
end;
if (s <> '') and TryStrToFloat(s, w, FPointSeparatorSettings) then
if not SameValue(w, AWorksheet.DefaultColWidth, EPS) then
for col := col1 to col2 do
AWorksheet.WriteColWidth(col, w);
end;
colNode := colNode.NextSibling;
end;
@ -1189,6 +1191,29 @@ begin
end;
end;
procedure TsSpreadOOXMLReader.ReadSheetFormatPr(ANode: TDOMNode;
AWorksheet: TsWorksheet);
var
w, h: Single;
s: String;
begin
if ANode = nil then
exit;
s := GetAttrValue(ANode, 'defaultColWidth'); // is in characters
if (s <> '') and TryStrToFloat(s, w, FPointSeparatorSettings) then
AWorksheet.DefaultColWidth := w;
s := GetAttrValue(ANode, 'defaultRowHeight'); // in in points
if (s <> '') and TryStrToFloat(s, h, FPointSeparatorSettings) then begin
h := h / Workbook.GetDefaultFontSize;
if h > ROW_HEIGHT_CORRECTION then begin
h := h - ROW_HEIGHT_CORRECTION;
AWorksheet.DefaultRowHeight := h;
end;
end;
end;
procedure TsSpreadOOXMLReader.ReadSheetList(ANode: TDOMNode; AList: TStrings);
var
node: TDOMNode;
@ -1340,8 +1365,8 @@ begin
end;
rownode := rownode.NextSibling;
end;
FixRows(AWorksheet);
FixCols(AWorksheet);
FixRows(AWorksheet);
end;
procedure TsSpreadOOXMLReader.ReadFromFile(AFileName: string; AData: TsWorkbook);
@ -1440,6 +1465,7 @@ begin
FWorksheet := AData.AddWorksheet(SheetList[i]);
ReadSheetViews(Doc.DocumentElement.FindNode('sheetViews'), FWorksheet);
ReadSheetFormatPr(Doc.DocumentElement.FindNode('sheetFormatPr'), FWorksheet);
ReadCols(Doc.DocumentElement.FindNode('cols'), FWorksheet);
ReadWorksheet(Doc.DocumentElement.FindNode('sheetData'), FWorksheet);