Added additional tests and y2 upgrades

This commit is contained in:
Nick 2025-12-18 18:34:57 -06:00 committed by kruftindustries
parent f0647157ba
commit e85d8d768f
28 changed files with 2908 additions and 390 deletions

View file

@ -0,0 +1,28 @@
{
"permissions": {
"allow": [
"Bash(grep:*)",
"Bash(unzip:*)",
"Bash(xmllint:*)",
"Bash(cat:*)",
"Bash(make clean:*)",
"Bash(make:*)",
"Bash(gcc:*)",
"Bash(./test_y2_axis:*)",
"Bash(ls:*)",
"Bash(rm:*)",
"Bash(echo:*)",
"Bash(./test_single_axis:*)",
"Bash(if [ -f test_single_verify/xl/charts/_rels/chart1.xml.rels ])",
"Bash(then echo \" ✓ YES\")",
"Bash(else echo \" ✗ NO\")",
"Bash(fi)",
"Bash(./test_bar_y2:*)",
"Bash(./test_area_y2)",
"Bash(./test_scatter_styled:*)",
"Bash(convert:*)",
"Bash(LD_LIBRARY_PATH=./lib:$LD_LIBRARY_PATH ./test_scatter_styled:*)",
"Bash(LD_LIBRARY_PATH=./lib:$LD_LIBRARY_PATH ./test_scatter_chartsheet:*)"
]
}
}

View file

@ -7,7 +7,6 @@
- This is shared object library version `libxlsxwriter.so.10`. This should be
updated automatically via `make` and `cmake` as part of the build process.
This version contains ABI changes since the previous release.
- Please report any downstream patches back upstream to help improve the overall
build process.

View file

@ -1,16 +1,14 @@
const std = @import("std");
const zon_version = @import("build.zig.zon").version;
const xlsxw_version: std.SemanticVersion = .{
.major = 1,
.minor = 1,
.patch = 9,
};
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const options: BuildConfig = .{
.target = target,
.optimize = optimize,
};
const xlsxw_version = std.SemanticVersion.parse(zon_version) catch |err| {
std.debug.panic("Error: {s}", .{@errorName(err)});
};
const shared = b.option(bool, "SHARED_LIBRARY", "Build the Shared Library [default: false]") orelse false;
const examples = b.option(bool, "BUILD_EXAMPLES", "Build libxlsxwriter examples [default: false]") orelse false;
@ -20,11 +18,15 @@ pub fn build(b: *std.Build) void {
const md5 = b.option(bool, "USE_OPENSSL_MD5", "Build libxlsxwriter with the OpenSSL MD5 lib [default: off]") orelse false;
const stdtmpfile = b.option(bool, "USE_STANDARD_TMPFILE", "Use the C standard library's tmpfile() [default: off]") orelse false;
const lib = b.addLibrary(.{
const lib = if (shared) b.addSharedLibrary(.{
.name = "xlsxwriter",
.root_module = createModule(b, options),
.linkage = if (shared) .dynamic else .static,
.target = target,
.optimize = optimize,
.version = xlsxw_version,
}) else b.addStaticLibrary(.{
.name = "xlsxwriter",
.target = target,
.optimize = optimize,
});
lib.pie = true;
switch (optimize) {
@ -78,7 +80,7 @@ pub fn build(b: *std.Build) void {
});
}
const zlib = buildZlib(b, options);
const zlib = buildZlib(b, .{ target, optimize });
lib.linkLibrary(zlib);
lib.installLibraryHeaders(zlib);
@ -120,52 +122,42 @@ pub fn build(b: *std.Build) void {
// build examples
if (examples) {
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/anatomy.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/array_formula.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/autofilter.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/background.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/chart_area.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/chart_column.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/data_validate.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/hello.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/watermark.c",
});
buildExe(b, .{
.options = options,
.lib = lib,
.path = "examples/worksheet_protection.c",
});
@ -173,112 +165,93 @@ pub fn build(b: *std.Build) void {
// build tests
if (tests) {
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/app/test_app.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/chart/test_chart.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/chartsheet/test_chartsheet.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/content_types/test_content_types.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/content_types/test_content_types_write_default.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/content_types/test_content_types_write_override.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/relationships/test_relationships.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/app/test_app_xml_declaration.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/relationships/test_relationships_xml_declaration.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/custom/test_custom_xml_declaration.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/metadata/test_metadata_xml_declaration.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/core/test_core_xml_declaration.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/sst/test_shared_strings.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/workbook/test_workbook.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/xmlwriter/test_xmlwriter.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/table/test_table01.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/table/test_table02.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/table/test_table03.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/table/test_table04.c",
});
buildTest(b, .{
.options = options,
.lib = lib,
.path = "test/unit/styles/test_styles_write_border.c",
});
}
}
fn buildExe(b: *std.Build, info: BuildExec) void {
fn buildExe(b: *std.Build, info: BuildInfo) void {
const exe = b.addExecutable(.{
.name = info.filename(),
.root_module = createModule(b, info.options),
.optimize = info.lib.root_module.optimize.?,
.target = info.lib.root_module.resolved_target.?,
});
exe.addCSourceFile(.{
.file = b.path(info.path),
@ -304,10 +277,11 @@ fn buildExe(b: *std.Build, info: BuildExec) void {
run_step.dependOn(&run_cmd.step);
}
fn buildTest(b: *std.Build, info: BuildExec) void {
fn buildTest(b: *std.Build, info: BuildInfo) void {
const exe = b.addExecutable(.{
.name = info.filename(),
.root_module = createModule(b, info.options),
.optimize = info.lib.root_module.optimize.?,
.target = info.lib.root_module.resolved_target.?,
});
exe.root_module.addCMacro("TESTING", "");
exe.addCSourceFile(.{
@ -319,10 +293,10 @@ fn buildTest(b: *std.Build, info: BuildExec) void {
.flags = cflags,
});
exe.addIncludePath(b.path("test/unit"));
exe.linkLibrary(info.lib);
for (info.lib.root_module.include_dirs.items) |include| {
exe.root_module.include_dirs.append(b.allocator, include) catch @panic("OOM");
exe.root_module.include_dirs.append(b.allocator, include) catch {};
}
exe.linkLibrary(info.lib);
exe.linkLibC();
b.installArtifact(exe);
@ -339,13 +313,6 @@ fn buildTest(b: *std.Build, info: BuildExec) void {
run_step.dependOn(&run_cmd.step);
}
fn createModule(b: *std.Build, options: BuildConfig) *std.Build.Module {
return b.createModule(.{
.target = options.target,
.optimize = options.optimize,
});
}
const cflags = &.{
"-std=c89",
"-Wall",
@ -359,29 +326,25 @@ const minizip_src: []const []const u8 = &.{
"third_party/minizip/zip.c",
};
const BuildExec = struct {
options: BuildConfig,
const BuildInfo = struct {
lib: *std.Build.Step.Compile,
path: []const u8,
fn filename(self: BuildExec) []const u8 {
fn filename(self: BuildInfo) []const u8 {
var split = std.mem.splitSequence(u8, std.fs.path.basename(self.path), ".");
return split.first();
}
};
const BuildConfig = struct {
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
};
fn buildZlib(b: *std.Build, options: BuildConfig) *std.Build.Step.Compile {
const libz = b.addLibrary(.{
fn buildZlib(b: *std.Build, options: anytype) *std.Build.Step.Compile {
const libz = b.addStaticLibrary(.{
.name = "z",
.root_module = createModule(b, options),
.target = options[0],
.optimize = options[1],
});
if (b.lazyDependency("zlib", .{
.target = options.target,
.optimize = options.optimize,
.target = options[0],
.optimize = options[1],
})) |zlib_path| {
libz.addIncludePath(zlib_path.path(""));
libz.addCSourceFiles(.{

View file

@ -2,7 +2,7 @@
.name = .libxlsxwriter,
.version = "1.1.9",
.fingerprint = 0xa28d9a85f22fad0e,
.minimum_zig_version = "0.15.1",
.minimum_zig_version = "0.14.0",
.dependencies = .{
.zlib = .{
.url = "git+https://github.com/madler/zlib#v1.3.1",

113
examples/test_area_y2.c Normal file
View file

@ -0,0 +1,113 @@
/*
* Test program to verify area chart secondary Y-axis functionality.
* Tests area chart with two series on different Y-axes.
*/
#include "xlsxwriter.h"
#include <stdio.h>
int main() {
printf("=== Area Chart Secondary Y-Axis Test ===\n\n");
lxw_workbook *workbook = workbook_new("test_area_y2.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Data");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_AREA);
lxw_chart_series *series1, *series2;
/* Write headers */
worksheet_write_string(worksheet, 0, 0, "Quarter", NULL);
worksheet_write_string(worksheet, 0, 1, "Units Sold (1000s)", NULL);
worksheet_write_string(worksheet, 0, 2, "Market Share (%)", NULL);
/* Write some data with different scales to demonstrate secondary axis. */
/* Column A: X-axis values (quarters) */
const char *quarters[] = {"Q1", "Q2", "Q3", "Q4", "Q5", "Q6", "Q7", "Q8"};
for (int i = 0; i < 8; i++) {
worksheet_write_string(worksheet, i + 1, 0, quarters[i], NULL);
}
/* Column B: Small scale values - Units Sold (primary Y-axis, left side) */
double units[] = {12.5, 15.3, 18.7, 22.1, 25.8, 28.3, 30.2, 31.5};
for (int i = 0; i < 8; i++) {
worksheet_write_number(worksheet, i + 1, 1, units[i], NULL);
}
/* Column C: Different scale values - Market Share % (secondary Y-axis, right side) */
double market_share[] = {8.5, 12.3, 15.7, 18.2, 22.5, 26.8, 29.3, 32.1};
for (int i = 0; i < 8; i++) {
worksheet_write_number(worksheet, i + 1, 2, market_share[i], NULL);
}
printf("1. Writing test data (8 quarters, 2 series with different scales)...\n");
/* Add series to primary Y-axis (left side) - Units Sold */
series1 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$9",
"=Data!$B$2:$B$9",
chart->y_axis);
/* Set series name */
chart_series_set_name(series1, "=Data!$B$1");
printf("2. Added primary series (Units Sold) to left Y-axis...\n");
/* Add series to secondary Y-axis (right side) - Market Share */
series2 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$9",
"=Data!$C$2:$C$9",
chart->y2_axis);
/* Set series name */
chart_series_set_name(series2, "=Data!$C$1");
printf("3. Added secondary series (Market Share) to right Y-axis...\n");
/* Configure chart title */
chart_title_set_name(chart, "Units Sold and Market Share by Quarter");
/* Configure X-axis */
chart_axis_set_name(chart->x_axis, "Quarter");
/* Configure primary Y-axis (left side) */
chart_axis_set_name(chart->y_axis, "Units Sold (1000s)");
/* Configure secondary Y-axis (right side) */
chart_axis_set_name(chart->y2_axis, "Market Share (%)");
/* Position the secondary Y-axis title on the right side of the chart */
lxw_chart_layout layout = {
.x = 0.686,
.y = 0.314,
.width = 0.0,
.height = 0.0,
.has_inner = LXW_FALSE
};
chart_axis_set_name_layout(chart->y2_axis, &layout);
printf("4. Configured chart title and axis labels...\n");
/* Insert the chart into the worksheet */
worksheet_insert_chart(worksheet, CELL("E2"), chart);
printf("5. Inserted chart into worksheet...\n");
/* Save the workbook */
printf("6. Saving workbook...\n");
lxw_error result = workbook_close(workbook);
if (result == LXW_NO_ERROR) {
printf("\n✓ SUCCESS! Created test_area_y2.xlsx\n\n");
printf("Expected behavior:\n");
printf(" - Area chart with TWO Y-axes\n");
printf(" - Units Sold series on left Y-axis (0-35 range)\n");
printf(" - Market Share series on right Y-axis (0-35%% range)\n");
printf(" - Both series plotted against quarters on X-axis\n");
printf(" - Two areaChart elements in the XML\n");
printf(" - Four axes total (2 X-axes, 2 Y-axes)\n\n");
printf("Open test_area_y2.xlsx in Excel to verify!\n");
return 0;
} else {
printf("\n✗ ERROR creating workbook: %d\n", result);
return 1;
}
}

113
examples/test_bar_y2.c Normal file
View file

@ -0,0 +1,113 @@
/*
* Test program to verify bar chart secondary Y-axis functionality.
* Tests horizontal bar chart with two series on different Y-axes.
*/
#include "xlsxwriter.h"
#include <stdio.h>
int main() {
printf("=== Bar Chart Secondary Y-Axis Test ===\n\n");
lxw_workbook *workbook = workbook_new("test_bar_y2.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Data");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_BAR);
lxw_chart_series *series1, *series2;
/* Write headers */
worksheet_write_string(worksheet, 0, 0, "Department", NULL);
worksheet_write_string(worksheet, 0, 1, "Employees", NULL);
worksheet_write_string(worksheet, 0, 2, "Budget ($M)", NULL);
/* Write some data with different scales to demonstrate secondary axis. */
/* Column A: X-axis values (departments) */
const char *departments[] = {"Engineering", "Sales", "Marketing", "Operations", "HR", "Finance"};
for (int i = 0; i < 6; i++) {
worksheet_write_string(worksheet, i + 1, 0, departments[i], NULL);
}
/* Column B: Small scale values - Employees (primary Y-axis, left side) */
double employees[] = {45, 32, 18, 28, 12, 15};
for (int i = 0; i < 6; i++) {
worksheet_write_number(worksheet, i + 1, 1, employees[i], NULL);
}
/* Column C: Large scale values - Budget in millions (secondary Y-axis, right side) */
double budget[] = {8.5, 6.2, 3.8, 5.1, 2.2, 2.8};
for (int i = 0; i < 6; i++) {
worksheet_write_number(worksheet, i + 1, 2, budget[i], NULL);
}
printf("1. Writing test data (6 departments, 2 series with different scales)...\n");
/* Add series to primary Y-axis (left side) - Employees */
series1 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$7",
"=Data!$B$2:$B$7",
chart->y_axis);
/* Set series name */
chart_series_set_name(series1, "=Data!$B$1");
printf("2. Added primary series (Employees) to left Y-axis...\n");
/* Add series to secondary Y-axis (right side) - Budget */
series2 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$7",
"=Data!$C$2:$C$7",
chart->y2_axis);
/* Set series name */
chart_series_set_name(series2, "=Data!$C$1");
printf("3. Added secondary series (Budget) to right Y-axis...\n");
/* Configure chart title */
chart_title_set_name(chart, "Department Employees and Budget");
/* Configure X-axis */
chart_axis_set_name(chart->x_axis, "Department");
/* Configure primary Y-axis (left side) */
chart_axis_set_name(chart->y_axis, "Employees");
/* Configure secondary Y-axis (right side) */
chart_axis_set_name(chart->y2_axis, "Budget ($M)");
/* Position the secondary Y-axis title on the right side of the chart */
lxw_chart_layout layout = {
.x = 0.686,
.y = 0.314,
.width = 0.0,
.height = 0.0,
.has_inner = LXW_FALSE
};
chart_axis_set_name_layout(chart->y2_axis, &layout);
printf("4. Configured chart title and axis labels...\n");
/* Insert the chart into the worksheet */
worksheet_insert_chart(worksheet, CELL("E2"), chart);
printf("5. Inserted chart into worksheet...\n");
/* Save the workbook */
printf("6. Saving workbook...\n");
lxw_error result = workbook_close(workbook);
if (result == LXW_NO_ERROR) {
printf("\n✓ SUCCESS! Created test_bar_y2.xlsx\n\n");
printf("Expected behavior:\n");
printf(" - Horizontal bar chart with TWO Y-axes\n");
printf(" - Employees series on left Y-axis (0-50 range)\n");
printf(" - Budget series on right Y-axis (0-10M range)\n");
printf(" - Both series plotted against departments on X-axis\n");
printf(" - Two barChart elements in the XML\n");
printf(" - Four axes total (2 X-axes, 2 Y-axes)\n\n");
printf("Open test_bar_y2.xlsx in Excel to verify!\n");
return 0;
} else {
printf("\n✗ ERROR creating workbook: %d\n", result);
return 1;
}
}

113
examples/test_column_y2.c Normal file
View file

@ -0,0 +1,113 @@
/*
* Test program to verify column chart secondary Y-axis functionality.
* Tests vertical column chart with two series on different Y-axes.
*/
#include "xlsxwriter.h"
#include <stdio.h>
int main() {
printf("=== Column Chart Secondary Y-Axis Test ===\n\n");
lxw_workbook *workbook = workbook_new("test_column_y2.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Data");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_COLUMN);
lxw_chart_series *series1, *series2;
/* Write headers */
worksheet_write_string(worksheet, 0, 0, "Product", NULL);
worksheet_write_string(worksheet, 0, 1, "Sales (Units)", NULL);
worksheet_write_string(worksheet, 0, 2, "Profit ($K)", NULL);
/* Write some data with different scales to demonstrate secondary axis. */
/* Column A: X-axis values (products) */
const char *products[] = {"Widget A", "Widget B", "Widget C", "Widget D", "Widget E", "Widget F"};
for (int i = 0; i < 6; i++) {
worksheet_write_string(worksheet, i + 1, 0, products[i], NULL);
}
/* Column B: Large scale values - Sales Units (primary Y-axis, left side) */
double sales[] = {1250, 1850, 2340, 1920, 2680, 3120};
for (int i = 0; i < 6; i++) {
worksheet_write_number(worksheet, i + 1, 1, sales[i], NULL);
}
/* Column C: Small scale values - Profit in thousands (secondary Y-axis, right side) */
double profit[] = {45.2, 68.5, 92.3, 71.8, 105.6, 128.4};
for (int i = 0; i < 6; i++) {
worksheet_write_number(worksheet, i + 1, 2, profit[i], NULL);
}
printf("1. Writing test data (6 products, 2 series with different scales)...\n");
/* Add series to primary Y-axis (left side) - Sales */
series1 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$7",
"=Data!$B$2:$B$7",
chart->y_axis);
/* Set series name */
chart_series_set_name(series1, "=Data!$B$1");
printf("2. Added primary series (Sales) to left Y-axis...\n");
/* Add series to secondary Y-axis (right side) - Profit */
series2 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$7",
"=Data!$C$2:$C$7",
chart->y2_axis);
/* Set series name */
chart_series_set_name(series2, "=Data!$C$1");
printf("3. Added secondary series (Profit) to right Y-axis...\n");
/* Configure chart title */
chart_title_set_name(chart, "Product Sales and Profit");
/* Configure X-axis */
chart_axis_set_name(chart->x_axis, "Product");
/* Configure primary Y-axis (left side) */
chart_axis_set_name(chart->y_axis, "Sales (Units)");
/* Configure secondary Y-axis (right side) */
chart_axis_set_name(chart->y2_axis, "Profit ($K)");
/* Position the secondary Y-axis title on the right side of the chart */
lxw_chart_layout layout = {
.x = 0.686,
.y = 0.314,
.width = 0.0,
.height = 0.0,
.has_inner = LXW_FALSE
};
chart_axis_set_name_layout(chart->y2_axis, &layout);
printf("4. Configured chart title and axis labels...\n");
/* Insert the chart into the worksheet */
worksheet_insert_chart(worksheet, CELL("E2"), chart);
printf("5. Inserted chart into worksheet...\n");
/* Save the workbook */
printf("6. Saving workbook...\n");
lxw_error result = workbook_close(workbook);
if (result == LXW_NO_ERROR) {
printf("\n✓ SUCCESS! Created test_column_y2.xlsx\n\n");
printf("Expected behavior:\n");
printf(" - Column chart with TWO Y-axes\n");
printf(" - Sales series on left Y-axis (0-3500 range)\n");
printf(" - Profit series on right Y-axis (0-140K range)\n");
printf(" - Both series plotted against products on X-axis\n");
printf(" - Two barChart elements in the XML (with barDir=\"col\")\n");
printf(" - Four axes total (2 X-axes, 2 Y-axes)\n\n");
printf("Open test_column_y2.xlsx in Excel to verify!\n");
return 0;
} else {
printf("\n✗ ERROR creating workbook: %d\n", result);
return 1;
}
}

View file

@ -0,0 +1,146 @@
/*
* Test program to create a styled scatter chart in a chartsheet.
* This is the chartsheet version of test_scatter_styled.c
* Features:
* - Circle markers with custom colors (blue/orange to approximate accent1/accent2)
* - No lines connecting markers
* - Legend at bottom
* - Secondary Y-axis
* - Formatted axis titles
* - Chart displayed in a dedicated chartsheet
*/
#include "xlsxwriter.h"
#include <stdio.h>
int main() {
printf("=== Styled Scatter Chart in Chartsheet ===\n\n");
lxw_workbook *workbook = workbook_new("test_scatter_chartsheet.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Data");
lxw_chartsheet *chartsheet = workbook_add_chartsheet(workbook, "Chart");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_SCATTER);
lxw_chart_series *series1, *series2;
/* Write headers */
worksheet_write_string(worksheet, 0, 0, "Time (hours)", NULL);
worksheet_write_string(worksheet, 0, 1, "Velocity (m/s)", NULL);
worksheet_write_string(worksheet, 0, 2, "Distance (km)", NULL);
/* Write time data (X-axis) */
double time[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 0, time[i], NULL);
}
/* Write velocity data (primary Y-axis, left side) */
double velocity[] = {0, 5.5, 12.3, 18.7, 22.1, 23.8, 24.2, 24.5, 24.7};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 1, velocity[i], NULL);
}
/* Write distance data (secondary Y-axis, right side) */
double distance[] = {0, 5, 25, 70, 135, 215, 285, 385, 500};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 2, distance[i], NULL);
}
printf("1. Writing test data (9 time points, 2 series)...\n");
/* Configure colors to approximate Excel's accent1 (blue) and accent2 (orange) */
lxw_color_t accent1_color = 0x4472C4; /* Excel default accent1: blue */
lxw_color_t accent2_color = 0xED7D31; /* Excel default accent2: orange */
/* Configure series 1 (Velocity) on primary Y-axis */
series1 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$10",
"=Data!$B$2:$B$10",
chart->y_axis);
chart_series_set_name(series1, "=Data!$B$1");
/* Set marker style for series 1 - circle with blue fill */
chart_series_set_marker_type(series1, LXW_CHART_MARKER_CIRCLE);
chart_series_set_marker_size(series1, 5);
lxw_chart_fill marker1_fill = {.color = accent1_color};
chart_series_set_marker_fill(series1, &marker1_fill);
lxw_chart_line marker1_line = {.color = accent1_color};
chart_series_set_marker_line(series1, &marker1_line);
/* Remove connecting line for series 1 (markers only) */
lxw_chart_line no_line = {.none = 1};
chart_series_set_line(series1, &no_line);
printf("2. Added primary series (Velocity) with blue circle markers...\n");
/* Configure series 2 (Distance) on secondary Y-axis */
series2 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$10",
"=Data!$C$2:$C$10",
chart->y2_axis);
chart_series_set_name(series2, "=Data!$C$1");
/* Set marker style for series 2 - circle with orange fill */
chart_series_set_marker_type(series2, LXW_CHART_MARKER_CIRCLE);
chart_series_set_marker_size(series2, 5);
lxw_chart_fill marker2_fill = {.color = accent2_color};
chart_series_set_marker_fill(series2, &marker2_fill);
lxw_chart_line marker2_line = {.color = accent2_color};
chart_series_set_marker_line(series2, &marker2_line);
/* Remove connecting line for series 2 (markers only) */
chart_series_set_line(series2, &no_line);
printf("3. Added secondary series (Distance) with orange circle markers...\n");
/* Configure chart title */
chart_title_set_name(chart, "Velocity (m/s) vs Distance (km)");
/* Configure X-axis */
chart_axis_set_name(chart->x_axis, "Time (hours)");
/* Configure primary Y-axis (left side) */
chart_axis_set_name(chart->y_axis, "Velocity (m/s)");
/* Configure secondary Y-axis (right side) */
chart_axis_set_name(chart->y2_axis, "Distance (km)");
/* Position legend at bottom */
chart_legend_set_position(chart, LXW_CHART_LEGEND_BOTTOM);
printf("4. Configured chart title, axis labels, and legend...\n");
/* Add the chart to the chartsheet (instead of inserting into worksheet) */
chartsheet_set_chart(chartsheet, chart);
/* Make the chartsheet the active sheet when the workbook is opened */
chartsheet_activate(chartsheet);
printf("5. Added chart to chartsheet...\n");
/* Save the workbook */
printf("6. Saving workbook...\n");
lxw_error result = workbook_close(workbook);
if (result == LXW_NO_ERROR) {
printf("\n✓ SUCCESS! Created test_scatter_chartsheet.xlsx\n\n");
printf("Styling features:\n");
printf(" - Circle markers (size 5) for both series\n");
printf(" - Series 1: Blue markers (accent1 approximation)\n");
printf(" - Series 2: Orange markers (accent2 approximation)\n");
printf(" - No connecting lines (markers only)\n");
printf(" - Legend positioned at bottom\n");
printf(" - Two Y-axes (left for Velocity, right for Distance)\n");
printf(" - Chart in dedicated chartsheet (not embedded in worksheet)\n\n");
printf("Open test_scatter_chartsheet.xlsx in Excel to verify!\n");
return 0;
} else {
printf("\n✗ ERROR creating workbook: %d\n", result);
return 1;
}
}

View file

@ -0,0 +1,139 @@
/*
* Test program to create a styled scatter chart matching test_scatter_y2_good.xlsx formatting.
* Features:
* - Circle markers with custom colors (blue/orange to approximate accent1/accent2)
* - No lines connecting markers
* - Legend at bottom
* - Secondary Y-axis
* - Formatted axis titles
*/
#include "xlsxwriter.h"
#include <stdio.h>
int main() {
printf("=== Styled Scatter Chart with Secondary Y-Axis ===\n\n");
lxw_workbook *workbook = workbook_new("test_scatter_styled.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Data");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_SCATTER);
lxw_chart_series *series1, *series2;
/* Write headers */
worksheet_write_string(worksheet, 0, 0, "Time (hours)", NULL);
worksheet_write_string(worksheet, 0, 1, "Velocity (m/s)", NULL);
worksheet_write_string(worksheet, 0, 2, "Distance (km)", NULL);
/* Write time data (X-axis) */
double time[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 0, time[i], NULL);
}
/* Write velocity data (primary Y-axis, left side) */
double velocity[] = {0, 5.5, 12.3, 18.7, 22.1, 23.8, 24.2, 24.5, 24.7};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 1, velocity[i], NULL);
}
/* Write distance data (secondary Y-axis, right side) */
double distance[] = {0, 5, 25, 70, 135, 215, 285, 385, 500};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 2, distance[i], NULL);
}
printf("1. Writing test data (9 time points, 2 series)...\n");
/* Configure colors to approximate Excel's accent1 (blue) and accent2 (orange) */
lxw_color_t accent1_color = 0x4472C4; /* Excel default accent1: blue */
lxw_color_t accent2_color = 0xED7D31; /* Excel default accent2: orange */
/* Configure series 1 (Velocity) on primary Y-axis */
series1 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$10",
"=Data!$B$2:$B$10",
chart->y_axis);
chart_series_set_name(series1, "=Data!$B$1");
/* Set marker style for series 1 - circle with blue fill */
chart_series_set_marker_type(series1, LXW_CHART_MARKER_CIRCLE);
chart_series_set_marker_size(series1, 5);
lxw_chart_fill marker1_fill = {.color = accent1_color};
chart_series_set_marker_fill(series1, &marker1_fill);
lxw_chart_line marker1_line = {.color = accent1_color};
chart_series_set_marker_line(series1, &marker1_line);
/* Remove connecting line for series 1 (markers only) */
lxw_chart_line no_line = {.none = 1};
chart_series_set_line(series1, &no_line);
printf("2. Added primary series (Velocity) with blue circle markers...\n");
/* Configure series 2 (Distance) on secondary Y-axis */
series2 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$10",
"=Data!$C$2:$C$10",
chart->y2_axis);
chart_series_set_name(series2, "=Data!$C$1");
/* Set marker style for series 2 - circle with orange fill */
chart_series_set_marker_type(series2, LXW_CHART_MARKER_CIRCLE);
chart_series_set_marker_size(series2, 5);
lxw_chart_fill marker2_fill = {.color = accent2_color};
chart_series_set_marker_fill(series2, &marker2_fill);
lxw_chart_line marker2_line = {.color = accent2_color};
chart_series_set_marker_line(series2, &marker2_line);
/* Remove connecting line for series 2 (markers only) */
chart_series_set_line(series2, &no_line);
printf("3. Added secondary series (Distance) with orange circle markers...\n");
/* Configure chart title */
chart_title_set_name(chart, "Velocity (m/s) vs Distance (km)");
/* Configure X-axis */
chart_axis_set_name(chart->x_axis, "Time (hours)");
/* Configure primary Y-axis (left side) */
chart_axis_set_name(chart->y_axis, "Velocity (m/s)");
/* Configure secondary Y-axis (right side) */
chart_axis_set_name(chart->y2_axis, "Distance (km)");
/* Position legend at bottom */
chart_legend_set_position(chart, LXW_CHART_LEGEND_BOTTOM);
printf("4. Configured chart title, axis labels, and legend...\n");
/* Insert the chart into the worksheet */
worksheet_insert_chart(worksheet, CELL("E2"), chart);
printf("5. Inserted chart into worksheet...\n");
/* Save the workbook */
printf("6. Saving workbook...\n");
lxw_error result = workbook_close(workbook);
if (result == LXW_NO_ERROR) {
printf("\n✓ SUCCESS! Created test_scatter_styled.xlsx\n\n");
printf("Styling features:\n");
printf(" - Circle markers (size 5) for both series\n");
printf(" - Series 1: Blue markers (accent1 approximation)\n");
printf(" - Series 2: Orange markers (accent2 approximation)\n");
printf(" - No connecting lines (markers only)\n");
printf(" - Legend positioned at bottom\n");
printf(" - Two Y-axes (left for Velocity, right for Distance)\n\n");
printf("Open test_scatter_styled.xlsx in Excel to verify!\n");
return 0;
} else {
printf("\n✗ ERROR creating workbook: %d\n", result);
return 1;
}
}

113
examples/test_scatter_y2.c Normal file
View file

@ -0,0 +1,113 @@
/*
* Test program to verify scatter chart secondary Y-axis functionality.
* Tests scatter chart with two series on different Y-axes.
*/
#include "xlsxwriter.h"
#include <stdio.h>
int main() {
printf("=== Scatter Chart Secondary Y-Axis Test ===\n\n");
lxw_workbook *workbook = workbook_new("test_scatter_y2.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Data");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_SCATTER);
lxw_chart_series *series1, *series2;
/* Write headers */
worksheet_write_string(worksheet, 0, 0, "Time (hours)", NULL);
worksheet_write_string(worksheet, 0, 1, "Velocity (m/s)", NULL);
worksheet_write_string(worksheet, 0, 2, "Distance (km)", NULL);
/* Write some data with different scales to demonstrate secondary axis. */
/* Column A: X-axis values (time in hours) */
double time[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 0, time[i], NULL);
}
/* Column B: Small scale values - Velocity in m/s (primary Y-axis, left side) */
double velocity[] = {0, 5.5, 12.3, 18.7, 22.1, 23.8, 24.2, 24.5, 24.7};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 1, velocity[i], NULL);
}
/* Column C: Large scale values - Distance in km (secondary Y-axis, right side) */
double distance[] = {0, 10, 35, 75, 130, 200, 285, 385, 500};
for (int i = 0; i < 9; i++) {
worksheet_write_number(worksheet, i + 1, 2, distance[i], NULL);
}
printf("1. Writing test data (9 time points, 2 series with different scales)...\n");
/* Add series to primary Y-axis (left side) - Velocity */
series1 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$10",
"=Data!$B$2:$B$10",
chart->y_axis);
/* Set series name */
chart_series_set_name(series1, "=Data!$B$1");
printf("2. Added primary series (Velocity) to left Y-axis...\n");
/* Add series to secondary Y-axis (right side) - Distance */
series2 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$10",
"=Data!$C$2:$C$10",
chart->y2_axis);
/* Set series name */
chart_series_set_name(series2, "=Data!$C$1");
printf("3. Added secondary series (Distance) to right Y-axis...\n");
/* Configure chart title */
chart_title_set_name(chart, "Velocity and Distance vs Time");
/* Configure X-axis */
chart_axis_set_name(chart->x_axis, "Time (hours)");
/* Configure primary Y-axis (left side) */
chart_axis_set_name(chart->y_axis, "Velocity (m/s)");
/* Configure secondary Y-axis (right side) */
chart_axis_set_name(chart->y2_axis, "Distance (km)");
/* Position the secondary Y-axis title on the right side of the chart */
lxw_chart_layout layout = {
.x = 0.686,
.y = 0.314,
.width = 0.0,
.height = 0.0,
.has_inner = LXW_FALSE
};
chart_axis_set_name_layout(chart->y2_axis, &layout);
printf("4. Configured chart title and axis labels...\n");
/* Insert the chart into the worksheet */
worksheet_insert_chart(worksheet, CELL("E2"), chart);
printf("5. Inserted chart into worksheet...\n");
/* Save the workbook */
printf("6. Saving workbook...\n");
lxw_error result = workbook_close(workbook);
if (result == LXW_NO_ERROR) {
printf("\n✓ SUCCESS! Created test_scatter_y2.xlsx\n\n");
printf("Expected behavior:\n");
printf(" - Scatter chart with TWO Y-axes\n");
printf(" - Velocity series on left Y-axis (0-25 m/s range)\n");
printf(" - Distance series on right Y-axis (0-500 km range)\n");
printf(" - Both series plotted against time on X-axis\n");
printf(" - Two scatterChart elements in the XML\n");
printf(" - Four axes total (2 X-axes, 2 Y-axes)\n\n");
printf("Open test_scatter_y2.xlsx in Excel to verify!\n");
return 0;
} else {
printf("\n✗ ERROR creating workbook: %d\n", result);
return 1;
}
}

View file

@ -0,0 +1,81 @@
/*
* Test program to verify single Y-axis functionality (baseline test).
* This ensures our secondary axis changes didn't break normal charts.
*/
#include "xlsxwriter.h"
#include <stdio.h>
int main() {
printf("=== Single Y-Axis Test (Baseline) ===\n\n");
lxw_workbook *workbook = workbook_new("test_single_axis.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Sales");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_LINE);
/* Write headers */
worksheet_write_string(worksheet, 0, 0, "Quarter", NULL);
worksheet_write_string(worksheet, 0, 1, "Sales", NULL);
worksheet_write_string(worksheet, 0, 2, "Profit", NULL);
printf("1. Writing test data...\n");
/* Write quarter labels */
const char *quarters[] = {"Q1", "Q2", "Q3", "Q4"};
for (int i = 0; i < 4; i++) {
worksheet_write_string(worksheet, i + 1, 0, quarters[i], NULL);
}
/* Write sales data */
double sales[] = {120, 180, 220, 195};
for (int i = 0; i < 4; i++) {
worksheet_write_number(worksheet, i + 1, 1, sales[i], NULL);
}
/* Write profit data */
double profit[] = {45, 68, 82, 71};
for (int i = 0; i < 4; i++) {
worksheet_write_number(worksheet, i + 1, 2, profit[i], NULL);
}
printf("2. Adding two series to PRIMARY Y-axis only...\n");
/* Add first series - Sales (using default/primary axis) */
lxw_chart_series *series1 = chart_add_series(chart,
"=Sales!$A$2:$A$5",
"=Sales!$B$2:$B$5");
chart_series_set_name(series1, "=Sales!$B$1");
/* Add second series - Profit (using default/primary axis) */
lxw_chart_series *series2 = chart_add_series(chart,
"=Sales!$A$2:$A$5",
"=Sales!$C$2:$C$5");
chart_series_set_name(series2, "=Sales!$C$1");
printf("3. Configuring chart...\n");
/* Configure chart */
chart_title_set_name(chart, "Quarterly Sales and Profit");
chart_axis_set_name(chart->x_axis, "Quarter");
chart_axis_set_name(chart->y_axis, "Amount ($K)");
/* Insert chart */
worksheet_insert_chart(worksheet, CELL("E2"), chart);
printf("4. Saving workbook...\n");
lxw_error result = workbook_close(workbook);
if (result == LXW_NO_ERROR) {
printf("\n✓ SUCCESS! Created test_single_axis.xlsx\n\n");
printf("Expected behavior:\n");
printf(" - Chart with ONE Y-axis (standard chart)\n");
printf(" - Two series (Sales and Profit) on same scale\n");
printf(" - Chart style and color files should still be generated\n\n");
printf("This verifies our changes didn't break normal charts!\n");
return 0;
} else {
printf("\n✗ ERROR creating workbook: %d\n", result);
return 1;
}
}

116
examples/test_y2_axis.c Normal file
View file

@ -0,0 +1,116 @@
/*
* Comprehensive test program to verify secondary Y-axis functionality.
* Tests chart style files, color files, and relationships generation.
*/
#include "xlsxwriter.h"
#include <stdio.h>
int main() {
printf("=== Secondary Y-Axis Test ===\n\n");
lxw_workbook *workbook = workbook_new("test_secondary_axis.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Data");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_LINE);
lxw_chart_series *series1, *series2;
/* Write headers */
worksheet_write_string(worksheet, 0, 0, "Month", NULL);
worksheet_write_string(worksheet, 0, 1, "Temperature (°C)", NULL);
worksheet_write_string(worksheet, 0, 2, "Revenue ($1000s)", NULL);
/* Write some data with different scales to demonstrate secondary axis. */
/* Column A: X-axis values (months) */
const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug"};
for (int i = 0; i < 8; i++) {
worksheet_write_string(worksheet, i + 1, 0, months[i], NULL);
}
/* Column B: Small scale values - Temperature (primary Y-axis, left side) */
double temperatures[] = {5.2, 7.8, 12.5, 16.3, 21.7, 25.4, 28.1, 26.8};
for (int i = 0; i < 8; i++) {
worksheet_write_number(worksheet, i + 1, 1, temperatures[i], NULL);
}
/* Column C: Large scale values - Revenue (secondary Y-axis, right side) */
double revenue[] = {1250, 1580, 2340, 2890, 3420, 3950, 4200, 3880};
for (int i = 0; i < 8; i++) {
worksheet_write_number(worksheet, i + 1, 2, revenue[i], NULL);
}
printf("1. Writing test data (8 months, 2 series with different scales)...\n");
/* Add series to primary Y-axis (left side) - Temperature */
series1 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$9",
"=Data!$B$2:$B$9",
chart->y_axis);
/* Set series name */
chart_series_set_name(series1, "=Data!$B$1");
printf("2. Added primary series (Temperature) to left Y-axis...\n");
/* Add series to secondary Y-axis (right side) - Revenue */
series2 = chart_add_series_on_axis(chart,
"=Data!$A$2:$A$9",
"=Data!$C$2:$C$9",
chart->y2_axis);
/* Set series name */
chart_series_set_name(series2, "=Data!$C$1");
printf("3. Added secondary series (Revenue) to right Y-axis...\n");
/* Configure chart title */
chart_title_set_name(chart, "Monthly Temperature vs Revenue");
/* Configure primary Y-axis (left side) */
chart_axis_set_name(chart->y_axis, "Temperature (°C)");
/* Configure secondary Y-axis (right side) */
chart_axis_set_name(chart->y2_axis, "Revenue ($1000s)");
/* Position the secondary Y-axis title on the right side of the chart */
lxw_chart_layout layout = {
.x = 0.686,
.y = 0.314,
.width = 0.0,
.height = 0.0,
.has_inner = LXW_FALSE
};
chart_axis_set_name_layout(chart->y2_axis, &layout);
/* Configure X-axis */
chart_axis_set_name(chart->x_axis, "Month");
printf("4. Configured chart title and axis labels...\n");
/* Insert the chart into the worksheet */
worksheet_insert_chart(worksheet, CELL("E2"), chart);
printf("5. Inserted chart into worksheet...\n");
/* Save the workbook */
printf("6. Saving workbook...\n");
lxw_error result = workbook_close(workbook);
if (result == LXW_NO_ERROR) {
printf("\n✓ SUCCESS! Created test_secondary_axis.xlsx\n\n");
printf("Expected files in the XLSX package:\n");
printf(" - xl/charts/chart1.xml (main chart definition)\n");
printf(" - xl/charts/style1.xml (chart style - NEW!)\n");
printf(" - xl/charts/colors1.xml (chart colors - NEW!)\n");
printf(" - xl/charts/_rels/chart1.xml.rels (relationships - NEW!)\n");
printf(" - [Content_Types].xml (with style/color registrations - NEW!)\n\n");
printf("The chart should display:\n");
printf(" - Temperature line on left Y-axis (0-30°C range)\n");
printf(" - Revenue line on right Y-axis (0-4500k range)\n");
printf(" - Both series properly scaled and visible\n\n");
printf("Open test_secondary_axis.xlsx in Excel to verify!\n");
return 0;
} else {
printf("\n✗ ERROR creating workbook: %d\n", result);
return 1;
}
}

View file

@ -1025,6 +1025,9 @@ typedef enum lxw_chart_trendline_type {
LXW_CHART_TRENDLINE_TYPE_AVERAGE
} lxw_chart_trendline_type;
/* Forward declaration for lxw_chart_axis. */
struct lxw_chart_axis;
/**
* @brief Struct to represent an Excel chart data series.
*
@ -1037,6 +1040,7 @@ typedef struct lxw_chart_series {
lxw_series_range *categories;
lxw_series_range *values;
lxw_chart_title title;
struct lxw_chart_axis *y_axis;
lxw_chart_line *line;
lxw_chart_fill *fill;
lxw_chart_pattern *pattern;
@ -1185,6 +1189,12 @@ typedef struct lxw_chart {
*/
lxw_chart_axis *y_axis;
/**
* A pointer to the chart y2_axis object which can be used in functions
* that configure the secondary Y axis.
*/
lxw_chart_axis *y2_axis;
lxw_chart_title title;
uint32_t id;
@ -1354,6 +1364,43 @@ lxw_chart_series *chart_add_series(lxw_chart *chart,
const char *categories,
const char *values);
/**
* @brief Add a data series to a chart on a specified Y-axis.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param categories The range of categories in the data series.
* @param values The range of values in the data series.
* @param y_axis Pointer to Y-axis (chart->y_axis, chart->y2_axis, or NULL for primary).
*
* @return A lxw_chart_series object pointer.
*
* This function works the same as chart_add_series() but allows you to specify
* which Y-axis the series should be plotted against. This is useful when you
* want to plot series with different scales on the same chart.
*
* @code
* // Add series to secondary Y-axis (right side)
* chart_add_series_on_axis(chart, "=Sheet1!$A$2:$A$7",
* "=Sheet1!$C$2:$C$7", chart->y2_axis);
*
* // Add series to primary Y-axis (left side)
* chart_add_series_on_axis(chart, "=Sheet1!$A$2:$A$7",
* "=Sheet1!$B$2:$B$7", chart->y_axis);
*
* // Configure the secondary Y-axis
* chart_axis_set_name(chart->y2_axis, "Secondary Axis");
* @endcode
*
* Pass NULL for y_axis to use the primary Y-axis (chart->y_axis).
*
* Note: Not all chart types support secondary axes. Pie, doughnut, and radar
* charts will return NULL if you attempt to add a series to a secondary axis.
*/
lxw_chart_series *chart_add_series_on_axis(lxw_chart *chart,
const char *categories,
const char *values,
lxw_chart_axis *y_axis);
/**
* @brief Set a series "categories" range using row and column values.
*

View file

@ -110,9 +110,6 @@ typedef enum lxw_error {
/** Function string parameter is empty. */
LXW_ERROR_PARAMETER_IS_EMPTY,
/** A #lxw_datetime parameter has a validation error. */
LXW_ERROR_DATETIME_VALIDATION,
/** Worksheet name exceeds Excel's limit of 31 characters. */
LXW_ERROR_SHEETNAME_LENGTH_EXCEEDED,

View file

@ -52,6 +52,10 @@ void lxw_ct_add_chartsheet_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_chart_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_chart_style_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_chart_colors_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_drawing_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_table_name(lxw_content_types *content_types,

View file

@ -61,6 +61,8 @@ void lxw_add_ms_package_relationship(lxw_relationships *self,
void lxw_add_worksheet_relationship(lxw_relationships *self, const char *type,
const char *target,
const char *target_mode);
void lxw_add_chart_style_relationship(lxw_relationships *self);
void lxw_add_chart_color_relationship(lxw_relationships *self);
void lxw_add_rich_value_relationship(lxw_relationships *self);
/* Declarations required for unit testing. */

View file

@ -212,30 +212,6 @@ double lxw_datetime_to_excel_datetime(lxw_datetime *datetime);
double lxw_datetime_to_excel_date_with_epoch(lxw_datetime *datetime,
uint8_t use_1904_epoch);
/**
* @brief Validate a #lxw_datetime struct.
*
* Validates a #lxw_datetime struct to ensure its fields are within acceptable
* ranges for Excel dates and times.
*
* The members of the #lxw_datetime struct and the range of their values are:
*
* Member | Value
* -------- | -----------
* year | 1900 - 9999
* month | 1 - 12
* day | 1 - 31
* hour | 0 - 23
* min | 0 - 59
* sec | 0 - 59.999
*
* @param datetime A pointer to a #lxw_datetime struct.
*
* @return A #lxw_error code. Either #LXW_NO_ERROR or
* #LXW_ERROR_DATETIME_VALIDATION if a field is out of range.
*/
lxw_error lxw_datetime_validate(lxw_datetime *datetime);
/**
* @brief Converts a unix datetime to an Excel datetime number.
*

804
libxlsxwriter_LV.h Normal file
View file

@ -0,0 +1,804 @@
/*
* libxlsxwriter_LV.h - Combined public API header for libxlsxwriter
*
* This header contains all public exported API functions with standard
* C calling convention (__stdcall/WINAPI) declarations.
* All macros have been expanded to their equivalent code.
*
* SPDX-License-Identifier: BSD-2-Clause
* Copyright 2014-2025, John McNamara, jmcnamara@cpan.org.
*
* Generated for LabVIEW integration.
*/
#ifndef __LIBXLSXWRITER_LV_H__
#define __LIBXLSXWRITER_LV_H__
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ============================================================================
* Calling Convention Definition
* ============================================================================ */
#if defined(_WIN32) || defined(_WIN64)
#define LXW_CALL __stdcall
#else
#define LXW_CALL
#endif
/* ============================================================================
* Basic Type Definitions
* ============================================================================ */
/** Integer data type to represent a row value (max 1,048,576). */
typedef uint32_t lxw_row_t;
/** Integer data type to represent a column value (max 16,384). */
typedef uint16_t lxw_col_t;
/** The type for RGB colors (0x000000 to 0xFFFFFF). */
typedef uint32_t lxw_color_t;
/* ============================================================================
* Boolean Values
* ============================================================================ */
enum lxw_boolean {
LXW_FALSE = 0,
LXW_TRUE = 1,
LXW_EXPLICIT_FALSE = 2
};
/* ============================================================================
* Error Codes
* ============================================================================ */
typedef enum lxw_error {
LXW_NO_ERROR = 0,
LXW_ERROR_MEMORY_MALLOC_FAILED,
LXW_ERROR_CREATING_XLSX_FILE,
LXW_ERROR_CREATING_TMPFILE,
LXW_ERROR_READING_TMPFILE,
LXW_ERROR_ZIP_FILE_OPERATION,
LXW_ERROR_ZIP_PARAMETER_ERROR,
LXW_ERROR_ZIP_BAD_ZIP_FILE,
LXW_ERROR_ZIP_INTERNAL_ERROR,
LXW_ERROR_ZIP_FILE_ADD,
LXW_ERROR_ZIP_CLOSE,
LXW_ERROR_FEATURE_NOT_SUPPORTED,
LXW_ERROR_NULL_PARAMETER_IGNORED,
LXW_ERROR_PARAMETER_VALIDATION,
LXW_ERROR_PARAMETER_IS_EMPTY,
LXW_ERROR_SHEETNAME_LENGTH_EXCEEDED,
LXW_ERROR_INVALID_SHEETNAME_CHARACTER,
LXW_ERROR_SHEETNAME_START_END_APOSTROPHE,
LXW_ERROR_SHEETNAME_ALREADY_USED,
LXW_ERROR_32_STRING_LENGTH_EXCEEDED,
LXW_ERROR_128_STRING_LENGTH_EXCEEDED,
LXW_ERROR_255_STRING_LENGTH_EXCEEDED,
LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED,
LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND,
LXW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE,
LXW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED,
LXW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED,
LXW_ERROR_IMAGE_DIMENSIONS,
LXW_MAX_ERRNO
} lxw_error;
/* ============================================================================
* Datetime Structure
* ============================================================================ */
typedef struct lxw_datetime {
int year; /* 1900 - 9999 */
int month; /* 1 - 12 */
int day; /* 1 - 31 */
int hour; /* 0 - 23 */
int min; /* 0 - 59 */
double sec; /* 0 - 59.999 */
} lxw_datetime;
/* ============================================================================
* Chart Types
* ============================================================================ */
typedef enum lxw_chart_type {
LXW_CHART_NONE = 0,
LXW_CHART_AREA,
LXW_CHART_AREA_STACKED,
LXW_CHART_AREA_STACKED_PERCENT,
LXW_CHART_BAR,
LXW_CHART_BAR_STACKED,
LXW_CHART_BAR_STACKED_PERCENT,
LXW_CHART_COLUMN,
LXW_CHART_COLUMN_STACKED,
LXW_CHART_COLUMN_STACKED_PERCENT,
LXW_CHART_DOUGHNUT,
LXW_CHART_LINE,
LXW_CHART_LINE_STACKED,
LXW_CHART_LINE_STACKED_PERCENT,
LXW_CHART_PIE,
LXW_CHART_SCATTER,
LXW_CHART_SCATTER_STRAIGHT,
LXW_CHART_SCATTER_STRAIGHT_WITH_MARKERS,
LXW_CHART_SCATTER_SMOOTH,
LXW_CHART_SCATTER_SMOOTH_WITH_MARKERS,
LXW_CHART_RADAR,
LXW_CHART_RADAR_WITH_MARKERS,
LXW_CHART_RADAR_FILLED
} lxw_chart_type;
typedef enum lxw_chart_legend_position {
LXW_CHART_LEGEND_NONE = 0,
LXW_CHART_LEGEND_RIGHT,
LXW_CHART_LEGEND_LEFT,
LXW_CHART_LEGEND_TOP,
LXW_CHART_LEGEND_BOTTOM,
LXW_CHART_LEGEND_TOP_RIGHT,
LXW_CHART_LEGEND_OVERLAY_RIGHT,
LXW_CHART_LEGEND_OVERLAY_LEFT,
LXW_CHART_LEGEND_OVERLAY_TOP_RIGHT
} lxw_chart_legend_position;
typedef enum lxw_chart_line_dash_type {
LXW_CHART_LINE_DASH_SOLID = 0,
LXW_CHART_LINE_DASH_ROUND_DOT,
LXW_CHART_LINE_DASH_SQUARE_DOT,
LXW_CHART_LINE_DASH_DASH,
LXW_CHART_LINE_DASH_DASH_DOT,
LXW_CHART_LINE_DASH_LONG_DASH,
LXW_CHART_LINE_DASH_LONG_DASH_DOT,
LXW_CHART_LINE_DASH_LONG_DASH_DOT_DOT,
LXW_CHART_LINE_DASH_DOT,
LXW_CHART_LINE_DASH_SYSTEM_DASH_DOT,
LXW_CHART_LINE_DASH_SYSTEM_DASH_DOT_DOT
} lxw_chart_line_dash_type;
typedef enum lxw_chart_marker_type {
LXW_CHART_MARKER_AUTOMATIC,
LXW_CHART_MARKER_NONE,
LXW_CHART_MARKER_SQUARE,
LXW_CHART_MARKER_DIAMOND,
LXW_CHART_MARKER_TRIANGLE,
LXW_CHART_MARKER_X,
LXW_CHART_MARKER_STAR,
LXW_CHART_MARKER_SHORT_DASH,
LXW_CHART_MARKER_LONG_DASH,
LXW_CHART_MARKER_CIRCLE,
LXW_CHART_MARKER_PLUS
} lxw_chart_marker_type;
typedef enum lxw_chart_label_position {
LXW_CHART_LABEL_POSITION_DEFAULT,
LXW_CHART_LABEL_POSITION_CENTER,
LXW_CHART_LABEL_POSITION_RIGHT,
LXW_CHART_LABEL_POSITION_LEFT,
LXW_CHART_LABEL_POSITION_ABOVE,
LXW_CHART_LABEL_POSITION_BELOW,
LXW_CHART_LABEL_POSITION_INSIDE_BASE,
LXW_CHART_LABEL_POSITION_INSIDE_END,
LXW_CHART_LABEL_POSITION_OUTSIDE_END,
LXW_CHART_LABEL_POSITION_BEST_FIT
} lxw_chart_label_position;
typedef enum lxw_chart_label_separator {
LXW_CHART_LABEL_SEPARATOR_COMMA,
LXW_CHART_LABEL_SEPARATOR_SEMICOLON,
LXW_CHART_LABEL_SEPARATOR_PERIOD,
LXW_CHART_LABEL_SEPARATOR_NEWLINE,
LXW_CHART_LABEL_SEPARATOR_SPACE
} lxw_chart_label_separator;
typedef enum lxw_chart_axis_tick_position {
LXW_CHART_AXIS_POSITION_DEFAULT,
LXW_CHART_AXIS_POSITION_ON_TICK,
LXW_CHART_AXIS_POSITION_BETWEEN
} lxw_chart_axis_tick_position;
typedef enum lxw_chart_axis_label_position {
LXW_CHART_AXIS_LABEL_POSITION_NEXT_TO,
LXW_CHART_AXIS_LABEL_POSITION_HIGH,
LXW_CHART_AXIS_LABEL_POSITION_LOW,
LXW_CHART_AXIS_LABEL_POSITION_NONE
} lxw_chart_axis_label_position;
typedef enum lxw_chart_axis_label_alignment {
LXW_CHART_AXIS_LABEL_ALIGN_CENTER,
LXW_CHART_AXIS_LABEL_ALIGN_LEFT,
LXW_CHART_AXIS_LABEL_ALIGN_RIGHT
} lxw_chart_axis_label_alignment;
typedef enum lxw_chart_axis_display_unit {
LXW_CHART_AXIS_UNITS_NONE,
LXW_CHART_AXIS_UNITS_HUNDREDS,
LXW_CHART_AXIS_UNITS_THOUSANDS,
LXW_CHART_AXIS_UNITS_TEN_THOUSANDS,
LXW_CHART_AXIS_UNITS_HUNDRED_THOUSANDS,
LXW_CHART_AXIS_UNITS_MILLIONS,
LXW_CHART_AXIS_UNITS_TEN_MILLIONS,
LXW_CHART_AXIS_UNITS_HUNDRED_MILLIONS,
LXW_CHART_AXIS_UNITS_BILLIONS,
LXW_CHART_AXIS_UNITS_TRILLIONS
} lxw_chart_axis_display_unit;
typedef enum lxw_chart_axis_tick_mark {
LXW_CHART_AXIS_TICK_MARK_DEFAULT,
LXW_CHART_AXIS_TICK_MARK_NONE,
LXW_CHART_AXIS_TICK_MARK_INSIDE,
LXW_CHART_AXIS_TICK_MARK_OUTSIDE,
LXW_CHART_AXIS_TICK_MARK_CROSSING
} lxw_chart_tick_mark;
typedef enum lxw_chart_blank {
LXW_CHART_BLANKS_AS_GAP,
LXW_CHART_BLANKS_AS_ZERO,
LXW_CHART_BLANKS_AS_CONNECTED
} lxw_chart_blank;
typedef enum lxw_chart_error_bar_type {
LXW_CHART_ERROR_BAR_TYPE_STD_ERROR,
LXW_CHART_ERROR_BAR_TYPE_FIXED,
LXW_CHART_ERROR_BAR_TYPE_PERCENTAGE,
LXW_CHART_ERROR_BAR_TYPE_STD_DEV
} lxw_chart_error_bar_type;
typedef enum lxw_chart_error_bar_direction {
LXW_CHART_ERROR_BAR_DIR_BOTH,
LXW_CHART_ERROR_BAR_DIR_PLUS,
LXW_CHART_ERROR_BAR_DIR_MINUS
} lxw_chart_error_bar_direction;
typedef enum lxw_chart_error_bar_cap {
LXW_CHART_ERROR_BAR_END_CAP,
LXW_CHART_ERROR_BAR_NO_CAP
} lxw_chart_error_bar_cap;
typedef enum lxw_chart_trendline_type {
LXW_CHART_TRENDLINE_TYPE_LINEAR,
LXW_CHART_TRENDLINE_TYPE_LOG,
LXW_CHART_TRENDLINE_TYPE_POLY,
LXW_CHART_TRENDLINE_TYPE_POWER,
LXW_CHART_TRENDLINE_TYPE_EXP,
LXW_CHART_TRENDLINE_TYPE_AVERAGE
} lxw_chart_trendline_type;
/* ============================================================================
* Format Enums
* ============================================================================ */
enum lxw_format_underlines {
LXW_UNDERLINE_NONE = 0,
LXW_UNDERLINE_SINGLE,
LXW_UNDERLINE_DOUBLE,
LXW_UNDERLINE_SINGLE_ACCOUNTING,
LXW_UNDERLINE_DOUBLE_ACCOUNTING
};
enum lxw_format_scripts {
LXW_FONT_SUPERSCRIPT = 1,
LXW_FONT_SUBSCRIPT
};
enum lxw_format_alignments {
LXW_ALIGN_NONE = 0,
LXW_ALIGN_LEFT,
LXW_ALIGN_CENTER,
LXW_ALIGN_RIGHT,
LXW_ALIGN_FILL,
LXW_ALIGN_JUSTIFY,
LXW_ALIGN_CENTER_ACROSS,
LXW_ALIGN_DISTRIBUTED,
LXW_ALIGN_VERTICAL_TOP,
LXW_ALIGN_VERTICAL_BOTTOM,
LXW_ALIGN_VERTICAL_CENTER,
LXW_ALIGN_VERTICAL_JUSTIFY,
LXW_ALIGN_VERTICAL_DISTRIBUTED
};
enum lxw_format_diagonal_types {
LXW_DIAGONAL_BORDER_UP = 1,
LXW_DIAGONAL_BORDER_DOWN,
LXW_DIAGONAL_BORDER_UP_DOWN
};
enum lxw_defined_colors {
LXW_COLOR_BLACK = 0x1000000,
LXW_COLOR_BLUE = 0x0000FF,
LXW_COLOR_BROWN = 0x800000,
LXW_COLOR_CYAN = 0x00FFFF,
LXW_COLOR_GRAY = 0x808080,
LXW_COLOR_GREEN = 0x008000,
LXW_COLOR_LIME = 0x00FF00,
LXW_COLOR_MAGENTA = 0xFF00FF,
LXW_COLOR_NAVY = 0x000080,
LXW_COLOR_ORANGE = 0xFF6600,
LXW_COLOR_PINK = 0xFF00FF,
LXW_COLOR_PURPLE = 0x800080,
LXW_COLOR_RED = 0xFF0000,
LXW_COLOR_SILVER = 0xC0C0C0,
LXW_COLOR_WHITE = 0xFFFFFF,
LXW_COLOR_YELLOW = 0xFFFF00
};
enum lxw_format_patterns {
LXW_PATTERN_NONE = 0,
LXW_PATTERN_SOLID,
LXW_PATTERN_MEDIUM_GRAY,
LXW_PATTERN_DARK_GRAY,
LXW_PATTERN_LIGHT_GRAY,
LXW_PATTERN_DARK_HORIZONTAL,
LXW_PATTERN_DARK_VERTICAL,
LXW_PATTERN_DARK_DOWN,
LXW_PATTERN_DARK_UP,
LXW_PATTERN_DARK_GRID,
LXW_PATTERN_DARK_TRELLIS,
LXW_PATTERN_LIGHT_HORIZONTAL,
LXW_PATTERN_LIGHT_VERTICAL,
LXW_PATTERN_LIGHT_DOWN,
LXW_PATTERN_LIGHT_UP,
LXW_PATTERN_LIGHT_GRID,
LXW_PATTERN_LIGHT_TRELLIS,
LXW_PATTERN_GRAY_125,
LXW_PATTERN_GRAY_0625
};
enum lxw_format_borders {
LXW_BORDER_NONE,
LXW_BORDER_THIN,
LXW_BORDER_MEDIUM,
LXW_BORDER_DASHED,
LXW_BORDER_DOTTED,
LXW_BORDER_THICK,
LXW_BORDER_DOUBLE,
LXW_BORDER_HAIR,
LXW_BORDER_MEDIUM_DASHED,
LXW_BORDER_DASH_DOT,
LXW_BORDER_MEDIUM_DASH_DOT,
LXW_BORDER_DASH_DOT_DOT,
LXW_BORDER_MEDIUM_DASH_DOT_DOT,
LXW_BORDER_SLANT_DASH_DOT
};
/* ============================================================================
* Forward Declarations (Opaque Pointers)
* ============================================================================ */
typedef struct lxw_workbook lxw_workbook;
typedef struct lxw_worksheet lxw_worksheet;
typedef struct lxw_chartsheet lxw_chartsheet;
typedef struct lxw_chart lxw_chart;
typedef struct lxw_chart_series lxw_chart_series;
typedef struct lxw_chart_axis lxw_chart_axis;
typedef struct lxw_format lxw_format;
typedef struct lxw_chart_line lxw_chart_line;
typedef struct lxw_chart_fill lxw_chart_fill;
typedef struct lxw_chart_pattern lxw_chart_pattern;
typedef struct lxw_chart_font lxw_chart_font;
typedef struct lxw_chart_layout lxw_chart_layout;
typedef struct lxw_chart_point lxw_chart_point;
typedef struct lxw_chart_data_label lxw_chart_data_label;
typedef struct lxw_series_error_bars lxw_series_error_bars;
typedef struct lxw_row_col_options lxw_row_col_options;
typedef struct lxw_image_options lxw_image_options;
typedef struct lxw_chart_options lxw_chart_options;
typedef struct lxw_protection lxw_protection;
typedef struct lxw_header_footer_options lxw_header_footer_options;
typedef struct lxw_data_validation lxw_data_validation;
typedef struct lxw_conditional_format lxw_conditional_format;
typedef struct lxw_button_options lxw_button_options;
typedef struct lxw_table_options lxw_table_options;
typedef struct lxw_filter_rule lxw_filter_rule;
typedef struct lxw_rich_string_tuple lxw_rich_string_tuple;
typedef struct lxw_comment_options lxw_comment_options;
typedef struct lxw_workbook_options lxw_workbook_options;
typedef struct lxw_doc_properties lxw_doc_properties;
/* ============================================================================
* Chart Line/Fill/Pattern Structures (for inline initialization)
* ============================================================================ */
struct lxw_chart_line {
lxw_color_t color;
uint8_t none;
float width;
uint8_t dash_type;
uint8_t transparency;
};
struct lxw_chart_fill {
lxw_color_t color;
uint8_t none;
uint8_t transparency;
};
struct lxw_chart_pattern {
lxw_color_t fg_color;
lxw_color_t bg_color;
uint8_t type;
};
struct lxw_chart_font {
const char *name;
double size;
uint8_t bold;
uint8_t italic;
uint8_t underline;
int32_t rotation;
lxw_color_t color;
uint8_t pitch_family;
uint8_t charset;
int8_t baseline;
};
struct lxw_chart_layout {
double x;
double y;
double width;
double height;
uint8_t has_inner;
};
/* ============================================================================
* WORKBOOK FUNCTIONS
* ============================================================================ */
lxw_workbook * LXW_CALL workbook_new(const char *filename);
lxw_workbook * LXW_CALL workbook_new_opt(const char *filename, lxw_workbook_options *options);
lxw_worksheet * LXW_CALL workbook_add_worksheet(lxw_workbook *workbook, const char *sheetname);
lxw_chartsheet * LXW_CALL workbook_add_chartsheet(lxw_workbook *workbook, const char *sheetname);
lxw_format * LXW_CALL workbook_add_format(lxw_workbook *workbook);
lxw_chart * LXW_CALL workbook_add_chart(lxw_workbook *workbook, uint8_t chart_type);
lxw_error LXW_CALL workbook_close(lxw_workbook *workbook);
lxw_error LXW_CALL workbook_set_properties(lxw_workbook *workbook, lxw_doc_properties *properties);
lxw_error LXW_CALL workbook_set_custom_property_string(lxw_workbook *workbook, const char *name, const char *value);
lxw_error LXW_CALL workbook_set_custom_property_number(lxw_workbook *workbook, const char *name, double value);
lxw_error LXW_CALL workbook_set_custom_property_integer(lxw_workbook *workbook, const char *name, int32_t value);
lxw_error LXW_CALL workbook_set_custom_property_boolean(lxw_workbook *workbook, const char *name, uint8_t value);
lxw_error LXW_CALL workbook_set_custom_property_datetime(lxw_workbook *workbook, const char *name, lxw_datetime *datetime);
lxw_error LXW_CALL workbook_define_name(lxw_workbook *workbook, const char *name, const char *formula);
lxw_format * LXW_CALL workbook_get_default_url_format(lxw_workbook *workbook);
lxw_worksheet * LXW_CALL workbook_get_worksheet_by_name(lxw_workbook *workbook, const char *name);
lxw_chartsheet * LXW_CALL workbook_get_chartsheet_by_name(lxw_workbook *workbook, const char *name);
lxw_error LXW_CALL workbook_validate_sheet_name(lxw_workbook *workbook, const char *sheetname);
lxw_error LXW_CALL workbook_add_vba_project(lxw_workbook *workbook, const char *filename);
lxw_error LXW_CALL workbook_add_signed_vba_project(lxw_workbook *workbook, const char *vba_project, const char *signature);
lxw_error LXW_CALL workbook_set_vba_name(lxw_workbook *workbook, const char *name);
void LXW_CALL workbook_read_only_recommended(lxw_workbook *workbook);
void LXW_CALL workbook_use_1904_epoch(lxw_workbook *workbook);
void LXW_CALL workbook_set_size(lxw_workbook *workbook, uint16_t width, uint16_t height);
/* ============================================================================
* WORKSHEET FUNCTIONS
* ============================================================================ */
lxw_error LXW_CALL worksheet_write_number(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, double number, lxw_format *format);
lxw_error LXW_CALL worksheet_write_string(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *string, lxw_format *format);
lxw_error LXW_CALL worksheet_write_formula(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *formula, lxw_format *format);
lxw_error LXW_CALL worksheet_write_array_formula(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col, const char *formula, lxw_format *format);
lxw_error LXW_CALL worksheet_write_dynamic_array_formula(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col, const char *formula, lxw_format *format);
lxw_error LXW_CALL worksheet_write_dynamic_formula(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *formula, lxw_format *format);
lxw_error LXW_CALL worksheet_write_datetime(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, lxw_datetime *datetime, lxw_format *format);
lxw_error LXW_CALL worksheet_write_unixtime(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, int64_t unixtime, lxw_format *format);
lxw_error LXW_CALL worksheet_write_url(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *url, lxw_format *format);
lxw_error LXW_CALL worksheet_write_url_opt(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *url, lxw_format *format, const char *string, const char *tooltip);
lxw_error LXW_CALL worksheet_write_boolean(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, int value, lxw_format *format);
lxw_error LXW_CALL worksheet_write_blank(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, lxw_format *format);
lxw_error LXW_CALL worksheet_write_formula_num(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *formula, lxw_format *format, double result);
lxw_error LXW_CALL worksheet_write_formula_str(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *formula, lxw_format *format, const char *result);
lxw_error LXW_CALL worksheet_write_rich_string(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, lxw_rich_string_tuple *rich_string[], lxw_format *format);
lxw_error LXW_CALL worksheet_write_comment(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *string);
lxw_error LXW_CALL worksheet_write_comment_opt(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *string, lxw_comment_options *options);
lxw_error LXW_CALL worksheet_set_row(lxw_worksheet *worksheet, lxw_row_t row, double height, lxw_format *format);
lxw_error LXW_CALL worksheet_set_row_opt(lxw_worksheet *worksheet, lxw_row_t row, double height, lxw_format *format, lxw_row_col_options *options);
lxw_error LXW_CALL worksheet_set_row_pixels(lxw_worksheet *worksheet, lxw_row_t row, uint32_t pixels, lxw_format *format);
lxw_error LXW_CALL worksheet_set_row_pixels_opt(lxw_worksheet *worksheet, lxw_row_t row, uint32_t pixels, lxw_format *format, lxw_row_col_options *options);
lxw_error LXW_CALL worksheet_set_column(lxw_worksheet *worksheet, lxw_col_t first_col, lxw_col_t last_col, double width, lxw_format *format);
lxw_error LXW_CALL worksheet_set_column_opt(lxw_worksheet *worksheet, lxw_col_t first_col, lxw_col_t last_col, double width, lxw_format *format, lxw_row_col_options *options);
lxw_error LXW_CALL worksheet_set_column_pixels(lxw_worksheet *worksheet, lxw_col_t first_col, lxw_col_t last_col, uint32_t pixels, lxw_format *format);
lxw_error LXW_CALL worksheet_set_column_pixels_opt(lxw_worksheet *worksheet, lxw_col_t first_col, lxw_col_t last_col, uint32_t pixels, lxw_format *format, lxw_row_col_options *options);
lxw_error LXW_CALL worksheet_insert_image(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *filename);
lxw_error LXW_CALL worksheet_insert_image_opt(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *filename, lxw_image_options *options);
lxw_error LXW_CALL worksheet_insert_image_buffer(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const unsigned char *image_buffer, size_t image_size);
lxw_error LXW_CALL worksheet_insert_image_buffer_opt(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const unsigned char *image_buffer, size_t image_size, lxw_image_options *options);
lxw_error LXW_CALL worksheet_embed_image(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *filename);
lxw_error LXW_CALL worksheet_embed_image_opt(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const char *filename, lxw_image_options *options);
lxw_error LXW_CALL worksheet_embed_image_buffer(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const unsigned char *image_buffer, size_t image_size);
lxw_error LXW_CALL worksheet_embed_image_buffer_opt(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, const unsigned char *image_buffer, size_t image_size, lxw_image_options *options);
lxw_error LXW_CALL worksheet_set_background(lxw_worksheet *worksheet, const char *filename);
lxw_error LXW_CALL worksheet_set_background_buffer(lxw_worksheet *worksheet, const unsigned char *image_buffer, size_t image_size);
lxw_error LXW_CALL worksheet_insert_chart(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, lxw_chart *chart);
lxw_error LXW_CALL worksheet_insert_chart_opt(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, lxw_chart *chart, lxw_chart_options *options);
lxw_error LXW_CALL worksheet_merge_range(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col, const char *string, lxw_format *format);
lxw_error LXW_CALL worksheet_autofilter(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col);
lxw_error LXW_CALL worksheet_filter_column(lxw_worksheet *worksheet, lxw_col_t col, lxw_filter_rule *rule);
lxw_error LXW_CALL worksheet_filter_column2(lxw_worksheet *worksheet, lxw_col_t col, lxw_filter_rule *rule1, lxw_filter_rule *rule2, uint8_t and_or);
lxw_error LXW_CALL worksheet_filter_list(lxw_worksheet *worksheet, lxw_col_t col, const char **list);
lxw_error LXW_CALL worksheet_data_validation_cell(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, lxw_data_validation *validation);
lxw_error LXW_CALL worksheet_data_validation_range(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col, lxw_data_validation *validation);
lxw_error LXW_CALL worksheet_conditional_format_cell(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, lxw_conditional_format *conditional_format);
lxw_error LXW_CALL worksheet_conditional_format_range(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col, lxw_conditional_format *conditional_format);
lxw_error LXW_CALL worksheet_insert_button(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col, lxw_button_options *options);
lxw_error LXW_CALL worksheet_add_table(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col, lxw_table_options *options);
void LXW_CALL worksheet_activate(lxw_worksheet *worksheet);
void LXW_CALL worksheet_select(lxw_worksheet *worksheet);
void LXW_CALL worksheet_hide(lxw_worksheet *worksheet);
void LXW_CALL worksheet_set_first_sheet(lxw_worksheet *worksheet);
void LXW_CALL worksheet_freeze_panes(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col);
void LXW_CALL worksheet_split_panes(lxw_worksheet *worksheet, double vertical, double horizontal);
lxw_error LXW_CALL worksheet_set_selection(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col);
void LXW_CALL worksheet_set_top_left_cell(lxw_worksheet *worksheet, lxw_row_t row, lxw_col_t col);
void LXW_CALL worksheet_set_landscape(lxw_worksheet *worksheet);
void LXW_CALL worksheet_set_portrait(lxw_worksheet *worksheet);
void LXW_CALL worksheet_set_page_view(lxw_worksheet *worksheet);
void LXW_CALL worksheet_set_paper(lxw_worksheet *worksheet, uint8_t paper_type);
void LXW_CALL worksheet_set_margins(lxw_worksheet *worksheet, double left, double right, double top, double bottom);
lxw_error LXW_CALL worksheet_set_header(lxw_worksheet *worksheet, const char *string);
lxw_error LXW_CALL worksheet_set_footer(lxw_worksheet *worksheet, const char *string);
lxw_error LXW_CALL worksheet_set_header_opt(lxw_worksheet *worksheet, const char *string, lxw_header_footer_options *options);
lxw_error LXW_CALL worksheet_set_footer_opt(lxw_worksheet *worksheet, const char *string, lxw_header_footer_options *options);
lxw_error LXW_CALL worksheet_set_h_pagebreaks(lxw_worksheet *worksheet, lxw_row_t breaks[]);
lxw_error LXW_CALL worksheet_set_v_pagebreaks(lxw_worksheet *worksheet, lxw_col_t breaks[]);
void LXW_CALL worksheet_print_across(lxw_worksheet *worksheet);
void LXW_CALL worksheet_set_zoom(lxw_worksheet *worksheet, uint16_t scale);
void LXW_CALL worksheet_gridlines(lxw_worksheet *worksheet, uint8_t option);
void LXW_CALL worksheet_center_horizontally(lxw_worksheet *worksheet);
void LXW_CALL worksheet_center_vertically(lxw_worksheet *worksheet);
void LXW_CALL worksheet_print_row_col_headers(lxw_worksheet *worksheet);
lxw_error LXW_CALL worksheet_repeat_rows(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_row_t last_row);
lxw_error LXW_CALL worksheet_repeat_columns(lxw_worksheet *worksheet, lxw_col_t first_col, lxw_col_t last_col);
lxw_error LXW_CALL worksheet_print_area(lxw_worksheet *worksheet, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col);
void LXW_CALL worksheet_fit_to_pages(lxw_worksheet *worksheet, uint16_t width, uint16_t height);
void LXW_CALL worksheet_set_start_page(lxw_worksheet *worksheet, uint16_t start_page);
void LXW_CALL worksheet_set_print_scale(lxw_worksheet *worksheet, uint16_t scale);
void LXW_CALL worksheet_print_black_and_white(lxw_worksheet *worksheet);
void LXW_CALL worksheet_right_to_left(lxw_worksheet *worksheet);
void LXW_CALL worksheet_hide_zero(lxw_worksheet *worksheet);
void LXW_CALL worksheet_set_tab_color(lxw_worksheet *worksheet, lxw_color_t color);
void LXW_CALL worksheet_protect(lxw_worksheet *worksheet, const char *password, lxw_protection *options);
void LXW_CALL worksheet_outline_settings(lxw_worksheet *worksheet, uint8_t visible, uint8_t symbols_below, uint8_t symbols_right, uint8_t auto_style);
void LXW_CALL worksheet_set_default_row(lxw_worksheet *worksheet, double height, uint8_t hide_unused_rows);
lxw_error LXW_CALL worksheet_set_vba_name(lxw_worksheet *worksheet, const char *name);
void LXW_CALL worksheet_show_comments(lxw_worksheet *worksheet);
void LXW_CALL worksheet_set_comments_author(lxw_worksheet *worksheet, const char *author);
lxw_error LXW_CALL worksheet_ignore_errors(lxw_worksheet *worksheet, uint8_t type, const char *range);
/* ============================================================================
* CHARTSHEET FUNCTIONS
* ============================================================================ */
lxw_error LXW_CALL chartsheet_set_chart(lxw_chartsheet *chartsheet, lxw_chart *chart);
lxw_error LXW_CALL chartsheet_set_chart_opt(lxw_chartsheet *chartsheet, lxw_chart *chart, lxw_chart_options *user_options);
void LXW_CALL chartsheet_activate(lxw_chartsheet *chartsheet);
void LXW_CALL chartsheet_select(lxw_chartsheet *chartsheet);
void LXW_CALL chartsheet_hide(lxw_chartsheet *chartsheet);
void LXW_CALL chartsheet_set_first_sheet(lxw_chartsheet *chartsheet);
void LXW_CALL chartsheet_set_tab_color(lxw_chartsheet *chartsheet, lxw_color_t color);
void LXW_CALL chartsheet_protect(lxw_chartsheet *chartsheet, const char *password, lxw_protection *options);
void LXW_CALL chartsheet_set_zoom(lxw_chartsheet *chartsheet, uint16_t scale);
void LXW_CALL chartsheet_set_landscape(lxw_chartsheet *chartsheet);
void LXW_CALL chartsheet_set_portrait(lxw_chartsheet *chartsheet);
void LXW_CALL chartsheet_set_paper(lxw_chartsheet *chartsheet, uint8_t paper_type);
void LXW_CALL chartsheet_set_margins(lxw_chartsheet *chartsheet, double left, double right, double top, double bottom);
lxw_error LXW_CALL chartsheet_set_header(lxw_chartsheet *chartsheet, const char *string);
lxw_error LXW_CALL chartsheet_set_footer(lxw_chartsheet *chartsheet, const char *string);
lxw_error LXW_CALL chartsheet_set_header_opt(lxw_chartsheet *chartsheet, const char *string, lxw_header_footer_options *options);
lxw_error LXW_CALL chartsheet_set_footer_opt(lxw_chartsheet *chartsheet, const char *string, lxw_header_footer_options *options);
/* ============================================================================
* CHART FUNCTIONS
* ============================================================================ */
lxw_chart_series * LXW_CALL chart_add_series(lxw_chart *chart, const char *categories, const char *values);
lxw_chart_series * LXW_CALL chart_add_series_on_axis(lxw_chart *chart, const char *categories, const char *values, lxw_chart_axis *y_axis);
void LXW_CALL chart_series_set_categories(lxw_chart_series *series, const char *sheetname, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col);
void LXW_CALL chart_series_set_values(lxw_chart_series *series, const char *sheetname, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col);
void LXW_CALL chart_series_set_name(lxw_chart_series *series, const char *name);
void LXW_CALL chart_series_set_name_range(lxw_chart_series *series, const char *sheetname, lxw_row_t row, lxw_col_t col);
void LXW_CALL chart_series_set_line(lxw_chart_series *series, lxw_chart_line *line);
void LXW_CALL chart_series_set_fill(lxw_chart_series *series, lxw_chart_fill *fill);
void LXW_CALL chart_series_set_invert_if_negative(lxw_chart_series *series);
void LXW_CALL chart_series_set_pattern(lxw_chart_series *series, lxw_chart_pattern *pattern);
void LXW_CALL chart_series_set_marker_type(lxw_chart_series *series, uint8_t type);
void LXW_CALL chart_series_set_marker_size(lxw_chart_series *series, uint8_t size);
void LXW_CALL chart_series_set_marker_line(lxw_chart_series *series, lxw_chart_line *line);
void LXW_CALL chart_series_set_marker_fill(lxw_chart_series *series, lxw_chart_fill *fill);
void LXW_CALL chart_series_set_marker_pattern(lxw_chart_series *series, lxw_chart_pattern *pattern);
lxw_error LXW_CALL chart_series_set_points(lxw_chart_series *series, lxw_chart_point *points[]);
void LXW_CALL chart_series_set_smooth(lxw_chart_series *series, uint8_t smooth);
void LXW_CALL chart_series_set_labels(lxw_chart_series *series);
void LXW_CALL chart_series_set_labels_options(lxw_chart_series *series, uint8_t show_name, uint8_t show_category, uint8_t show_value);
lxw_error LXW_CALL chart_series_set_labels_custom(lxw_chart_series *series, lxw_chart_data_label *data_labels[]);
void LXW_CALL chart_series_set_labels_separator(lxw_chart_series *series, uint8_t separator);
void LXW_CALL chart_series_set_labels_position(lxw_chart_series *series, uint8_t position);
void LXW_CALL chart_series_set_labels_leader_line(lxw_chart_series *series);
void LXW_CALL chart_series_set_labels_legend(lxw_chart_series *series);
void LXW_CALL chart_series_set_labels_percentage(lxw_chart_series *series);
void LXW_CALL chart_series_set_labels_num_format(lxw_chart_series *series, const char *num_format);
void LXW_CALL chart_series_set_labels_font(lxw_chart_series *series, lxw_chart_font *font);
void LXW_CALL chart_series_set_labels_line(lxw_chart_series *series, lxw_chart_line *line);
void LXW_CALL chart_series_set_labels_fill(lxw_chart_series *series, lxw_chart_fill *fill);
void LXW_CALL chart_series_set_labels_pattern(lxw_chart_series *series, lxw_chart_pattern *pattern);
void LXW_CALL chart_series_set_trendline(lxw_chart_series *series, uint8_t type, uint8_t value);
void LXW_CALL chart_series_set_trendline_forecast(lxw_chart_series *series, double forward, double backward);
void LXW_CALL chart_series_set_trendline_equation(lxw_chart_series *series);
void LXW_CALL chart_series_set_trendline_r_squared(lxw_chart_series *series);
void LXW_CALL chart_series_set_trendline_intercept(lxw_chart_series *series, double intercept);
void LXW_CALL chart_series_set_trendline_name(lxw_chart_series *series, const char *name);
void LXW_CALL chart_series_set_trendline_line(lxw_chart_series *series, lxw_chart_line *line);
void LXW_CALL chart_series_set_error_bars(lxw_series_error_bars *error_bars, uint8_t type, double value);
void LXW_CALL chart_series_set_error_bars_direction(lxw_series_error_bars *error_bars, uint8_t direction);
void LXW_CALL chart_series_set_error_bars_endcap(lxw_series_error_bars *error_bars, uint8_t endcap);
void LXW_CALL chart_series_set_error_bars_line(lxw_series_error_bars *error_bars, lxw_chart_line *line);
void LXW_CALL chart_axis_set_name(lxw_chart_axis *axis, const char *name);
void LXW_CALL chart_axis_set_name_range(lxw_chart_axis *axis, const char *sheetname, lxw_row_t row, lxw_col_t col);
void LXW_CALL chart_axis_set_name_layout(lxw_chart_axis *axis, lxw_chart_layout *layout);
void LXW_CALL chart_axis_set_name_font(lxw_chart_axis *axis, lxw_chart_font *font);
void LXW_CALL chart_axis_set_num_font(lxw_chart_axis *axis, lxw_chart_font *font);
void LXW_CALL chart_axis_set_num_format(lxw_chart_axis *axis, const char *num_format);
void LXW_CALL chart_axis_set_line(lxw_chart_axis *axis, lxw_chart_line *line);
void LXW_CALL chart_axis_set_fill(lxw_chart_axis *axis, lxw_chart_fill *fill);
void LXW_CALL chart_axis_set_pattern(lxw_chart_axis *axis, lxw_chart_pattern *pattern);
void LXW_CALL chart_axis_set_reverse(lxw_chart_axis *axis);
void LXW_CALL chart_axis_set_crossing(lxw_chart_axis *axis, double value);
void LXW_CALL chart_axis_set_crossing_max(lxw_chart_axis *axis);
void LXW_CALL chart_axis_set_crossing_min(lxw_chart_axis *axis);
void LXW_CALL chart_axis_off(lxw_chart_axis *axis);
void LXW_CALL chart_axis_set_position(lxw_chart_axis *axis, uint8_t position);
void LXW_CALL chart_axis_set_label_position(lxw_chart_axis *axis, uint8_t position);
void LXW_CALL chart_axis_set_label_align(lxw_chart_axis *axis, uint8_t align);
void LXW_CALL chart_axis_set_min(lxw_chart_axis *axis, double min);
void LXW_CALL chart_axis_set_max(lxw_chart_axis *axis, double max);
void LXW_CALL chart_axis_set_log_base(lxw_chart_axis *axis, uint16_t log_base);
void LXW_CALL chart_axis_set_major_tick_mark(lxw_chart_axis *axis, uint8_t type);
void LXW_CALL chart_axis_set_minor_tick_mark(lxw_chart_axis *axis, uint8_t type);
void LXW_CALL chart_axis_set_interval_unit(lxw_chart_axis *axis, uint16_t unit);
void LXW_CALL chart_axis_set_interval_tick(lxw_chart_axis *axis, uint16_t unit);
void LXW_CALL chart_axis_set_major_unit(lxw_chart_axis *axis, double unit);
void LXW_CALL chart_axis_set_minor_unit(lxw_chart_axis *axis, double unit);
void LXW_CALL chart_axis_set_display_units(lxw_chart_axis *axis, uint8_t units);
void LXW_CALL chart_axis_set_display_units_visible(lxw_chart_axis *axis, uint8_t visible);
void LXW_CALL chart_axis_major_gridlines_set_visible(lxw_chart_axis *axis, uint8_t visible);
void LXW_CALL chart_axis_minor_gridlines_set_visible(lxw_chart_axis *axis, uint8_t visible);
void LXW_CALL chart_axis_major_gridlines_set_line(lxw_chart_axis *axis, lxw_chart_line *line);
void LXW_CALL chart_axis_minor_gridlines_set_line(lxw_chart_axis *axis, lxw_chart_line *line);
void LXW_CALL chart_title_set_name(lxw_chart *chart, const char *name);
void LXW_CALL chart_title_set_name_range(lxw_chart *chart, const char *sheetname, lxw_row_t row, lxw_col_t col);
void LXW_CALL chart_title_set_name_font(lxw_chart *chart, lxw_chart_font *font);
void LXW_CALL chart_title_off(lxw_chart *chart);
void LXW_CALL chart_title_set_layout(lxw_chart *chart, lxw_chart_layout *layout);
void LXW_CALL chart_title_set_overlay(lxw_chart *chart, uint8_t overlay);
void LXW_CALL chart_legend_set_position(lxw_chart *chart, uint8_t position);
void LXW_CALL chart_legend_set_layout(lxw_chart *chart, lxw_chart_layout *layout);
void LXW_CALL chart_legend_set_font(lxw_chart *chart, lxw_chart_font *font);
lxw_error LXW_CALL chart_legend_delete_series(lxw_chart *chart, int16_t delete_series[]);
void LXW_CALL chart_chartarea_set_line(lxw_chart *chart, lxw_chart_line *line);
void LXW_CALL chart_chartarea_set_fill(lxw_chart *chart, lxw_chart_fill *fill);
void LXW_CALL chart_chartarea_set_pattern(lxw_chart *chart, lxw_chart_pattern *pattern);
void LXW_CALL chart_plotarea_set_line(lxw_chart *chart, lxw_chart_line *line);
void LXW_CALL chart_plotarea_set_fill(lxw_chart *chart, lxw_chart_fill *fill);
void LXW_CALL chart_plotarea_set_pattern(lxw_chart *chart, lxw_chart_pattern *pattern);
void LXW_CALL chart_plotarea_set_layout(lxw_chart *chart, lxw_chart_layout *layout);
void LXW_CALL chart_set_style(lxw_chart *chart, uint8_t style_id);
void LXW_CALL chart_set_table(lxw_chart *chart);
void LXW_CALL chart_set_table_grid(lxw_chart *chart, uint8_t horizontal, uint8_t vertical, uint8_t outline, uint8_t legend_keys);
void LXW_CALL chart_set_table_font(lxw_chart *chart, lxw_chart_font *font);
void LXW_CALL chart_set_up_down_bars(lxw_chart *chart);
void LXW_CALL chart_set_up_down_bars_format(lxw_chart *chart, lxw_chart_line *up_bar_line, lxw_chart_fill *up_bar_fill, lxw_chart_line *down_bar_line, lxw_chart_fill *down_bar_fill);
void LXW_CALL chart_set_drop_lines(lxw_chart *chart, lxw_chart_line *line);
void LXW_CALL chart_set_high_low_lines(lxw_chart *chart, lxw_chart_line *line);
void LXW_CALL chart_set_series_overlap(lxw_chart *chart, int8_t overlap);
void LXW_CALL chart_set_series_gap(lxw_chart *chart, uint16_t gap);
void LXW_CALL chart_show_blanks_as(lxw_chart *chart, uint8_t option);
void LXW_CALL chart_show_hidden_data(lxw_chart *chart);
void LXW_CALL chart_set_rotation(lxw_chart *chart, uint16_t rotation);
void LXW_CALL chart_set_hole_size(lxw_chart *chart, uint8_t size);
/* ============================================================================
* FORMAT FUNCTIONS
* ============================================================================ */
void LXW_CALL format_set_font_name(lxw_format *format, const char *font_name);
void LXW_CALL format_set_font_size(lxw_format *format, double size);
void LXW_CALL format_set_font_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_bold(lxw_format *format);
void LXW_CALL format_set_italic(lxw_format *format);
void LXW_CALL format_set_underline(lxw_format *format, uint8_t style);
void LXW_CALL format_set_font_strikeout(lxw_format *format);
void LXW_CALL format_set_font_script(lxw_format *format, uint8_t style);
void LXW_CALL format_set_font_family(lxw_format *format, uint8_t value);
void LXW_CALL format_set_font_charset(lxw_format *format, uint8_t value);
void LXW_CALL format_set_num_format(lxw_format *format, const char *num_format);
void LXW_CALL format_set_num_format_index(lxw_format *format, uint8_t index);
void LXW_CALL format_set_unlocked(lxw_format *format);
void LXW_CALL format_set_hidden(lxw_format *format);
void LXW_CALL format_set_align(lxw_format *format, uint8_t alignment);
void LXW_CALL format_set_text_wrap(lxw_format *format);
void LXW_CALL format_set_rotation(lxw_format *format, int16_t angle);
void LXW_CALL format_set_indent(lxw_format *format, uint8_t level);
void LXW_CALL format_set_shrink(lxw_format *format);
void LXW_CALL format_set_pattern(lxw_format *format, uint8_t index);
void LXW_CALL format_set_bg_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_fg_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_border(lxw_format *format, uint8_t style);
void LXW_CALL format_set_bottom(lxw_format *format, uint8_t style);
void LXW_CALL format_set_top(lxw_format *format, uint8_t style);
void LXW_CALL format_set_left(lxw_format *format, uint8_t style);
void LXW_CALL format_set_right(lxw_format *format, uint8_t style);
void LXW_CALL format_set_border_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_bottom_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_top_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_left_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_right_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_diag_type(lxw_format *format, uint8_t type);
void LXW_CALL format_set_diag_border(lxw_format *format, uint8_t style);
void LXW_CALL format_set_diag_color(lxw_format *format, lxw_color_t color);
void LXW_CALL format_set_quote_prefix(lxw_format *format);
/* ============================================================================
* UTILITY FUNCTIONS
* ============================================================================ */
const char * LXW_CALL lxw_version(void);
uint16_t LXW_CALL lxw_version_id(void);
char * LXW_CALL lxw_strerror(lxw_error error_num);
void LXW_CALL lxw_col_to_name(char *col_name, lxw_col_t col_num, uint8_t absolute);
void LXW_CALL lxw_rowcol_to_cell(char *cell_name, lxw_row_t row, lxw_col_t col);
void LXW_CALL lxw_rowcol_to_cell_abs(char *cell_name, lxw_row_t row, lxw_col_t col, uint8_t abs_row, uint8_t abs_col);
void LXW_CALL lxw_rowcol_to_range(char *range, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col);
void LXW_CALL lxw_rowcol_to_range_abs(char *range, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col);
void LXW_CALL lxw_rowcol_to_formula_abs(char *formula, const char *sheetname, lxw_row_t first_row, lxw_col_t first_col, lxw_row_t last_row, lxw_col_t last_col);
uint32_t LXW_CALL lxw_name_to_row(const char *row_str);
uint16_t LXW_CALL lxw_name_to_col(const char *col_str);
uint32_t LXW_CALL lxw_name_to_row_2(const char *row_str);
uint16_t LXW_CALL lxw_name_to_col_2(const char *col_str);
double LXW_CALL lxw_datetime_to_excel_datetime(lxw_datetime *datetime);
double LXW_CALL lxw_datetime_to_excel_date_with_epoch(lxw_datetime *datetime, uint8_t use_1904_epoch);
double LXW_CALL lxw_unixtime_to_excel_date(int64_t unixtime);
double LXW_CALL lxw_unixtime_to_excel_date_with_epoch(int64_t unixtime, uint8_t use_1904_epoch);
/* ============================================================================
* MACRO REPLACEMENT FUNCTIONS
*
* The following inline functions replace the original macros:
* - CELL(cell) -> use lxw_name_to_row(cell) and lxw_name_to_col(cell) separately
* - COLS(cols) -> use lxw_name_to_col(cols) and lxw_name_to_col_2(cols) separately
* - RANGE(range) -> use lxw_name_to_row(range), lxw_name_to_col(range),
* lxw_name_to_row_2(range), lxw_name_to_col_2(range) separately
*
* Example usage:
* Instead of: worksheet_write_string(worksheet, CELL("A1"), "Hello", NULL);
* Use: worksheet_write_string(worksheet, lxw_name_to_row("A1"),
* lxw_name_to_col("A1"), "Hello", NULL);
*
* Instead of: worksheet_set_column(worksheet, COLS("B:D"), 20, NULL, NULL);
* Use: worksheet_set_column(worksheet, lxw_name_to_col("B:D"),
* lxw_name_to_col_2("B:D"), 20, NULL, NULL);
*
* Instead of: worksheet_print_area(worksheet, RANGE("A1:K42"));
* Use: worksheet_print_area(worksheet, lxw_name_to_row("A1:K42"),
* lxw_name_to_col("A1:K42"),
* lxw_name_to_row_2("A1:K42"),
* lxw_name_to_col_2("A1:K42"));
* ============================================================================ */
#ifdef __cplusplus
}
#endif
#endif /* __LIBXLSXWRITER_LV_H__ */

File diff suppressed because it is too large Load diff

View file

@ -314,6 +314,24 @@ lxw_ct_add_chart_name(lxw_content_types *self, const char *name)
lxw_ct_add_override(self, name, LXW_APP_DOCUMENT "drawingml.chart+xml");
}
/*
* Add the name of a chart style to the ContentTypes overrides.
*/
void
lxw_ct_add_chart_style_name(lxw_content_types *self, const char *name)
{
lxw_ct_add_override(self, name, "application/vnd.ms-office.chartstyle+xml");
}
/*
* Add the name of a chart color style to the ContentTypes overrides.
*/
void
lxw_ct_add_chart_colors_name(lxw_content_types *self, const char *name)
{
lxw_ct_add_override(self, name, "application/vnd.ms-office.chartcolorstyle+xml");
}
/*
* Add the name of a drawing to the ContentTypes overrides.
*/

View file

@ -247,15 +247,25 @@ _drawing_write_a_hlink_click(lxw_drawing *self, uint32_t rel_index, char *tip)
* Write the <a16:creationId> element.
*/
STATIC void
_drawing_write_a16_creation_id(lxw_drawing *self)
_drawing_write_a16_creation_id(lxw_drawing *self, uint32_t index)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char xmlns[] = "http://schemas.microsoft.com/office/drawing/2014/main";
char guid[LXW_GUID_LENGTH];
/* Generate a pseudo-GUID based on the index. */
lxw_snprintf(guid, LXW_GUID_LENGTH,
"{%08X-%04X-%04X-%04X-%012lX}",
(unsigned int)(0xCC148400 + index),
(unsigned int)0xB16C,
(unsigned int)0x9B21,
(unsigned int)0xA699,
(unsigned long)(0xF10CC9149C00UL + index));
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns:a16", xmlns);
LXW_PUSH_ATTRIBUTES_STR("id", "{00000000-0008-0000-0000-000002000000}");
LXW_PUSH_ATTRIBUTES_STR("id", guid);
lxw_xml_empty_tag(self->file, "a16:creationId", &attributes);
@ -303,12 +313,12 @@ _drawing_write_uri_ext(lxw_drawing *self, char *uri)
* Write the decorative elements.
*/
STATIC void
_workbook_write_decorative(lxw_drawing *self)
_workbook_write_decorative(lxw_drawing *self, uint32_t index)
{
lxw_xml_start_tag(self->file, "a:extLst", NULL);
_drawing_write_uri_ext(self, "{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}");
_drawing_write_a16_creation_id(self);
_drawing_write_a16_creation_id(self, index);
lxw_xml_end_tag(self->file, "a:ext");
_drawing_write_uri_ext(self, "{C183D7F6-B498-43B3-948B-1728B52AA6E4}");
@ -318,6 +328,21 @@ _workbook_write_decorative(lxw_drawing *self)
lxw_xml_end_tag(self->file, "a:extLst");
}
/*
* Write the creation ID extension list for charts.
*/
STATIC void
_drawing_write_chart_creation_id(lxw_drawing *self, uint32_t index)
{
lxw_xml_start_tag(self->file, "a:extLst", NULL);
_drawing_write_uri_ext(self, "{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}");
_drawing_write_a16_creation_id(self, index);
lxw_xml_end_tag(self->file, "a:ext");
lxw_xml_end_tag(self->file, "a:extLst");
}
/*
* Write the <xdr:cNvPr> element.
*/
@ -355,11 +380,17 @@ _drawing_write_c_nv_pr(lxw_drawing *self, char *object_name, uint32_t index,
}
if (drawing_object->decorative) {
_workbook_write_decorative(self);
_workbook_write_decorative(self, index);
}
lxw_xml_end_tag(self->file, "xdr:cNvPr");
}
else if (strcmp(object_name, "Chart") == 0) {
/* Charts need creation ID extension list. */
lxw_xml_start_tag(self->file, "xdr:cNvPr", &attributes);
_drawing_write_chart_creation_id(self, index);
lxw_xml_end_tag(self->file, "xdr:cNvPr");
}
else {
lxw_xml_empty_tag(self->file, "xdr:cNvPr", &attributes);
}

View file

@ -546,12 +546,6 @@ format_set_text_justlast(lxw_format *self)
void
format_set_pattern(lxw_format *self, uint8_t value)
{
if (value > LXW_PATTERN_GRAY_0625) {
LXW_WARN_FORMAT1("format_set_pattern(): invalid pattern value: %d",
value);
return;
}
self->pattern = value;
}
@ -695,12 +689,6 @@ format_set_diag_color(lxw_format *self, lxw_color_t color)
void
format_set_diag_border(lxw_format *self, uint8_t style)
{
if (style > LXW_BORDER_SLANT_DASH_DOT) {
LXW_WARN_FORMAT1("format_set_diag_border(): invalid border style: %d",
style);
return;
}
self->diag_border = style;
}
@ -719,13 +707,6 @@ format_set_num_format_index(lxw_format *self, uint8_t value)
void
format_set_valign(lxw_format *self, uint8_t value)
{
if (value > LXW_ALIGN_VERTICAL_DISTRIBUTED) {
LXW_WARN_FORMAT1
("format_set_valign(): invalid vertical alignment value: %d",
value);
return;
}
self->text_v_align = value;
}

View file

@ -549,6 +549,175 @@ _write_chart_files(lxw_packager *self)
return LXW_NO_ERROR;
}
/*
* Write the chart style files for charts.
*/
STATIC lxw_error
_write_chart_style_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_chart *chart;
char filename[LXW_FILENAME_LENGTH] = { 0 };
uint32_t index = 1;
lxw_error err;
/* Complete chart style XML content (based on Excel's default style 240) - from working file */
const char *style_xml =
"<cs:chartStyle xmlns:cs=\"http://schemas.microsoft.com/office/drawing/2012/chartStyle\" "
"xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" id=\"240\">"
"<cs:axisTitle><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:defRPr sz=\"1000\" kern=\"1200\"/></cs:axisTitle>"
"<cs:categoryAxis><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\">"
"<a:lumMod val=\"25000\"/><a:lumOff val=\"75000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr>"
"<cs:defRPr sz=\"900\" kern=\"1200\"/></cs:categoryAxis>"
"<cs:chartArea mods=\"allowNoFillOverride allowNoLineOverride\"><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/>"
"<cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef>"
"<cs:spPr><a:solidFill><a:schemeClr val=\"bg1\"/></a:solidFill>"
"<a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\">"
"<a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr>"
"<cs:defRPr sz=\"1000\" kern=\"1200\"/></cs:chartArea>"
"<cs:dataLabel><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"75000\"/><a:lumOff val=\"25000\"/></a:schemeClr></cs:fontRef>"
"<cs:defRPr sz=\"900\" kern=\"1200\"/></cs:dataLabel>"
"<cs:dataLabelCallout><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"dk1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:spPr><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill><a:ln><a:solidFill><a:schemeClr val=\"dk1\">"
"<a:lumMod val=\"25000\"/><a:lumOff val=\"75000\"/></a:schemeClr></a:solidFill></a:ln></cs:spPr>"
"<cs:defRPr sz=\"900\" kern=\"1200\"/><cs:bodyPr rot=\"0\" spcFirstLastPara=\"1\" vertOverflow=\"clip\" horzOverflow=\"clip\" vert=\"horz\" wrap=\"square\" lIns=\"36576\" tIns=\"18288\" rIns=\"36576\" bIns=\"18288\" anchor=\"ctr\" anchorCtr=\"1\"><a:spAutoFit/></cs:bodyPr></cs:dataLabelCallout>"
"<cs:dataPoint><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"1\"><cs:styleClr val=\"auto\"/></cs:fillRef>"
"<cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef></cs:dataPoint>"
"<cs:dataPoint3D><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"1\"><cs:styleClr val=\"auto\"/></cs:fillRef>"
"<cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef></cs:dataPoint3D>"
"<cs:dataPointLine><cs:lnRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:lnRef><cs:fillRef idx=\"1\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"19050\" cap=\"rnd\"><a:solidFill>"
"<a:schemeClr val=\"phClr\"/></a:solidFill><a:round/></a:ln></cs:spPr></cs:dataPointLine>"
"<cs:dataPointMarker><cs:lnRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:lnRef><cs:fillRef idx=\"1\"><cs:styleClr val=\"auto\"/></cs:fillRef>"
"<cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef>"
"<cs:spPr><a:ln w=\"9525\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill></a:ln></cs:spPr></cs:dataPointMarker>"
"<cs:dataPointMarkerLayout symbol=\"circle\" size=\"5\"/>"
"<cs:dataPointWireframe><cs:lnRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:lnRef><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"dk1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"rnd\"><a:solidFill>"
"<a:schemeClr val=\"phClr\"/></a:solidFill><a:round/></a:ln></cs:spPr></cs:dataPointWireframe>"
"<cs:dataTable><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:spPr><a:noFill/><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\">"
"<a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr>"
"<cs:defRPr sz=\"900\" kern=\"1200\"/></cs:dataTable>"
"<cs:downBar><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"dk1\">"
"<a:lumMod val=\"75000\"/><a:lumOff val=\"25000\"/></a:schemeClr></a:solidFill>"
"<a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\">"
"<a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:downBar>"
"<cs:dropLine><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"35000\"/><a:lumOff val=\"65000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:dropLine>"
"<cs:errorBar><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:errorBar>"
"<cs:floor><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:noFill/><a:ln><a:noFill/></a:ln></cs:spPr></cs:floor>"
"<cs:gridlineMajor><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef>"
"<cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\">"
"<a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:gridlineMajor>"
"<cs:gridlineMinor><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"5000\"/><a:lumOff val=\"95000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:gridlineMinor>"
"<cs:hiLoLine><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"50000\"/><a:lumOff val=\"50000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:hiLoLine>"
"<cs:leaderLine><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"35000\"/><a:lumOff val=\"65000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:leaderLine>"
"<cs:legend><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:defRPr sz=\"900\" kern=\"1200\"/></cs:legend>"
"<cs:plotArea mods=\"allowNoFillOverride allowNoLineOverride\"><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/>"
"<cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef></cs:plotArea>"
"<cs:plotArea3D mods=\"allowNoFillOverride allowNoLineOverride\"><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/>"
"<cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef></cs:plotArea3D>"
"<cs:seriesAxis><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:defRPr sz=\"900\" kern=\"1200\"/></cs:seriesAxis>"
"<cs:seriesLine><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"35000\"/><a:lumOff val=\"65000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:seriesLine>"
"<cs:title><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:defRPr sz=\"1400\" b=\"0\" kern=\"1200\" spc=\"0\" baseline=\"0\"/></cs:title>"
"<cs:trendline><cs:lnRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:lnRef><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"19050\" cap=\"rnd\"><a:solidFill>"
"<a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"sysDot\"/></a:ln></cs:spPr></cs:trendline>"
"<cs:trendlineLabel><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:defRPr sz=\"900\" kern=\"1200\"/></cs:trendlineLabel>"
"<cs:upBar><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill>"
"<a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\">"
"<a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:upBar>"
"<cs:valueAxis><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef>"
"<cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\">"
"<a:lumMod val=\"25000\"/><a:lumOff val=\"75000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr>"
"<cs:defRPr sz=\"900\" kern=\"1200\"/></cs:valueAxis>"
"<cs:wall><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/>"
"<cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:noFill/><a:ln><a:noFill/></a:ln></cs:spPr></cs:wall>"
"</cs:chartStyle>";
STAILQ_FOREACH(chart, workbook->ordered_charts, ordered_list_pointers) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/charts/style%d.xml", index++);
err = _add_buffer_to_zip(self, style_xml, strlen(style_xml), filename);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Write the chart color files for charts.
*/
STATIC lxw_error
_write_chart_color_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_chart *chart;
char filename[LXW_FILENAME_LENGTH] = { 0 };
uint32_t index = 1;
lxw_error err;
/* Static chart color style XML content (based on Excel's default color scheme 10) */
const char *colors_xml =
"<cs:colorStyle xmlns:cs=\"http://schemas.microsoft.com/office/drawing/2012/chartStyle\" "
"xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" meth=\"cycle\" id=\"10\">"
"<a:schemeClr val=\"accent1\"/><a:schemeClr val=\"accent2\"/><a:schemeClr val=\"accent3\"/>"
"<a:schemeClr val=\"accent4\"/><a:schemeClr val=\"accent5\"/><a:schemeClr val=\"accent6\"/>"
"<cs:variation/>"
"<cs:variation><a:lumMod val=\"60000\"/></cs:variation>"
"<cs:variation><a:lumMod val=\"80000\"/><a:lumOff val=\"20000\"/></cs:variation>"
"<cs:variation><a:lumMod val=\"80000\"/></cs:variation>"
"<cs:variation><a:lumMod val=\"60000\"/><a:lumOff val=\"40000\"/></cs:variation>"
"<cs:variation><a:lumMod val=\"50000\"/></cs:variation>"
"<cs:variation><a:lumMod val=\"70000\"/><a:lumOff val=\"30000\"/></cs:variation>"
"<cs:variation><a:lumMod val=\"70000\"/></cs:variation>"
"<cs:variation><a:lumMod val=\"50000\"/><a:lumOff val=\"50000\"/></cs:variation>"
"</cs:colorStyle>";
STAILQ_FOREACH(chart, workbook->ordered_charts, ordered_list_pointers) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/charts/colors%d.xml", index++);
err = _add_buffer_to_zip(self, colors_xml, strlen(colors_xml), filename);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Count the chart files.
*/
@ -1504,6 +1673,16 @@ _write_content_types_file(lxw_packager *self)
lxw_snprintf(filename, LXW_FILENAME_LENGTH, "/xl/charts/chart%d.xml",
index);
lxw_ct_add_chart_name(content_types, filename);
/* Register external style files (testing individually) */
lxw_snprintf(filename, LXW_FILENAME_LENGTH, "/xl/charts/style%d.xml",
index);
lxw_ct_add_chart_style_name(content_types, filename);
/* Register external color files (testing individually) */
lxw_snprintf(filename, LXW_FILENAME_LENGTH, "/xl/charts/colors%d.xml",
index);
lxw_ct_add_chart_colors_name(content_types, filename);
}
for (index = 1; index <= drawing_count; index++) {
@ -1843,6 +2022,51 @@ _write_drawing_rels_file(lxw_packager *self)
return LXW_NO_ERROR;
}
/*
* Write the chart .rels files for charts that contain style and color references.
*/
STATIC lxw_error
_write_chart_rels_files(lxw_packager *self)
{
lxw_relationships *rels;
char *buffer = NULL;
size_t buffer_size = 0;
lxw_workbook *workbook = self->workbook;
lxw_chart *chart;
char filename[LXW_FILENAME_LENGTH] = { 0 };
uint32_t index = 1;
lxw_error err;
STAILQ_FOREACH(chart, workbook->ordered_charts, ordered_list_pointers) {
rels = lxw_relationships_new();
rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!rels->file) {
lxw_free_relationships(rels);
return LXW_ERROR_CREATING_TMPFILE;
}
/* Add relationships to chart style and color files */
lxw_add_chart_style_relationship(rels);
lxw_add_chart_color_relationship(rels);
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/charts/_rels/chart%d.xml.rels", index++);
lxw_relationships_assemble_xml_file(rels);
err = _add_to_zip(self, rels->file, &buffer, &buffer_size, filename);
fclose(rels->file);
free(buffer);
lxw_free_relationships(rels);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Write the vmlDrawing .rels files for worksheets that contain images in
* headers or footers.
@ -2187,6 +2411,14 @@ lxw_create_package(lxw_packager *self)
error = _write_chart_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
/* Generate external style files (testing individually) */
error = _write_chart_style_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
/* Generate external color files (testing individually) */
error = _write_chart_color_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_drawing_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
@ -2220,6 +2452,10 @@ lxw_create_package(lxw_packager *self)
error = _write_drawing_rels_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
/* Generate chart relationship files (links to style/color files) */
error = _write_chart_rels_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_image_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);

View file

@ -245,6 +245,25 @@ lxw_add_worksheet_relationship(lxw_relationships *self, const char *type,
_add_relationship(self, LXW_SCHEMA_DOCUMENT, type, target, target_mode);
}
/*
* Add chart style and color relationships to chart .rels xml files.
*/
void
lxw_add_chart_style_relationship(lxw_relationships *self)
{
_add_relationship(self,
"http://schemas.microsoft.com/office/2011/relationships/",
"chartStyle", "style1.xml", NULL);
}
void
lxw_add_chart_color_relationship(lxw_relationships *self)
{
_add_relationship(self,
"http://schemas.microsoft.com/office/2011/relationships/",
"chartColorStyle", "colors1.xml", NULL);
}
/*
* Add a richValue relationship to sheet .rels xml files.
*/

View file

@ -41,7 +41,6 @@ char *error_strings[LXW_MAX_ERRNO + 1] = {
"NULL function parameter ignored.",
"Function parameter validation error.",
"Function string parameter is empty.",
"Datetime struct parameter has an invalid field value.",
"Worksheet name exceeds Excel's limit of 31 characters.",
"Worksheet name cannot contain invalid characters: '[ ] : * ? / \\'",
"Worksheet name cannot start or end with an apostrophe.",
@ -333,69 +332,6 @@ lxw_name_to_col_2(const char *col_str)
return 0;
}
lxw_error
lxw_datetime_validate(lxw_datetime *datetime)
{
if (!datetime)
return LXW_ERROR_DATETIME_VALIDATION;
/*
* Excel uses the year 1900 as the default epoch but it uses 1899-12-31 as
* the 0 date and internally we use the 0-0-0 date for time only values.
*/
if (datetime->year < 1900 &&
!(datetime->year == 0 &&
datetime->month == 0 && datetime->day == 0) &&
!(datetime->year == 1899 &&
datetime->month == 12 && datetime->day == 31)) {
LXW_WARN_FORMAT1("lxw_datetime_validate(): invalid year: %d. "
"Valid range is 1900-9999.", datetime->year);
return LXW_ERROR_DATETIME_VALIDATION;
}
if (datetime->year > 9999) {
LXW_WARN_FORMAT1("lxw_datetime_validate(): invalid year: %d. "
"Valid range is 1900-9999.", datetime->year);
return LXW_ERROR_DATETIME_VALIDATION;
}
if (datetime->year != 0) {
if (datetime->month < 1 || datetime->month > 12) {
LXW_WARN_FORMAT1("lxw_datetime_validate(): invalid month: %d. "
"Valid range is 1-12.", datetime->month);
return LXW_ERROR_DATETIME_VALIDATION;
}
if (datetime->day < 1 || datetime->day > 31) {
LXW_WARN_FORMAT1("lxw_datetime_validate(): invalid day: %d. "
"Valid range is 1-31.", datetime->day);
return LXW_ERROR_DATETIME_VALIDATION;
}
}
if (datetime->hour < 0 || datetime->hour > 23) {
LXW_WARN_FORMAT1("lxw_datetime_validate(): invalid hour: %d. "
"Valid range is 0-23.", datetime->hour);
return LXW_ERROR_DATETIME_VALIDATION;
}
if (datetime->min < 0 || datetime->min > 59) {
LXW_WARN_FORMAT1("lxw_datetime_validate(): invalid minute: %d. "
"Valid range is 0-59.", datetime->min);
return LXW_ERROR_DATETIME_VALIDATION;
}
if (datetime->sec < 0.0 || datetime->sec >= 60.0) {
LXW_WARN_FORMAT1("lxw_datetime_validate(): invalid seconds: %.3f. "
"Valid range is 0.0-59.999.", datetime->sec);
return LXW_ERROR_DATETIME_VALIDATION;
}
return LXW_NO_ERROR;
}
/*
* Convert a lxw_datetime struct to an Excel serial date, with a 1900
* or 1904 epoch.
@ -421,9 +357,6 @@ lxw_datetime_to_excel_date_with_epoch(lxw_datetime *datetime,
int days = 0;
int i;
if (lxw_datetime_validate(datetime) != LXW_NO_ERROR)
return 0.0;
/* For times without dates set the default date for the epoch. */
if (!year) {
if (!use_1904_epoch) {

View file

@ -13,7 +13,6 @@
#include "xlsxwriter/utility.h"
#include "xlsxwriter/packager.h"
#include "xlsxwriter/hash_table.h"
#include "xlsxwriter/hash_table.h"
STATIC int _worksheet_name_cmp(lxw_worksheet_name *name1,
lxw_worksheet_name *name2);
@ -2167,12 +2166,6 @@ workbook_add_chart(lxw_workbook *self, uint8_t type)
{
lxw_chart *chart;
if (type == LXW_CHART_NONE || type > LXW_CHART_RADAR_FILLED) {
LXW_WARN_FORMAT1("workbook_add_chart(): invalid chart type: %d",
type);
return NULL;
}
/* Create a new chart object. */
chart = lxw_chart_new(type);
@ -2660,10 +2653,6 @@ workbook_set_custom_property_datetime(lxw_workbook *self, const char *name,
return LXW_ERROR_NULL_PARAMETER_IGNORED;
}
if (lxw_datetime_validate(datetime) != LXW_NO_ERROR) {
return LXW_ERROR_DATETIME_VALIDATION;
}
/* Create a struct to hold the custom property. */
custom_property = calloc(1, sizeof(struct lxw_custom_property));
RETURN_ON_MEM_ERROR(custom_property, LXW_ERROR_MEMORY_MALLOC_FAILED);

View file

@ -3007,15 +3007,13 @@ _worksheet_position_object_pixels(lxw_worksheet *self,
height = height + y1;
/* Subtract the underlying cell widths to find the end cell. */
while (width >= _worksheet_size_col(self, col_end, anchor)
&& col_end < LXW_COL_MAX) {
while (width >= _worksheet_size_col(self, col_end, anchor)) {
width -= _worksheet_size_col(self, col_end, anchor);
col_end++;
}
/* Subtract the underlying cell heights to find the end cell. */
while (height >= _worksheet_size_row(self, row_end, anchor)
&& row_end < LXW_ROW_MAX) {
while (height >= _worksheet_size_row(self, row_end, anchor)) {
height -= _worksheet_size_row(self, row_end, anchor);
row_end++;
}
@ -8334,9 +8332,9 @@ worksheet_write_datetime(lxw_worksheet *self,
if (err)
return err;
err = lxw_datetime_validate(datetime);
if (err)
return err;
printf("worksheet_write_datetime(): %d-%02d-%02d - 1904: %d\n",
datetime->year, datetime->month, datetime->day,
self->use_1904_epoch);
excel_date =
lxw_datetime_to_excel_date_with_epoch(datetime, self->use_1904_epoch);
@ -9795,12 +9793,6 @@ worksheet_set_page_view(lxw_worksheet *self)
void
worksheet_set_paper(lxw_worksheet *self, uint8_t paper_size)
{
if (paper_size > 118) {
LXW_WARN_FORMAT1("worksheet_set_paper(): invalid paper size: %d. "
"Valid range is 0-118", paper_size);
return;
}
self->paper_size = paper_size;
self->page_setup_changed = LXW_TRUE;
}

View file

@ -30,8 +30,18 @@ CTEST(chart, chart01) {
char* got;
char exp[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<c:chartSpace xmlns:c=\"http://schemas.openxmlformats.org/drawingml/2006/chart\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
"<c:chartSpace xmlns:c=\"http://schemas.openxmlformats.org/drawingml/2006/chart\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:c16r2=\"http://schemas.microsoft.com/office/drawing/2015/06/chart\">"
"<c:date1904 val=\"0\"/>"
"<c:lang val=\"en-US\"/>"
"<c:roundedCorners val=\"0\"/>"
"<mc:AlternateContent xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\">"
"<mc:Choice xmlns:c14=\"http://schemas.microsoft.com/office/drawing/2007/8/2/chart\" Requires=\"c14\">"
"<c14:style val=\"102\"/>"
"</mc:Choice>"
"<mc:Fallback>"
"<c:style val=\"2\"/>"
"</mc:Fallback>"
"</mc:AlternateContent>"
"<c:chart>"
"<c:plotArea>"
"<c:layout/>"