Fix the error on getting the range of merged cells on the worksheet which contains one cell merged cell range

- Parse workbook default theme for custom theme color support in the feature
- Variables name typo fix
- Add system foreground and background color as RGB in the IndexedColorMapping list
This commit is contained in:
xuri 2022-10-28 00:31:55 +08:00
parent adf9d37d82
commit a410b22bdd
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
17 changed files with 355 additions and 320 deletions

388
calc.go
View File

@ -59,19 +59,19 @@ const (
criteriaErr criteriaErr
criteriaRegexp criteriaRegexp
catgoryWeightAndMass categoryWeightAndMass
catgoryDistance categoryDistance
catgoryTime categoryTime
catgoryPressure categoryPressure
catgoryForce categoryForce
catgoryEnergy categoryEnergy
catgoryPower categoryPower
catgoryMagnetism categoryMagnetism
catgoryTemperature categoryTemperature
catgoryVolumeAndLiquidMeasure categoryVolumeAndLiquidMeasure
catgoryArea categoryArea
catgoryInformation categoryInformation
catgorySpeed categorySpeed
matchModeExact = 0 matchModeExact = 0
matchModeMinGreater = 1 matchModeMinGreater = 1
@ -2144,177 +2144,177 @@ type conversionUnit struct {
// formula function CONVERT. // formula function CONVERT.
var conversionUnits = map[string]conversionUnit{ var conversionUnits = map[string]conversionUnit{
// weight and mass // weight and mass
"g": {group: catgoryWeightAndMass, allowPrefix: true}, "g": {group: categoryWeightAndMass, allowPrefix: true},
"sg": {group: catgoryWeightAndMass, allowPrefix: false}, "sg": {group: categoryWeightAndMass, allowPrefix: false},
"lbm": {group: catgoryWeightAndMass, allowPrefix: false}, "lbm": {group: categoryWeightAndMass, allowPrefix: false},
"u": {group: catgoryWeightAndMass, allowPrefix: true}, "u": {group: categoryWeightAndMass, allowPrefix: true},
"ozm": {group: catgoryWeightAndMass, allowPrefix: false}, "ozm": {group: categoryWeightAndMass, allowPrefix: false},
"grain": {group: catgoryWeightAndMass, allowPrefix: false}, "grain": {group: categoryWeightAndMass, allowPrefix: false},
"cwt": {group: catgoryWeightAndMass, allowPrefix: false}, "cwt": {group: categoryWeightAndMass, allowPrefix: false},
"shweight": {group: catgoryWeightAndMass, allowPrefix: false}, "shweight": {group: categoryWeightAndMass, allowPrefix: false},
"uk_cwt": {group: catgoryWeightAndMass, allowPrefix: false}, "uk_cwt": {group: categoryWeightAndMass, allowPrefix: false},
"lcwt": {group: catgoryWeightAndMass, allowPrefix: false}, "lcwt": {group: categoryWeightAndMass, allowPrefix: false},
"hweight": {group: catgoryWeightAndMass, allowPrefix: false}, "hweight": {group: categoryWeightAndMass, allowPrefix: false},
"stone": {group: catgoryWeightAndMass, allowPrefix: false}, "stone": {group: categoryWeightAndMass, allowPrefix: false},
"ton": {group: catgoryWeightAndMass, allowPrefix: false}, "ton": {group: categoryWeightAndMass, allowPrefix: false},
"uk_ton": {group: catgoryWeightAndMass, allowPrefix: false}, "uk_ton": {group: categoryWeightAndMass, allowPrefix: false},
"LTON": {group: catgoryWeightAndMass, allowPrefix: false}, "LTON": {group: categoryWeightAndMass, allowPrefix: false},
"brton": {group: catgoryWeightAndMass, allowPrefix: false}, "brton": {group: categoryWeightAndMass, allowPrefix: false},
// distance // distance
"m": {group: catgoryDistance, allowPrefix: true}, "m": {group: categoryDistance, allowPrefix: true},
"mi": {group: catgoryDistance, allowPrefix: false}, "mi": {group: categoryDistance, allowPrefix: false},
"Nmi": {group: catgoryDistance, allowPrefix: false}, "Nmi": {group: categoryDistance, allowPrefix: false},
"in": {group: catgoryDistance, allowPrefix: false}, "in": {group: categoryDistance, allowPrefix: false},
"ft": {group: catgoryDistance, allowPrefix: false}, "ft": {group: categoryDistance, allowPrefix: false},
"yd": {group: catgoryDistance, allowPrefix: false}, "yd": {group: categoryDistance, allowPrefix: false},
"ang": {group: catgoryDistance, allowPrefix: true}, "ang": {group: categoryDistance, allowPrefix: true},
"ell": {group: catgoryDistance, allowPrefix: false}, "ell": {group: categoryDistance, allowPrefix: false},
"ly": {group: catgoryDistance, allowPrefix: false}, "ly": {group: categoryDistance, allowPrefix: false},
"parsec": {group: catgoryDistance, allowPrefix: false}, "parsec": {group: categoryDistance, allowPrefix: false},
"pc": {group: catgoryDistance, allowPrefix: false}, "pc": {group: categoryDistance, allowPrefix: false},
"Pica": {group: catgoryDistance, allowPrefix: false}, "Pica": {group: categoryDistance, allowPrefix: false},
"Picapt": {group: catgoryDistance, allowPrefix: false}, "Picapt": {group: categoryDistance, allowPrefix: false},
"pica": {group: catgoryDistance, allowPrefix: false}, "pica": {group: categoryDistance, allowPrefix: false},
"survey_mi": {group: catgoryDistance, allowPrefix: false}, "survey_mi": {group: categoryDistance, allowPrefix: false},
// time // time
"yr": {group: catgoryTime, allowPrefix: false}, "yr": {group: categoryTime, allowPrefix: false},
"day": {group: catgoryTime, allowPrefix: false}, "day": {group: categoryTime, allowPrefix: false},
"d": {group: catgoryTime, allowPrefix: false}, "d": {group: categoryTime, allowPrefix: false},
"hr": {group: catgoryTime, allowPrefix: false}, "hr": {group: categoryTime, allowPrefix: false},
"mn": {group: catgoryTime, allowPrefix: false}, "mn": {group: categoryTime, allowPrefix: false},
"min": {group: catgoryTime, allowPrefix: false}, "min": {group: categoryTime, allowPrefix: false},
"sec": {group: catgoryTime, allowPrefix: true}, "sec": {group: categoryTime, allowPrefix: true},
"s": {group: catgoryTime, allowPrefix: true}, "s": {group: categoryTime, allowPrefix: true},
// pressure // pressure
"Pa": {group: catgoryPressure, allowPrefix: true}, "Pa": {group: categoryPressure, allowPrefix: true},
"p": {group: catgoryPressure, allowPrefix: true}, "p": {group: categoryPressure, allowPrefix: true},
"atm": {group: catgoryPressure, allowPrefix: true}, "atm": {group: categoryPressure, allowPrefix: true},
"at": {group: catgoryPressure, allowPrefix: true}, "at": {group: categoryPressure, allowPrefix: true},
"mmHg": {group: catgoryPressure, allowPrefix: true}, "mmHg": {group: categoryPressure, allowPrefix: true},
"psi": {group: catgoryPressure, allowPrefix: true}, "psi": {group: categoryPressure, allowPrefix: true},
"Torr": {group: catgoryPressure, allowPrefix: true}, "Torr": {group: categoryPressure, allowPrefix: true},
// force // force
"N": {group: catgoryForce, allowPrefix: true}, "N": {group: categoryForce, allowPrefix: true},
"dyn": {group: catgoryForce, allowPrefix: true}, "dyn": {group: categoryForce, allowPrefix: true},
"dy": {group: catgoryForce, allowPrefix: true}, "dy": {group: categoryForce, allowPrefix: true},
"lbf": {group: catgoryForce, allowPrefix: false}, "lbf": {group: categoryForce, allowPrefix: false},
"pond": {group: catgoryForce, allowPrefix: true}, "pond": {group: categoryForce, allowPrefix: true},
// energy // energy
"J": {group: catgoryEnergy, allowPrefix: true}, "J": {group: categoryEnergy, allowPrefix: true},
"e": {group: catgoryEnergy, allowPrefix: true}, "e": {group: categoryEnergy, allowPrefix: true},
"c": {group: catgoryEnergy, allowPrefix: true}, "c": {group: categoryEnergy, allowPrefix: true},
"cal": {group: catgoryEnergy, allowPrefix: true}, "cal": {group: categoryEnergy, allowPrefix: true},
"eV": {group: catgoryEnergy, allowPrefix: true}, "eV": {group: categoryEnergy, allowPrefix: true},
"ev": {group: catgoryEnergy, allowPrefix: true}, "ev": {group: categoryEnergy, allowPrefix: true},
"HPh": {group: catgoryEnergy, allowPrefix: false}, "HPh": {group: categoryEnergy, allowPrefix: false},
"hh": {group: catgoryEnergy, allowPrefix: false}, "hh": {group: categoryEnergy, allowPrefix: false},
"Wh": {group: catgoryEnergy, allowPrefix: true}, "Wh": {group: categoryEnergy, allowPrefix: true},
"wh": {group: catgoryEnergy, allowPrefix: true}, "wh": {group: categoryEnergy, allowPrefix: true},
"flb": {group: catgoryEnergy, allowPrefix: false}, "flb": {group: categoryEnergy, allowPrefix: false},
"BTU": {group: catgoryEnergy, allowPrefix: false}, "BTU": {group: categoryEnergy, allowPrefix: false},
"btu": {group: catgoryEnergy, allowPrefix: false}, "btu": {group: categoryEnergy, allowPrefix: false},
// power // power
"HP": {group: catgoryPower, allowPrefix: false}, "HP": {group: categoryPower, allowPrefix: false},
"h": {group: catgoryPower, allowPrefix: false}, "h": {group: categoryPower, allowPrefix: false},
"W": {group: catgoryPower, allowPrefix: true}, "W": {group: categoryPower, allowPrefix: true},
"w": {group: catgoryPower, allowPrefix: true}, "w": {group: categoryPower, allowPrefix: true},
"PS": {group: catgoryPower, allowPrefix: false}, "PS": {group: categoryPower, allowPrefix: false},
"T": {group: catgoryMagnetism, allowPrefix: true}, "T": {group: categoryMagnetism, allowPrefix: true},
"ga": {group: catgoryMagnetism, allowPrefix: true}, "ga": {group: categoryMagnetism, allowPrefix: true},
// temperature // temperature
"C": {group: catgoryTemperature, allowPrefix: false}, "C": {group: categoryTemperature, allowPrefix: false},
"cel": {group: catgoryTemperature, allowPrefix: false}, "cel": {group: categoryTemperature, allowPrefix: false},
"F": {group: catgoryTemperature, allowPrefix: false}, "F": {group: categoryTemperature, allowPrefix: false},
"fah": {group: catgoryTemperature, allowPrefix: false}, "fah": {group: categoryTemperature, allowPrefix: false},
"K": {group: catgoryTemperature, allowPrefix: false}, "K": {group: categoryTemperature, allowPrefix: false},
"kel": {group: catgoryTemperature, allowPrefix: false}, "kel": {group: categoryTemperature, allowPrefix: false},
"Rank": {group: catgoryTemperature, allowPrefix: false}, "Rank": {group: categoryTemperature, allowPrefix: false},
"Reau": {group: catgoryTemperature, allowPrefix: false}, "Reau": {group: categoryTemperature, allowPrefix: false},
// volume // volume
"l": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: true}, "l": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
"L": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: true}, "L": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
"lt": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: true}, "lt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
"tsp": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "tsp": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"tspm": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "tspm": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"tbs": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "tbs": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"oz": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "oz": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"cup": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "cup": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"pt": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "pt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"us_pt": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "us_pt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"uk_pt": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "uk_pt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"qt": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "qt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"uk_qt": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "uk_qt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"gal": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "gal": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"uk_gal": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "uk_gal": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"ang3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: true}, "ang3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
"ang^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: true}, "ang^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
"barrel": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "barrel": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"bushel": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "bushel": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"in3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "in3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"in^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "in^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"ft3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "ft3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"ft^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "ft^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"ly3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "ly3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"ly^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "ly^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"m3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: true}, "m3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
"m^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: true}, "m^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
"mi3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "mi3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"mi^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "mi^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"yd3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "yd3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"yd^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "yd^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"Nmi3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "Nmi3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"Nmi^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "Nmi^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"Pica3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "Pica3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"Pica^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "Pica^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"Picapt3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "Picapt3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"Picapt^3": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "Picapt^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"GRT": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "GRT": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"regton": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "regton": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
"MTON": {group: catgoryVolumeAndLiquidMeasure, allowPrefix: false}, "MTON": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
// area // area
"ha": {group: catgoryArea, allowPrefix: true}, "ha": {group: categoryArea, allowPrefix: true},
"uk_acre": {group: catgoryArea, allowPrefix: false}, "uk_acre": {group: categoryArea, allowPrefix: false},
"us_acre": {group: catgoryArea, allowPrefix: false}, "us_acre": {group: categoryArea, allowPrefix: false},
"ang2": {group: catgoryArea, allowPrefix: true}, "ang2": {group: categoryArea, allowPrefix: true},
"ang^2": {group: catgoryArea, allowPrefix: true}, "ang^2": {group: categoryArea, allowPrefix: true},
"ar": {group: catgoryArea, allowPrefix: true}, "ar": {group: categoryArea, allowPrefix: true},
"ft2": {group: catgoryArea, allowPrefix: false}, "ft2": {group: categoryArea, allowPrefix: false},
"ft^2": {group: catgoryArea, allowPrefix: false}, "ft^2": {group: categoryArea, allowPrefix: false},
"in2": {group: catgoryArea, allowPrefix: false}, "in2": {group: categoryArea, allowPrefix: false},
"in^2": {group: catgoryArea, allowPrefix: false}, "in^2": {group: categoryArea, allowPrefix: false},
"ly2": {group: catgoryArea, allowPrefix: false}, "ly2": {group: categoryArea, allowPrefix: false},
"ly^2": {group: catgoryArea, allowPrefix: false}, "ly^2": {group: categoryArea, allowPrefix: false},
"m2": {group: catgoryArea, allowPrefix: true}, "m2": {group: categoryArea, allowPrefix: true},
"m^2": {group: catgoryArea, allowPrefix: true}, "m^2": {group: categoryArea, allowPrefix: true},
"Morgen": {group: catgoryArea, allowPrefix: false}, "Morgen": {group: categoryArea, allowPrefix: false},
"mi2": {group: catgoryArea, allowPrefix: false}, "mi2": {group: categoryArea, allowPrefix: false},
"mi^2": {group: catgoryArea, allowPrefix: false}, "mi^2": {group: categoryArea, allowPrefix: false},
"Nmi2": {group: catgoryArea, allowPrefix: false}, "Nmi2": {group: categoryArea, allowPrefix: false},
"Nmi^2": {group: catgoryArea, allowPrefix: false}, "Nmi^2": {group: categoryArea, allowPrefix: false},
"Pica2": {group: catgoryArea, allowPrefix: false}, "Pica2": {group: categoryArea, allowPrefix: false},
"Pica^2": {group: catgoryArea, allowPrefix: false}, "Pica^2": {group: categoryArea, allowPrefix: false},
"Picapt2": {group: catgoryArea, allowPrefix: false}, "Picapt2": {group: categoryArea, allowPrefix: false},
"Picapt^2": {group: catgoryArea, allowPrefix: false}, "Picapt^2": {group: categoryArea, allowPrefix: false},
"yd2": {group: catgoryArea, allowPrefix: false}, "yd2": {group: categoryArea, allowPrefix: false},
"yd^2": {group: catgoryArea, allowPrefix: false}, "yd^2": {group: categoryArea, allowPrefix: false},
// information // information
"byte": {group: catgoryInformation, allowPrefix: true}, "byte": {group: categoryInformation, allowPrefix: true},
"bit": {group: catgoryInformation, allowPrefix: true}, "bit": {group: categoryInformation, allowPrefix: true},
// speed // speed
"m/s": {group: catgorySpeed, allowPrefix: true}, "m/s": {group: categorySpeed, allowPrefix: true},
"m/sec": {group: catgorySpeed, allowPrefix: true}, "m/sec": {group: categorySpeed, allowPrefix: true},
"m/h": {group: catgorySpeed, allowPrefix: true}, "m/h": {group: categorySpeed, allowPrefix: true},
"m/hr": {group: catgorySpeed, allowPrefix: true}, "m/hr": {group: categorySpeed, allowPrefix: true},
"mph": {group: catgorySpeed, allowPrefix: false}, "mph": {group: categorySpeed, allowPrefix: false},
"admkn": {group: catgorySpeed, allowPrefix: false}, "admkn": {group: categorySpeed, allowPrefix: false},
"kn": {group: catgorySpeed, allowPrefix: false}, "kn": {group: categorySpeed, allowPrefix: false},
} }
// unitConversions maps details of the Units of measure conversion factors, // unitConversions maps details of the Units of measure conversion factors,
// organised by group. // organised by group.
var unitConversions = map[byte]map[string]float64{ var unitConversions = map[byte]map[string]float64{
// conversion uses gram (g) as an intermediate unit // conversion uses gram (g) as an intermediate unit
catgoryWeightAndMass: { categoryWeightAndMass: {
"g": 1, "g": 1,
"sg": 6.85217658567918e-05, "sg": 6.85217658567918e-05,
"lbm": 2.20462262184878e-03, "lbm": 2.20462262184878e-03,
@ -2333,7 +2333,7 @@ var unitConversions = map[byte]map[string]float64{
"brton": 9.84206527611061e-07, "brton": 9.84206527611061e-07,
}, },
// conversion uses meter (m) as an intermediate unit // conversion uses meter (m) as an intermediate unit
catgoryDistance: { categoryDistance: {
"m": 1, "m": 1,
"mi": 6.21371192237334e-04, "mi": 6.21371192237334e-04,
"Nmi": 5.39956803455724e-04, "Nmi": 5.39956803455724e-04,
@ -2351,7 +2351,7 @@ var unitConversions = map[byte]map[string]float64{
"survey_mi": 6.21369949494950e-04, "survey_mi": 6.21369949494950e-04,
}, },
// conversion uses second (s) as an intermediate unit // conversion uses second (s) as an intermediate unit
catgoryTime: { categoryTime: {
"yr": 3.16880878140289e-08, "yr": 3.16880878140289e-08,
"day": 1.15740740740741e-05, "day": 1.15740740740741e-05,
"d": 1.15740740740741e-05, "d": 1.15740740740741e-05,
@ -2362,7 +2362,7 @@ var unitConversions = map[byte]map[string]float64{
"s": 1, "s": 1,
}, },
// conversion uses Pascal (Pa) as an intermediate unit // conversion uses Pascal (Pa) as an intermediate unit
catgoryPressure: { categoryPressure: {
"Pa": 1, "Pa": 1,
"p": 1, "p": 1,
"atm": 9.86923266716013e-06, "atm": 9.86923266716013e-06,
@ -2372,7 +2372,7 @@ var unitConversions = map[byte]map[string]float64{
"Torr": 7.50061682704170e-03, "Torr": 7.50061682704170e-03,
}, },
// conversion uses Newton (N) as an intermediate unit // conversion uses Newton (N) as an intermediate unit
catgoryForce: { categoryForce: {
"N": 1, "N": 1,
"dyn": 1.0e+5, "dyn": 1.0e+5,
"dy": 1.0e+5, "dy": 1.0e+5,
@ -2380,7 +2380,7 @@ var unitConversions = map[byte]map[string]float64{
"pond": 1.01971621297793e+02, "pond": 1.01971621297793e+02,
}, },
// conversion uses Joule (J) as an intermediate unit // conversion uses Joule (J) as an intermediate unit
catgoryEnergy: { categoryEnergy: {
"J": 1, "J": 1,
"e": 9.99999519343231e+06, "e": 9.99999519343231e+06,
"c": 2.39006249473467e-01, "c": 2.39006249473467e-01,
@ -2396,7 +2396,7 @@ var unitConversions = map[byte]map[string]float64{
"btu": 9.47815067349015e-04, "btu": 9.47815067349015e-04,
}, },
// conversion uses Horsepower (HP) as an intermediate unit // conversion uses Horsepower (HP) as an intermediate unit
catgoryPower: { categoryPower: {
"HP": 1, "HP": 1,
"h": 1, "h": 1,
"W": 7.45699871582270e+02, "W": 7.45699871582270e+02,
@ -2404,12 +2404,12 @@ var unitConversions = map[byte]map[string]float64{
"PS": 1.01386966542400e+00, "PS": 1.01386966542400e+00,
}, },
// conversion uses Tesla (T) as an intermediate unit // conversion uses Tesla (T) as an intermediate unit
catgoryMagnetism: { categoryMagnetism: {
"T": 1, "T": 1,
"ga": 10000, "ga": 10000,
}, },
// conversion uses litre (l) as an intermediate unit // conversion uses litre (l) as an intermediate unit
catgoryVolumeAndLiquidMeasure: { categoryVolumeAndLiquidMeasure: {
"l": 1, "l": 1,
"L": 1, "L": 1,
"lt": 1, "lt": 1,
@ -2452,7 +2452,7 @@ var unitConversions = map[byte]map[string]float64{
"MTON": 8.82866668037215e-04, "MTON": 8.82866668037215e-04,
}, },
// conversion uses hectare (ha) as an intermediate unit // conversion uses hectare (ha) as an intermediate unit
catgoryArea: { categoryArea: {
"ha": 1, "ha": 1,
"uk_acre": 2.47105381467165e+00, "uk_acre": 2.47105381467165e+00,
"us_acre": 2.47104393046628e+00, "us_acre": 2.47104393046628e+00,
@ -2480,12 +2480,12 @@ var unitConversions = map[byte]map[string]float64{
"yd^2": 1.19599004630108e+04, "yd^2": 1.19599004630108e+04,
}, },
// conversion uses bit (bit) as an intermediate unit // conversion uses bit (bit) as an intermediate unit
catgoryInformation: { categoryInformation: {
"bit": 1, "bit": 1,
"byte": 0.125, "byte": 0.125,
}, },
// conversion uses Meters per Second (m/s) as an intermediate unit // conversion uses Meters per Second (m/s) as an intermediate unit
catgorySpeed: { categorySpeed: {
"m/s": 1, "m/s": 1,
"m/sec": 1, "m/sec": 1,
"m/h": 3.60e+03, "m/h": 3.60e+03,
@ -2639,7 +2639,7 @@ func (fn *formulaFuncs) CONVERT(argsList *list.List) formulaArg {
return newNumberFormulaArg(val / fromMultiplier) return newNumberFormulaArg(val / fromMultiplier)
} else if fromUOM == toUOM { } else if fromUOM == toUOM {
return newNumberFormulaArg(val / toMultiplier) return newNumberFormulaArg(val / toMultiplier)
} else if fromCategory == catgoryTemperature { } else if fromCategory == categoryTemperature {
return newNumberFormulaArg(convertTemperature(fromUOM, toUOM, val)) return newNumberFormulaArg(convertTemperature(fromUOM, toUOM, val))
} }
fromConversion := unitConversions[fromCategory][fromUOM] fromConversion := unitConversions[fromCategory][fromUOM]
@ -13607,7 +13607,7 @@ func (fn *formulaFuncs) replace(name string, argsList *list.List) formulaArg {
if argsList.Len() != 4 { if argsList.Len() != 4 {
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 4 arguments", name)) return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 4 arguments", name))
} }
oldText, newText := argsList.Front().Value.(formulaArg).Value(), argsList.Back().Value.(formulaArg).Value() sourceText, targetText := argsList.Front().Value.(formulaArg).Value(), argsList.Back().Value.(formulaArg).Value()
startNumArg, numCharsArg := argsList.Front().Next().Value.(formulaArg).ToNumber(), argsList.Front().Next().Next().Value.(formulaArg).ToNumber() startNumArg, numCharsArg := argsList.Front().Next().Value.(formulaArg).ToNumber(), argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
if startNumArg.Type != ArgNumber { if startNumArg.Type != ArgNumber {
return startNumArg return startNumArg
@ -13615,18 +13615,18 @@ func (fn *formulaFuncs) replace(name string, argsList *list.List) formulaArg {
if numCharsArg.Type != ArgNumber { if numCharsArg.Type != ArgNumber {
return numCharsArg return numCharsArg
} }
oldTextLen, startIdx := len(oldText), int(startNumArg.Number) sourceTextLen, startIdx := len(sourceText), int(startNumArg.Number)
if startIdx > oldTextLen { if startIdx > sourceTextLen {
startIdx = oldTextLen + 1 startIdx = sourceTextLen + 1
} }
endIdx := startIdx + int(numCharsArg.Number) endIdx := startIdx + int(numCharsArg.Number)
if endIdx > oldTextLen { if endIdx > sourceTextLen {
endIdx = oldTextLen + 1 endIdx = sourceTextLen + 1
} }
if startIdx < 1 || endIdx < 1 { if startIdx < 1 || endIdx < 1 {
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE) return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
} }
result := oldText[:startIdx-1] + newText + oldText[endIdx-1:] result := sourceText[:startIdx-1] + targetText + sourceText[endIdx-1:]
return newStringFormulaArg(result) return newStringFormulaArg(result)
} }
@ -13683,10 +13683,10 @@ func (fn *formulaFuncs) SUBSTITUTE(argsList *list.List) formulaArg {
if argsList.Len() != 3 && argsList.Len() != 4 { if argsList.Len() != 3 && argsList.Len() != 4 {
return newErrorFormulaArg(formulaErrorVALUE, "SUBSTITUTE requires 3 or 4 arguments") return newErrorFormulaArg(formulaErrorVALUE, "SUBSTITUTE requires 3 or 4 arguments")
} }
text, oldText := argsList.Front().Value.(formulaArg), argsList.Front().Next().Value.(formulaArg) text, sourceText := argsList.Front().Value.(formulaArg), argsList.Front().Next().Value.(formulaArg)
newText, instanceNum := argsList.Front().Next().Next().Value.(formulaArg), 0 targetText, instanceNum := argsList.Front().Next().Next().Value.(formulaArg), 0
if argsList.Len() == 3 { if argsList.Len() == 3 {
return newStringFormulaArg(strings.ReplaceAll(text.Value(), oldText.Value(), newText.Value())) return newStringFormulaArg(strings.ReplaceAll(text.Value(), sourceText.Value(), targetText.Value()))
} }
instanceNumArg := argsList.Back().Value.(formulaArg).ToNumber() instanceNumArg := argsList.Back().Value.(formulaArg).ToNumber()
if instanceNumArg.Type != ArgNumber { if instanceNumArg.Type != ArgNumber {
@ -13696,10 +13696,10 @@ func (fn *formulaFuncs) SUBSTITUTE(argsList *list.List) formulaArg {
if instanceNum < 1 { if instanceNum < 1 {
return newErrorFormulaArg(formulaErrorVALUE, "instance_num should be > 0") return newErrorFormulaArg(formulaErrorVALUE, "instance_num should be > 0")
} }
str, oldTextLen, count, chars, pos := text.Value(), len(oldText.Value()), instanceNum, 0, -1 str, sourceTextLen, count, chars, pos := text.Value(), len(sourceText.Value()), instanceNum, 0, -1
for { for {
count-- count--
index := strings.Index(str, oldText.Value()) index := strings.Index(str, sourceText.Value())
if index == -1 { if index == -1 {
pos = -1 pos = -1
break break
@ -13708,7 +13708,7 @@ func (fn *formulaFuncs) SUBSTITUTE(argsList *list.List) formulaArg {
if count == 0 { if count == 0 {
break break
} }
idx := oldTextLen + index idx := sourceTextLen + index
chars += idx chars += idx
str = str[idx:] str = str[idx:]
} }
@ -13716,8 +13716,8 @@ func (fn *formulaFuncs) SUBSTITUTE(argsList *list.List) formulaArg {
if pos == -1 { if pos == -1 {
return newStringFormulaArg(text.Value()) return newStringFormulaArg(text.Value())
} }
pre, post := text.Value()[:pos], text.Value()[pos+oldTextLen:] pre, post := text.Value()[:pos], text.Value()[pos+sourceTextLen:]
return newStringFormulaArg(pre + newText.Value() + post) return newStringFormulaArg(pre + targetText.Value() + post)
} }
// TEXTJOIN function joins together a series of supplied text strings into one // TEXTJOIN function joins together a series of supplied text strings into one

View File

@ -91,7 +91,7 @@ func (f *File) addChart(opts *chartOptions, comboCharts []*chartOptions) {
Cs: &aCs{ Cs: &aCs{
Typeface: "+mn-cs", Typeface: "+mn-cs",
}, },
Latin: &aLatin{ Latin: &xlsxCTTextFont{
Typeface: "+mn-lt", Typeface: "+mn-lt",
}, },
}, },
@ -1168,7 +1168,7 @@ func (f *File) drawPlotAreaTxPr(opts *chartAxisOptions) *cTxPr {
LumOff: &attrValInt{Val: intPtr(85000)}, LumOff: &attrValInt{Val: intPtr(85000)},
}, },
}, },
Latin: &aLatin{Typeface: "+mn-lt"}, Latin: &xlsxCTTextFont{Typeface: "+mn-lt"},
Ea: &aEa{Typeface: "+mn-ea"}, Ea: &aEa{Typeface: "+mn-ea"},
Cs: &aCs{Typeface: "+mn-cs"}, Cs: &aCs{Typeface: "+mn-cs"},
}, },

View File

@ -93,6 +93,12 @@ func newStreamSetRowError(row int) error {
return fmt.Errorf("row %d has already been written", row) return fmt.Errorf("row %d has already been written", row)
} }
// newViewIdxError defined the error message on receiving a invalid sheet view
// index.
func newViewIdxError(viewIndex int) error {
return fmt.Errorf("view index %d out of range", viewIndex)
}
var ( var (
// ErrStreamSetColWidth defined the error message on set column width in // ErrStreamSetColWidth defined the error message on set column width in
// stream writing mode. // stream writing mode.

View File

@ -182,6 +182,7 @@ func (f *File) writeToZip(zw *zip.Writer) error {
_ = f.sharedStringsLoader() _ = f.sharedStringsLoader()
f.sharedStringsWriter() f.sharedStringsWriter()
f.styleSheetWriter() f.styleSheetWriter()
f.themeWriter()
for path, stream := range f.streams { for path, stream := range f.streams {
fi, err := zw.Create(path) fi, err := zw.Create(path)

8
lib.go
View File

@ -626,12 +626,12 @@ func getXMLNamespace(space string, attr []xml.Attr) string {
// replaceNameSpaceBytes provides a function to replace the XML root element // replaceNameSpaceBytes provides a function to replace the XML root element
// attribute by the given component part path and XML content. // attribute by the given component part path and XML content.
func (f *File) replaceNameSpaceBytes(path string, contentMarshal []byte) []byte { func (f *File) replaceNameSpaceBytes(path string, contentMarshal []byte) []byte {
oldXmlns := []byte(`xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`) sourceXmlns := []byte(`xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
newXmlns := []byte(templateNamespaceIDMap) targetXmlns := []byte(templateNamespaceIDMap)
if attr, ok := f.xmlAttr[path]; ok { if attr, ok := f.xmlAttr[path]; ok {
newXmlns = []byte(genXMLNamespace(attr)) targetXmlns = []byte(genXMLNamespace(attr))
} }
return bytesReplace(contentMarshal, oldXmlns, bytes.ReplaceAll(newXmlns, []byte(" mc:Ignorable=\"r\""), []byte{}), -1) return bytesReplace(contentMarshal, sourceXmlns, bytes.ReplaceAll(targetXmlns, []byte(" mc:Ignorable=\"r\""), []byte{}), -1)
} }
// addNameSpaces provides a function to add an XML attribute by the given // addNameSpaces provides a function to add an XML attribute by the given

View File

@ -17,7 +17,11 @@ import "strings"
func (mc *xlsxMergeCell) Rect() ([]int, error) { func (mc *xlsxMergeCell) Rect() ([]int, error) {
var err error var err error
if mc.rect == nil { if mc.rect == nil {
mc.rect, err = rangeRefToCoordinates(mc.Ref) mergedCellsRef := mc.Ref
if !strings.Contains(mergedCellsRef, ":") {
mergedCellsRef += ":" + mergedCellsRef
}
mc.rect, err = rangeRefToCoordinates(mergedCellsRef)
} }
return mc.rect, err return mc.rect, err
} }
@ -105,7 +109,11 @@ func (f *File) UnmergeCell(sheet, hCell, vCell string) error {
if mergeCell == nil { if mergeCell == nil {
continue continue
} }
rect2, _ := rangeRefToCoordinates(mergeCell.Ref) mergedCellsRef := mergeCell.Ref
if !strings.Contains(mergedCellsRef, ":") {
mergedCellsRef += ":" + mergedCellsRef
}
rect2, _ := rangeRefToCoordinates(mergedCellsRef)
if isOverlap(rect1, rect2) { if isOverlap(rect1, rect2) {
continue continue
} }

View File

@ -185,7 +185,7 @@ func TestUnmergeCell(t *testing.T) {
ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml") ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok) assert.True(t, ok)
ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A1"}}} ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A1"}}}
assert.EqualError(t, f.UnmergeCell("Sheet1", "A2", "B3"), ErrParameterInvalid.Error()) assert.NoError(t, f.UnmergeCell("Sheet1", "A2", "B3"))
ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml") ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok) assert.True(t, ok)
@ -194,6 +194,6 @@ func TestUnmergeCell(t *testing.T) {
} }
func TestFlatMergedCells(t *testing.T) { func TestFlatMergedCells(t *testing.T) {
ws := &xlsxWorksheet{MergeCells: &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A1"}}}} ws := &xlsxWorksheet{MergeCells: &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ""}}}}
assert.EqualError(t, flatMergedCells(ws, [][]*xlsxMergeCell{}), ErrParameterInvalid.Error()) assert.EqualError(t, flatMergedCells(ws, [][]*xlsxMergeCell{}), "cannot convert cell \"\" to coordinates: invalid cell name \"\"")
} }

12
rows.go
View File

@ -744,8 +744,8 @@ func checkRow(ws *xlsxWorksheet) error {
} }
if colCount < lastCol { if colCount < lastCol {
oldList := rowData.C sourceList := rowData.C
newList := make([]xlsxC, 0, lastCol) targetList := make([]xlsxC, 0, lastCol)
rowData.C = ws.SheetData.Row[rowIdx].C[:0] rowData.C = ws.SheetData.Row[rowIdx].C[:0]
@ -754,13 +754,13 @@ func checkRow(ws *xlsxWorksheet) error {
if err != nil { if err != nil {
return err return err
} }
newList = append(newList, xlsxC{R: cellName}) targetList = append(targetList, xlsxC{R: cellName})
} }
rowData.C = newList rowData.C = targetList
for colIdx := range oldList { for colIdx := range sourceList {
colData := &oldList[colIdx] colData := &sourceList[colIdx]
colNum, _, err := CellNameToCoordinates(colData.R) colNum, _, err := CellNameToCoordinates(colData.R)
if err != nil { if err != nil {
return err return err

View File

@ -418,7 +418,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *shapeOption
AltLang: "en-US", AltLang: "en-US",
U: u, U: u,
Sz: p.Font.Size * 100, Sz: p.Font.Size * 100,
Latin: &aLatin{Typeface: p.Font.Family}, Latin: &xlsxCTTextFont{Typeface: p.Font.Family},
}, },
T: text, T: text,
}, },

View File

@ -243,9 +243,9 @@ func (f *File) relsWriter() {
// strict requirements about the structure of the input XML. This function is // strict requirements about the structure of the input XML. This function is
// a horrible hack to fix that after the XML marshalling is completed. // a horrible hack to fix that after the XML marshalling is completed.
func replaceRelationshipsBytes(content []byte) []byte { func replaceRelationshipsBytes(content []byte) []byte {
oldXmlns := []byte(`xmlns:relationships="http://schemas.openxmlformats.org/officeDocument/2006/relationships" relationships`) sourceXmlns := []byte(`xmlns:relationships="http://schemas.openxmlformats.org/officeDocument/2006/relationships" relationships`)
newXmlns := []byte("r") targetXmlns := []byte("r")
return bytesReplace(content, oldXmlns, newXmlns, -1) return bytesReplace(content, sourceXmlns, targetXmlns, -1)
} }
// SetActiveSheet provides a function to set the default active sheet of the // SetActiveSheet provides a function to set the default active sheet of the
@ -1623,7 +1623,7 @@ func (f *File) InsertPageBreak(sheet, cell string) error {
if row != 0 && rowBrk == -1 { if row != 0 && rowBrk == -1 {
ws.RowBreaks.Brk = append(ws.RowBreaks.Brk, &xlsxBrk{ ws.RowBreaks.Brk = append(ws.RowBreaks.Brk, &xlsxBrk{
ID: row, ID: row,
Max: 16383, Max: MaxColumns - 1,
Man: true, Man: true,
}) })
ws.RowBreaks.ManualBreakCount++ ws.RowBreaks.ManualBreakCount++
@ -1631,7 +1631,7 @@ func (f *File) InsertPageBreak(sheet, cell string) error {
if col != 0 && colBrk == -1 { if col != 0 && colBrk == -1 {
ws.ColBreaks.Brk = append(ws.ColBreaks.Brk, &xlsxBrk{ ws.ColBreaks.Brk = append(ws.ColBreaks.Brk, &xlsxBrk{
ID: col, ID: col,
Max: 1048575, Max: TotalRows - 1,
Man: true, Man: true,
}) })
ws.ColBreaks.ManualBreakCount++ ws.ColBreaks.ManualBreakCount++

View File

@ -11,8 +11,6 @@
package excelize package excelize
import "fmt"
// getSheetView returns the SheetView object // getSheetView returns the SheetView object
func (f *File) getSheetView(sheet string, viewIndex int) (*xlsxSheetView, error) { func (f *File) getSheetView(sheet string, viewIndex int) (*xlsxSheetView, error) {
ws, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
@ -26,11 +24,11 @@ func (f *File) getSheetView(sheet string, viewIndex int) (*xlsxSheetView, error)
} }
if viewIndex < 0 { if viewIndex < 0 {
if viewIndex < -len(ws.SheetViews.SheetView) { if viewIndex < -len(ws.SheetViews.SheetView) {
return nil, fmt.Errorf("view index %d out of range", viewIndex) return nil, newViewIdxError(viewIndex)
} }
viewIndex = len(ws.SheetViews.SheetView) + viewIndex viewIndex = len(ws.SheetViews.SheetView) + viewIndex
} else if viewIndex >= len(ws.SheetViews.SheetView) { } else if viewIndex >= len(ws.SheetViews.SheetView) {
return nil, fmt.Errorf("view index %d out of range", viewIndex) return nil, newViewIdxError(viewIndex)
} }
return &(ws.SheetViews.SheetView[viewIndex]), err return &(ws.SheetViews.SheetView[viewIndex]), err

View File

@ -1057,6 +1057,15 @@ func (f *File) styleSheetWriter() {
} }
} }
// themeWriter provides a function to save xl/theme/theme1.xml after serialize
// structure.
func (f *File) themeWriter() {
if f.Theme != nil {
output, _ := xml.Marshal(f.Theme)
f.saveFileList(defaultXMLPathTheme, f.replaceNameSpaceBytes(defaultXMLPathTheme, output))
}
}
// sharedStringsWriter provides a function to save xl/sharedStrings.xml after // sharedStringsWriter provides a function to save xl/sharedStrings.xml after
// serialize structure. // serialize structure.
func (f *File) sharedStringsWriter() { func (f *File) sharedStringsWriter() {
@ -3311,11 +3320,11 @@ func getPaletteColor(color string) string {
// themeReader provides a function to get the pointer to the xl/theme/theme1.xml // themeReader provides a function to get the pointer to the xl/theme/theme1.xml
// structure after deserialization. // structure after deserialization.
func (f *File) themeReader() *xlsxTheme { func (f *File) themeReader() *xlsxTheme {
var ( if _, ok := f.Pkg.Load(defaultXMLPathTheme); !ok {
err error return nil
theme xlsxTheme }
) theme := xlsxTheme{XMLNSa: NameSpaceDrawingML.Value, XMLNSr: SourceRelationship.Value}
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("xl/theme/theme1.xml")))). if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathTheme)))).
Decode(&theme); err != nil && err != io.EOF { Decode(&theme); err != nil && err != io.EOF {
log.Printf("xml decoder error: %s", err) log.Printf("xml decoder error: %s", err)
} }

View File

@ -334,8 +334,8 @@ func TestStylesReader(t *testing.T) {
func TestThemeReader(t *testing.T) { func TestThemeReader(t *testing.T) {
f := NewFile() f := NewFile()
// Test read theme with unsupported charset. // Test read theme with unsupported charset.
f.Pkg.Store("xl/theme/theme1.xml", MacintoshCyrillicCharset) f.Pkg.Store(defaultXMLPathTheme, MacintoshCyrillicCharset)
assert.EqualValues(t, new(xlsxTheme), f.themeReader()) assert.EqualValues(t, &xlsxTheme{XMLNSa: NameSpaceDrawingML.Value, XMLNSr: SourceRelationship.Value}, f.themeReader())
} }
func TestSetCellStyle(t *testing.T) { func TestSetCellStyle(t *testing.T) {

View File

@ -21,6 +21,7 @@ const (
defaultXMLPathCalcChain = "xl/calcChain.xml" defaultXMLPathCalcChain = "xl/calcChain.xml"
defaultXMLPathSharedStrings = "xl/sharedStrings.xml" defaultXMLPathSharedStrings = "xl/sharedStrings.xml"
defaultXMLPathStyles = "xl/styles.xml" defaultXMLPathStyles = "xl/styles.xml"
defaultXMLPathTheme = "xl/theme/theme1.xml"
defaultXMLPathWorkbook = "xl/workbook.xml" defaultXMLPathWorkbook = "xl/workbook.xml"
defaultTempFileSST = "sharedStrings" defaultTempFileSST = "sharedStrings"
) )

View File

@ -171,12 +171,11 @@ type aEa struct {
Typeface string `xml:"typeface,attr"` Typeface string `xml:"typeface,attr"`
} }
// aLatin (Latin Font) directly maps the a:latin element. This element type xlsxCTTextFont struct {
// specifies that a Latin font be used for a specific run of text. This font is Typeface string `xml:"typeface,attr"`
// specified with a typeface attribute much like the others but is specifically Panose string `xml:"panose,attr,omitempty"`
// classified as a Latin font. PitchFamily string `xml:"pitchFamily,attr,omitempty"`
type aLatin struct { Charset string `xml:"Charset,attr,omitempty"`
Typeface string `xml:"typeface,attr"`
} }
// aR directly maps the a:r element. // aR directly maps the a:r element.
@ -191,29 +190,29 @@ type aR struct {
// properties are defined as direct formatting, since they are directly applied // properties are defined as direct formatting, since they are directly applied
// to the run and supersede any formatting from styles. // to the run and supersede any formatting from styles.
type aRPr struct { type aRPr struct {
AltLang string `xml:"altLang,attr,omitempty"` AltLang string `xml:"altLang,attr,omitempty"`
B bool `xml:"b,attr"` B bool `xml:"b,attr"`
Baseline int `xml:"baseline,attr"` Baseline int `xml:"baseline,attr"`
Bmk string `xml:"bmk,attr,omitempty"` Bmk string `xml:"bmk,attr,omitempty"`
Cap string `xml:"cap,attr,omitempty"` Cap string `xml:"cap,attr,omitempty"`
Dirty bool `xml:"dirty,attr,omitempty"` Dirty bool `xml:"dirty,attr,omitempty"`
Err bool `xml:"err,attr,omitempty"` Err bool `xml:"err,attr,omitempty"`
I bool `xml:"i,attr"` I bool `xml:"i,attr"`
Kern int `xml:"kern,attr"` Kern int `xml:"kern,attr"`
Kumimoji bool `xml:"kumimoji,attr,omitempty"` Kumimoji bool `xml:"kumimoji,attr,omitempty"`
Lang string `xml:"lang,attr,omitempty"` Lang string `xml:"lang,attr,omitempty"`
NoProof bool `xml:"noProof,attr,omitempty"` NoProof bool `xml:"noProof,attr,omitempty"`
NormalizeH bool `xml:"normalizeH,attr,omitempty"` NormalizeH bool `xml:"normalizeH,attr,omitempty"`
SmtClean bool `xml:"smtClean,attr,omitempty"` SmtClean bool `xml:"smtClean,attr,omitempty"`
SmtID uint64 `xml:"smtId,attr,omitempty"` SmtID uint64 `xml:"smtId,attr,omitempty"`
Spc int `xml:"spc,attr"` Spc int `xml:"spc,attr"`
Strike string `xml:"strike,attr,omitempty"` Strike string `xml:"strike,attr,omitempty"`
Sz float64 `xml:"sz,attr,omitempty"` Sz float64 `xml:"sz,attr,omitempty"`
U string `xml:"u,attr,omitempty"` U string `xml:"u,attr,omitempty"`
SolidFill *aSolidFill `xml:"a:solidFill"` SolidFill *aSolidFill `xml:"a:solidFill"`
Latin *aLatin `xml:"a:latin"` Latin *xlsxCTTextFont `xml:"a:latin"`
Ea *aEa `xml:"a:ea"` Ea *aEa `xml:"a:ea"`
Cs *aCs `xml:"a:cs"` Cs *aCs `xml:"a:cs"`
} }
// cSpPr (Shape Properties) directly maps the spPr element. This element // cSpPr (Shape Properties) directly maps the spPr element. This element

View File

@ -159,6 +159,7 @@ var IndexedColorMapping = []string{
"00CCFF", "CCFFFF", "CCFFCC", "FFFF99", "99CCFF", "FF99CC", "CC99FF", "FFCC99", "00CCFF", "CCFFFF", "CCFFCC", "FFFF99", "99CCFF", "FF99CC", "CC99FF", "FFCC99",
"3366FF", "33CCCC", "99CC00", "FFCC00", "FF9900", "FF6600", "666699", "969696", "3366FF", "33CCCC", "99CC00", "FFCC00", "FF9900", "FF6600", "666699", "969696",
"003366", "339966", "003300", "333300", "993300", "993366", "333399", "333333", "003366", "339966", "003300", "333300", "993300", "993366", "333399", "333333",
"000000", "FFFFFF",
} }
// supportedImageTypes defined supported image types. // supportedImageTypes defined supported image types.

View File

@ -16,12 +16,59 @@ import "encoding/xml"
// xlsxTheme directly maps the theme element in the namespace // xlsxTheme directly maps the theme element in the namespace
// http://schemas.openxmlformats.org/drawingml/2006/main // http://schemas.openxmlformats.org/drawingml/2006/main
type xlsxTheme struct { type xlsxTheme struct {
ThemeElements xlsxThemeElements `xml:"themeElements"` XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/main theme"`
XMLNSa string `xml:"xmlns:a,attr"`
XMLNSr string `xml:"xmlns:r,attr"`
Name string `xml:"name,attr"`
ThemeElements xlsxBaseStyles `xml:"themeElements"`
ObjectDefaults xlsxObjectDefaults `xml:"objectDefaults"` ObjectDefaults xlsxObjectDefaults `xml:"objectDefaults"`
ExtraClrSchemeLst xlsxExtraClrSchemeLst `xml:"extraClrSchemeLst"` ExtraClrSchemeLst xlsxExtraClrSchemeLst `xml:"extraClrSchemeLst"`
CustClrLst *xlsxInnerXML `xml:"custClrLst"`
ExtLst *xlsxExtLst `xml:"extLst"` ExtLst *xlsxExtLst `xml:"extLst"`
} }
// xlsxBaseStyles defines the theme elements for a theme, and is the workhorse
// of the theme. The bulk of the shared theme information that is used by a
// given document is defined here. Within this complex type is defined a color
// scheme, a font scheme, and a style matrix (format scheme) that defines
// different formatting options for different pieces of a document.
type xlsxBaseStyles struct {
ClrScheme xlsxColorScheme `xml:"clrScheme"`
FontScheme xlsxFontScheme `xml:"fontScheme"`
FmtScheme xlsxStyleMatrix `xml:"fmtScheme"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// xlsxCTColor holds the actual color values that are to be applied to a given
// diagram and how those colors are to be applied.
type xlsxCTColor struct {
ScrgbClr *xlsxInnerXML `xml:"scrgbClr"`
SrgbClr *attrValString `xml:"srgbClr"`
HslClr *xlsxInnerXML `xml:"hslClr"`
SysClr *xlsxSysClr `xml:"sysClr"`
SchemeClr *xlsxInnerXML `xml:"schemeClr"`
PrstClr *xlsxInnerXML `xml:"prstClr"`
}
// xlsxColorScheme defines a set of colors for the theme. The set of colors
// consists of twelve color slots that can each hold a color of choice.
type xlsxColorScheme struct {
Name string `xml:"name,attr"`
Dk1 xlsxCTColor `xml:"dk1"`
Lt1 xlsxCTColor `xml:"lt1"`
Dk2 xlsxCTColor `xml:"dk2"`
Lt2 xlsxCTColor `xml:"lt2"`
Accent1 xlsxCTColor `xml:"accent1"`
Accent2 xlsxCTColor `xml:"accent2"`
Accent3 xlsxCTColor `xml:"accent3"`
Accent4 xlsxCTColor `xml:"accent4"`
Accent5 xlsxCTColor `xml:"accent5"`
Accent6 xlsxCTColor `xml:"accent6"`
Hlink xlsxCTColor `xml:"hlink"`
FolHlink xlsxCTColor `xml:"folHlink"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// objectDefaults element allows for the definition of default shape, line, // objectDefaults element allows for the definition of default shape, line,
// and textbox formatting properties. An application can use this information // and textbox formatting properties. An application can use this information
// to format a shape (or text) initially on insertion into a document. // to format a shape (or text) initially on insertion into a document.
@ -35,24 +82,24 @@ type xlsxExtraClrSchemeLst struct {
ExtraClrSchemeLst string `xml:",innerxml"` ExtraClrSchemeLst string `xml:",innerxml"`
} }
// xlsxThemeElements directly maps the element defines the theme formatting // xlsxCTSupplementalFont defines an additional font that is used for language
// options for the theme and is the workhorse of the theme. This is where the // specific fonts in themes. For example, one can specify a font that gets used
// bulk of the shared theme information is contained and used by a document. // only within the Japanese language context.
// This element contains the color scheme, font scheme, and format scheme type xlsxCTSupplementalFont struct {
// elements which define the different formatting aspects of what a theme Script string `xml:"script,attr"`
// defines. Typeface string `xml:"typeface,attr"`
type xlsxThemeElements struct {
ClrScheme xlsxClrScheme `xml:"clrScheme"`
FontScheme xlsxFontScheme `xml:"fontScheme"`
FmtScheme xlsxFmtScheme `xml:"fmtScheme"`
} }
// xlsxClrScheme element specifies the theme color, stored in the document's // xlsxFontCollection defines a major and minor font which is used in the font
// Theme part to which the value of this theme color shall be mapped. This // scheme. A font collection consists of a font definition for Latin, East
// mapping enables multiple theme colors to be chained together. // Asian, and complex script. On top of these three definitions, one can also
type xlsxClrScheme struct { // define a font for use in a specific language or languages.
Name string `xml:"name,attr"` type xlsxFontCollection struct {
Children []xlsxClrSchemeEl `xml:",any"` Latin *xlsxCTTextFont `xml:"latin"`
Ea *xlsxCTTextFont `xml:"ea"`
Cs *xlsxCTTextFont `xml:"cs"`
Font []xlsxCTSupplementalFont `xml:"font"`
ExtLst *xlsxExtLst `xml:"extLst"`
} }
// xlsxFontScheme element defines the font scheme within the theme. The font // xlsxFontScheme element defines the font scheme within the theme. The font
@ -61,34 +108,19 @@ type xlsxClrScheme struct {
// document, and the minor font corresponds well with the normal text or // document, and the minor font corresponds well with the normal text or
// paragraph areas. // paragraph areas.
type xlsxFontScheme struct { type xlsxFontScheme struct {
Name string `xml:"name,attr"` Name string `xml:"name,attr"`
MajorFont xlsxMajorFont `xml:"majorFont"` MajorFont xlsxFontCollection `xml:"majorFont"`
MinorFont xlsxMinorFont `xml:"minorFont"` MinorFont xlsxFontCollection `xml:"minorFont"`
ExtLst *xlsxExtLst `xml:"extLst"` ExtLst *xlsxExtLst `xml:"extLst"`
} }
// xlsxMajorFont element defines the set of major fonts which are to be used // xlsxStyleMatrix defines a set of formatting options, which can be referenced
// under different languages or locals. // by documents that apply a certain style to a given part of an object. For
type xlsxMajorFont struct { // example, in a given shape, say a rectangle, one can reference a themed line
Children []xlsxFontSchemeEl `xml:",any"` // style, themed effect, and themed fill that would be theme specific and
} // change when the theme is changed.
type xlsxStyleMatrix struct {
// xlsxMinorFont element defines the set of minor fonts that are to be used Name string `xml:"name,attr,omitempty"`
// under different languages or locals.
type xlsxMinorFont struct {
Children []xlsxFontSchemeEl `xml:",any"`
}
// xlsxFmtScheme element contains the background fill styles, effect styles,
// fill styles, and line styles which define the style matrix for a theme. The
// style matrix consists of subtle, moderate, and intense fills, lines, and
// effects. The background fills are not generally thought of to directly be
// associated with the matrix, but do play a role in the style of the overall
// document. Usually, a given object chooses a single line style, a single
// fill style, and a single effect style in order to define the overall final
// look of the object.
type xlsxFmtScheme struct {
Name string `xml:"name,attr"`
FillStyleLst xlsxFillStyleLst `xml:"fillStyleLst"` FillStyleLst xlsxFillStyleLst `xml:"fillStyleLst"`
LnStyleLst xlsxLnStyleLst `xml:"lnStyleLst"` LnStyleLst xlsxLnStyleLst `xml:"lnStyleLst"`
EffectStyleLst xlsxEffectStyleLst `xml:"effectStyleLst"` EffectStyleLst xlsxEffectStyleLst `xml:"effectStyleLst"`
@ -123,26 +155,6 @@ type xlsxBgFillStyleLst struct {
BgFillStyleLst string `xml:",innerxml"` BgFillStyleLst string `xml:",innerxml"`
} }
// xlsxClrScheme specifies the theme color, stored in the document's Theme
// part to which the value of this theme color shall be mapped. This mapping
// enables multiple theme colors to be chained together.
type xlsxClrSchemeEl struct {
XMLName xml.Name
SysClr *xlsxSysClr `xml:"sysClr"`
SrgbClr *attrValString `xml:"srgbClr"`
}
// xlsxFontSchemeEl directly maps the major and minor font of the style's font
// scheme.
type xlsxFontSchemeEl struct {
XMLName xml.Name
Script string `xml:"script,attr,omitempty"`
Typeface string `xml:"typeface,attr"`
Panose string `xml:"panose,attr,omitempty"`
PitchFamily string `xml:"pitchFamily,attr,omitempty"`
Charset string `xml:"charset,attr,omitempty"`
}
// xlsxSysClr element specifies a color bound to predefined operating system // xlsxSysClr element specifies a color bound to predefined operating system
// elements. // elements.
type xlsxSysClr struct { type xlsxSysClr struct {