mirror of
https://github.com/jmcnamara/libxlsxwriter
synced 2025-03-28 21:13:14 +00:00
parent
cf887d65ce
commit
d9f2540080
4
.indent.pro
vendored
4
.indent.pro
vendored
@ -132,6 +132,10 @@
|
||||
-T lxw_repeat_cols
|
||||
-T lxw_repeat_rows
|
||||
-T lxw_rich_string_tuple
|
||||
-T lxw_rich_value
|
||||
-T lxw_rich_value_rel
|
||||
-T lxw_rich_value_structure
|
||||
-T lxw_rich_value_types
|
||||
-T lxw_row
|
||||
-T lxw_row_col_options
|
||||
-T lxw_row_t
|
||||
|
37
examples/embed_images.c
Normal file
37
examples/embed_images.c
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* An example of embedding images into a worksheet using the libxlsxwriter
|
||||
* library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
/* Create a new workbook and add a worksheet. */
|
||||
lxw_workbook *workbook = workbook_new("embed_images.xlsx");
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
/* Change some of the column widths for clarity. */
|
||||
worksheet_set_column(worksheet, COLS("A:B"), 30, NULL);
|
||||
|
||||
/* Embed an image. */
|
||||
worksheet_write_string(worksheet, CELL("A2"), "Embed an image in a cell:", NULL);
|
||||
worksheet_embed_image(worksheet, CELL("B2"), "logo.png");
|
||||
|
||||
/* Make a row bigger and embed the image. */
|
||||
worksheet_set_row(worksheet, 3, 72, NULL);
|
||||
worksheet_write_string(worksheet, CELL("A4"), "Embed an image in a cell:", NULL);
|
||||
worksheet_embed_image(worksheet, CELL("B4"), "logo.png");
|
||||
|
||||
/* Make a row bigger and embed the image. */
|
||||
worksheet_set_row(worksheet, 5, 150, NULL);
|
||||
worksheet_write_string(worksheet, CELL("A6"), "Embed an image in a cell:", NULL);
|
||||
worksheet_embed_image(worksheet, CELL("B6"), "logo.png");
|
||||
|
||||
workbook_close(workbook);
|
||||
|
||||
return 0;
|
||||
}
|
@ -64,6 +64,7 @@ void lxw_ct_add_shared_strings(lxw_content_types *content_types);
|
||||
void lxw_ct_add_calc_chain(lxw_content_types *content_types);
|
||||
void lxw_ct_add_custom_properties(lxw_content_types *content_types);
|
||||
void lxw_ct_add_metadata(lxw_content_types *content_types);
|
||||
void lxw_ct_add_rich_value(lxw_content_types *content_types);
|
||||
|
||||
/* Declarations required for unit testing. */
|
||||
#ifdef TESTING
|
||||
|
@ -20,6 +20,9 @@
|
||||
typedef struct lxw_metadata {
|
||||
|
||||
FILE *file;
|
||||
uint8_t has_dynamic_functions;
|
||||
uint8_t has_embedded_images;
|
||||
uint32_t num_embedded_images;
|
||||
|
||||
} lxw_metadata;
|
||||
|
||||
|
@ -37,6 +37,10 @@
|
||||
#include "vml.h"
|
||||
#include "comment.h"
|
||||
#include "metadata.h"
|
||||
#include "rich_value.h"
|
||||
#include "rich_value_rel.h"
|
||||
#include "rich_value_types.h"
|
||||
#include "rich_value_structure.h"
|
||||
|
||||
#define LXW_ZIP_BUFFER_SIZE (16384)
|
||||
|
||||
|
@ -61,6 +61,7 @@ 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_rich_value_relationship(lxw_relationships *self);
|
||||
|
||||
/* Declarations required for unit testing. */
|
||||
#ifdef TESTING
|
||||
|
51
include/xlsxwriter/rich_value.h
Normal file
51
include/xlsxwriter/rich_value.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* libxlsxwriter
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||
*
|
||||
* rich_value - A libxlsxwriter library for creating Excel XLSX rich_value files.
|
||||
*
|
||||
*/
|
||||
#ifndef __LXW_RICH_VALUE_H__
|
||||
#define __LXW_RICH_VALUE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "workbook.h"
|
||||
|
||||
/*
|
||||
* Struct to represent a rich_value object.
|
||||
*/
|
||||
typedef struct lxw_rich_value {
|
||||
|
||||
FILE *file;
|
||||
lxw_workbook *workbook;
|
||||
|
||||
} lxw_rich_value;
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
lxw_rich_value *lxw_rich_value_new(void);
|
||||
void lxw_rich_value_free(lxw_rich_value *rich_value);
|
||||
void lxw_rich_value_assemble_xml_file(lxw_rich_value *self);
|
||||
|
||||
/* Declarations required for unit testing. */
|
||||
#ifdef TESTING
|
||||
|
||||
STATIC void _rich_value_xml_declaration(lxw_rich_value *self);
|
||||
|
||||
#endif /* TESTING */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* __LXW_RICH_VALUE_H__ */
|
50
include/xlsxwriter/rich_value_rel.h
Normal file
50
include/xlsxwriter/rich_value_rel.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* libxlsxwriter
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||
*
|
||||
* rich_value_rel - A libxlsxwriter library for creating Excel XLSX rich_value_rel files.
|
||||
*
|
||||
*/
|
||||
#ifndef __LXW_RICH_VALUE_REL_H__
|
||||
#define __LXW_RICH_VALUE_REL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Struct to represent a rich_value_rel object.
|
||||
*/
|
||||
typedef struct lxw_rich_value_rel {
|
||||
|
||||
FILE *file;
|
||||
uint32_t num_embedded_images;
|
||||
|
||||
} lxw_rich_value_rel;
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
lxw_rich_value_rel *lxw_rich_value_rel_new(void);
|
||||
void lxw_rich_value_rel_free(lxw_rich_value_rel *rich_value_rel);
|
||||
void lxw_rich_value_rel_assemble_xml_file(lxw_rich_value_rel *self);
|
||||
|
||||
/* Declarations required for unit testing. */
|
||||
#ifdef TESTING
|
||||
|
||||
STATIC void _rich_value_rel_xml_declaration(lxw_rich_value_rel *self);
|
||||
|
||||
#endif /* TESTING */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* __LXW_RICH_VALUE_REL_H__ */
|
53
include/xlsxwriter/rich_value_structure.h
Normal file
53
include/xlsxwriter/rich_value_structure.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* libxlsxwriter
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||
*
|
||||
* rich_value_structure - A libxlsxwriter library for creating Excel XLSX rich_value_structure files.
|
||||
*
|
||||
*/
|
||||
#ifndef __LXW_RICH_VALUE_STRUCTURE_H__
|
||||
#define __LXW_RICH_VALUE_STRUCTURE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Struct to represent a rich_value_structure object.
|
||||
*/
|
||||
typedef struct lxw_rich_value_structure {
|
||||
|
||||
FILE *file;
|
||||
uint8_t has_embedded_image_descriptions;
|
||||
|
||||
} lxw_rich_value_structure;
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
lxw_rich_value_structure *lxw_rich_value_structure_new(void);
|
||||
void lxw_rich_value_structure_free(lxw_rich_value_structure
|
||||
*rich_value_structure);
|
||||
void lxw_rich_value_structure_assemble_xml_file(lxw_rich_value_structure
|
||||
*self);
|
||||
|
||||
/* Declarations required for unit testing. */
|
||||
#ifdef TESTING
|
||||
|
||||
STATIC void _rich_value_structure_xml_declaration(lxw_rich_value_structure
|
||||
*self);
|
||||
|
||||
#endif /* TESTING */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* __LXW_RICH_VALUE_STRUCTURE_H__ */
|
49
include/xlsxwriter/rich_value_types.h
Normal file
49
include/xlsxwriter/rich_value_types.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* libxlsxwriter
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||
*
|
||||
* rich_value_types - A libxlsxwriter library for creating Excel XLSX rich_value_types files.
|
||||
*
|
||||
*/
|
||||
#ifndef __LXW_RICH_VALUE_TYPES_H__
|
||||
#define __LXW_RICH_VALUE_TYPES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Struct to represent a rich_value_types object.
|
||||
*/
|
||||
typedef struct lxw_rich_value_types {
|
||||
|
||||
FILE *file;
|
||||
|
||||
} lxw_rich_value_types;
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
lxw_rich_value_types *lxw_rich_value_types_new(void);
|
||||
void lxw_rich_value_types_free(lxw_rich_value_types *rich_value_types);
|
||||
void lxw_rich_value_types_assemble_xml_file(lxw_rich_value_types *self);
|
||||
|
||||
/* Declarations required for unit testing. */
|
||||
#ifdef TESTING
|
||||
|
||||
STATIC void _rich_value_types_xml_declaration(lxw_rich_value_types *self);
|
||||
|
||||
#endif /* TESTING */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* __LXW_RICH_VALUE_TYPES_H__ */
|
@ -299,6 +299,7 @@ typedef struct lxw_workbook {
|
||||
struct lxw_worksheet_names *worksheet_names;
|
||||
struct lxw_chartsheet_names *chartsheet_names;
|
||||
struct lxw_image_md5s *image_md5s;
|
||||
struct lxw_image_md5s *embedded_image_md5s;
|
||||
struct lxw_image_md5s *header_image_md5s;
|
||||
struct lxw_image_md5s *background_md5s;
|
||||
struct lxw_charts *charts;
|
||||
@ -337,6 +338,10 @@ typedef struct lxw_workbook {
|
||||
uint8_t has_vml;
|
||||
uint8_t has_comments;
|
||||
uint8_t has_metadata;
|
||||
uint8_t has_embedded_images;
|
||||
uint8_t has_dynamic_functions;
|
||||
|
||||
uint32_t num_embedded_images;
|
||||
|
||||
lxw_hash_table *used_xf_formats;
|
||||
lxw_hash_table *used_dxf_formats;
|
||||
|
@ -721,6 +721,7 @@ enum cell_types {
|
||||
DYNAMIC_ARRAY_FORMULA_CELL,
|
||||
BLANK_CELL,
|
||||
BOOLEAN_CELL,
|
||||
ERROR_CELL,
|
||||
COMMENT,
|
||||
HYPERLINK_URL,
|
||||
HYPERLINK_INTERNAL,
|
||||
@ -818,6 +819,7 @@ STAILQ_HEAD(lxw_selections, lxw_selection);
|
||||
STAILQ_HEAD(lxw_data_validations, lxw_data_val_obj);
|
||||
STAILQ_HEAD(lxw_cond_format_list, lxw_cond_format_obj);
|
||||
STAILQ_HEAD(lxw_image_props, lxw_object_properties);
|
||||
STAILQ_HEAD(lxw_embedded_image_props, lxw_object_properties);
|
||||
STAILQ_HEAD(lxw_chart_props, lxw_object_properties);
|
||||
STAILQ_HEAD(lxw_comment_objs, lxw_vml_obj);
|
||||
STAILQ_HEAD(lxw_table_objs, lxw_table_obj);
|
||||
@ -2120,6 +2122,7 @@ typedef struct lxw_worksheet {
|
||||
struct lxw_data_validations *data_validations;
|
||||
struct lxw_cond_format_hash *conditional_formats;
|
||||
struct lxw_image_props *image_props;
|
||||
struct lxw_image_props *embedded_image_props;
|
||||
struct lxw_chart_props *chart_data;
|
||||
struct lxw_drawing_rel_ids *drawing_rel_ids;
|
||||
struct lxw_vml_drawing_rel_ids *vml_drawing_rel_ids;
|
||||
@ -2193,7 +2196,7 @@ typedef struct lxw_worksheet {
|
||||
uint8_t zoom_scale_normal;
|
||||
uint8_t black_white;
|
||||
uint8_t num_validations;
|
||||
uint8_t has_dynamic_arrays;
|
||||
uint8_t has_dynamic_functions;
|
||||
char *vba_codename;
|
||||
uint16_t num_buttons;
|
||||
|
||||
@ -3783,6 +3786,34 @@ lxw_error worksheet_insert_image_buffer_opt(lxw_worksheet *worksheet,
|
||||
size_t image_size,
|
||||
lxw_image_options *options);
|
||||
|
||||
/**
|
||||
* @brief TODO
|
||||
*
|
||||
* @param worksheet
|
||||
* @param row
|
||||
* @param col
|
||||
* @param filename
|
||||
* @return lxw_error
|
||||
*/
|
||||
lxw_error worksheet_embed_image(lxw_worksheet *worksheet,
|
||||
lxw_row_t row, lxw_col_t col,
|
||||
const char *filename);
|
||||
|
||||
/**
|
||||
* @brief TODO
|
||||
*
|
||||
* @param worksheet
|
||||
* @param row
|
||||
* @param col
|
||||
* @param filename
|
||||
* @param options
|
||||
* @return lxw_error
|
||||
*/
|
||||
lxw_error worksheet_embed_image_opt(lxw_worksheet *worksheet,
|
||||
lxw_row_t row, lxw_col_t col,
|
||||
const char *filename,
|
||||
lxw_image_options *options);
|
||||
|
||||
/**
|
||||
* @brief Set the background image for a worksheet.
|
||||
*
|
||||
@ -5812,6 +5843,10 @@ void lxw_worksheet_write_sheet_pr(lxw_worksheet *worksheet);
|
||||
void lxw_worksheet_write_page_setup(lxw_worksheet *worksheet);
|
||||
void lxw_worksheet_write_header_footer(lxw_worksheet *worksheet);
|
||||
|
||||
void worksheet_set_error_cell(lxw_worksheet *worksheet,
|
||||
lxw_object_properties *object_props,
|
||||
uint32_t ref_id);
|
||||
|
||||
/* Declarations required for unit testing. */
|
||||
#ifdef TESTING
|
||||
|
||||
|
@ -391,3 +391,23 @@ lxw_ct_add_metadata(lxw_content_types *self)
|
||||
lxw_ct_add_override(self, "/xl/metadata.xml",
|
||||
LXW_APP_DOCUMENT "spreadsheetml.sheetMetadata+xml");
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the richValue files to the ContentTypes overrides.
|
||||
*/
|
||||
void
|
||||
lxw_ct_add_rich_value(lxw_content_types *self)
|
||||
{
|
||||
lxw_ct_add_override(self, "/xl/richData/rdRichValueTypes.xml",
|
||||
LXW_APP_MSEXCEL "rdrichvaluetypes+xml");
|
||||
|
||||
lxw_ct_add_override(self, "/xl/richData/rdrichvalue.xml",
|
||||
LXW_APP_MSEXCEL "rdrichvalue+xml");
|
||||
|
||||
lxw_ct_add_override(self, "/xl/richData/rdrichvaluestructure.xml",
|
||||
LXW_APP_MSEXCEL "rdrichvaluestructure+xml");
|
||||
|
||||
lxw_ct_add_override(self, "/xl/richData/richValueRel.xml",
|
||||
LXW_APP_MSEXCEL "richvaluerel+xml");
|
||||
|
||||
}
|
||||
|
193
src/metadata.c
193
src/metadata.c
@ -77,10 +77,17 @@ _metadata_write_metadata(lxw_metadata *self)
|
||||
"spreadsheetml/2006/main";
|
||||
char xmlns_xda[] = "http://schemas.microsoft.com/office/"
|
||||
"spreadsheetml/2017/dynamicarray";
|
||||
char xmlns_xlrd[] = "http://schemas.microsoft.com/office/"
|
||||
"spreadsheetml/2017/richdata";
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns:xda", xmlns_xda);
|
||||
|
||||
if (self->has_embedded_images)
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns:xlrd", xmlns_xlrd);
|
||||
|
||||
if (self->has_dynamic_functions)
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns:xda", xmlns_xda);
|
||||
|
||||
lxw_xml_start_tag(self->file, "metadata", &attributes);
|
||||
|
||||
@ -88,10 +95,10 @@ _metadata_write_metadata(lxw_metadata *self)
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <metadataType> element.
|
||||
* Write the <metadataType> element for dynamic functions.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_metadata_type(lxw_metadata *self)
|
||||
_metadata_write_cell_metadata_type(lxw_metadata *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
@ -116,6 +123,34 @@ _metadata_write_metadata_type(lxw_metadata *self)
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <metadataType> element for embedded images.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_value_metadata_type(lxw_metadata *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("name", "XLRICHVALUE");
|
||||
LXW_PUSH_ATTRIBUTES_INT("minSupportedVersion", 120000);
|
||||
LXW_PUSH_ATTRIBUTES_INT("copy", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("pasteAll", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("pasteValues", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("merge", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("splitFirst", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("rowColShift", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("clearFormats", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("clearComments", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("assign", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("coerce", 1);
|
||||
|
||||
lxw_xml_empty_tag(self->file, "metadataType", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <metadataTypes> element.
|
||||
*/
|
||||
@ -124,14 +159,24 @@ _metadata_write_metadata_types(lxw_metadata *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
uint8_t count = 0;
|
||||
|
||||
if (self->has_dynamic_functions)
|
||||
count++;
|
||||
|
||||
if (self->has_embedded_images)
|
||||
count++;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_INT("count", 1);
|
||||
LXW_PUSH_ATTRIBUTES_INT("count", count);
|
||||
|
||||
lxw_xml_start_tag(self->file, "metadataTypes", &attributes);
|
||||
|
||||
/* Write the metadataType element. */
|
||||
_metadata_write_metadata_type(self);
|
||||
if (self->has_dynamic_functions)
|
||||
_metadata_write_cell_metadata_type(self);
|
||||
if (self->has_embedded_images)
|
||||
_metadata_write_value_metadata_type(self);
|
||||
|
||||
lxw_xml_end_tag(self->file, "metadataTypes");
|
||||
|
||||
@ -157,10 +202,10 @@ _metadata_write_xda_dynamic_array_properties(lxw_metadata *self)
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <ext> element.
|
||||
* Write the <ext> element for dynamic functions.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_ext(lxw_metadata *self)
|
||||
_metadata_write_cell_ext(lxw_metadata *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
@ -179,10 +224,49 @@ _metadata_write_ext(lxw_metadata *self)
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <futureMetadata> element.
|
||||
* Write the <xlrd:rvb> element.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_future_metadata(lxw_metadata *self)
|
||||
_metadata_write_xlrd_rvb(lxw_metadata *self, uint32_t index)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_INT("i", index);
|
||||
|
||||
lxw_xml_empty_tag(self->file, "xlrd:rvb", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <ext> element for embedded images.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_value_ext(lxw_metadata *self, uint32_t index)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("uri", "{3e2802c4-a4d2-4d8b-9148-e3be6c30e623}");
|
||||
|
||||
lxw_xml_start_tag(self->file, "ext", &attributes);
|
||||
|
||||
/* Write the xlrd:rvb element. */
|
||||
_metadata_write_xlrd_rvb(self, index);
|
||||
|
||||
lxw_xml_end_tag(self->file, "ext");
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <futureMetadata> element for dynamic functions.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_cell_future_metadata(lxw_metadata *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
@ -194,14 +278,12 @@ _metadata_write_future_metadata(lxw_metadata *self)
|
||||
lxw_xml_start_tag(self->file, "futureMetadata", &attributes);
|
||||
|
||||
lxw_xml_start_tag(self->file, "bk", NULL);
|
||||
|
||||
lxw_xml_start_tag(self->file, "extLst", NULL);
|
||||
|
||||
/* Write the ext element. */
|
||||
_metadata_write_ext(self);
|
||||
_metadata_write_cell_ext(self);
|
||||
|
||||
lxw_xml_end_tag(self->file, "extLst");
|
||||
|
||||
lxw_xml_end_tag(self->file, "bk");
|
||||
|
||||
lxw_xml_end_tag(self->file, "futureMetadata");
|
||||
@ -209,18 +291,52 @@ _metadata_write_future_metadata(lxw_metadata *self)
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <futureMetadata> element for embedded images.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_value_future_metadata(lxw_metadata *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
uint32_t i;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("name", "XLRICHVALUE");
|
||||
LXW_PUSH_ATTRIBUTES_INT("count", self->num_embedded_images);
|
||||
|
||||
lxw_xml_start_tag(self->file, "futureMetadata", &attributes);
|
||||
|
||||
for (i = 0; i < self->num_embedded_images; i++) {
|
||||
lxw_xml_start_tag(self->file, "bk", NULL);
|
||||
|
||||
lxw_xml_start_tag(self->file, "extLst", NULL);
|
||||
|
||||
/* Write the ext element. */
|
||||
_metadata_write_value_ext(self, i);
|
||||
|
||||
lxw_xml_end_tag(self->file, "extLst");
|
||||
lxw_xml_end_tag(self->file, "bk");
|
||||
|
||||
}
|
||||
|
||||
lxw_xml_end_tag(self->file, "futureMetadata");
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <rc> element.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_rc(lxw_metadata *self)
|
||||
_metadata_write_rc(lxw_metadata *self, uint8_t type, uint32_t index)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("t", "1");
|
||||
LXW_PUSH_ATTRIBUTES_STR("v", "0");
|
||||
LXW_PUSH_ATTRIBUTES_INT("t", type);
|
||||
LXW_PUSH_ATTRIBUTES_INT("v", index);
|
||||
|
||||
lxw_xml_empty_tag(self->file, "rc", &attributes);
|
||||
|
||||
@ -228,7 +344,7 @@ _metadata_write_rc(lxw_metadata *self)
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <cellMetadata> element.
|
||||
* Write the <cellMetadata> element for dynamic functions.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_cell_metadata(lxw_metadata *self)
|
||||
@ -244,7 +360,7 @@ _metadata_write_cell_metadata(lxw_metadata *self)
|
||||
lxw_xml_start_tag(self->file, "bk", NULL);
|
||||
|
||||
/* Write the rc element. */
|
||||
_metadata_write_rc(self);
|
||||
_metadata_write_rc(self, 1, 0);
|
||||
|
||||
lxw_xml_end_tag(self->file, "bk");
|
||||
|
||||
@ -253,6 +369,39 @@ _metadata_write_cell_metadata(lxw_metadata *self)
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <cellMetadata> element for embedded images.
|
||||
*/
|
||||
STATIC void
|
||||
_metadata_write_value_metadata(lxw_metadata *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
uint8_t type = 1;
|
||||
uint32_t i;
|
||||
|
||||
if (self->has_dynamic_functions)
|
||||
type = 2;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_INT("count", self->num_embedded_images);
|
||||
|
||||
lxw_xml_start_tag(self->file, "valueMetadata", &attributes);
|
||||
|
||||
for (i = 0; i < self->num_embedded_images; i++) {
|
||||
lxw_xml_start_tag(self->file, "bk", NULL);
|
||||
|
||||
/* Write the rc element. */
|
||||
_metadata_write_rc(self, type, i);
|
||||
|
||||
lxw_xml_end_tag(self->file, "bk");
|
||||
}
|
||||
|
||||
lxw_xml_end_tag(self->file, "valueMetadata");
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML file assembly functions.
|
||||
@ -275,10 +424,16 @@ lxw_metadata_assemble_xml_file(lxw_metadata *self)
|
||||
_metadata_write_metadata_types(self);
|
||||
|
||||
/* Write the futureMetadata element. */
|
||||
_metadata_write_future_metadata(self);
|
||||
if (self->has_dynamic_functions)
|
||||
_metadata_write_cell_future_metadata(self);
|
||||
if (self->has_embedded_images)
|
||||
_metadata_write_value_future_metadata(self);
|
||||
|
||||
/* Write the cellMetadata element. */
|
||||
_metadata_write_cell_metadata(self);
|
||||
if (self->has_dynamic_functions)
|
||||
_metadata_write_cell_metadata(self);
|
||||
if (self->has_embedded_images)
|
||||
_metadata_write_value_metadata(self);
|
||||
|
||||
lxw_xml_end_tag(self->file, "metadata");
|
||||
}
|
||||
|
300
src/packager.c
300
src/packager.c
@ -383,9 +383,43 @@ _write_image_files(lxw_packager *self)
|
||||
else
|
||||
worksheet = sheet->u.worksheet;
|
||||
|
||||
if (STAILQ_EMPTY(worksheet->image_props))
|
||||
if (STAILQ_EMPTY(worksheet->image_props)
|
||||
&& STAILQ_EMPTY(worksheet->embedded_image_props))
|
||||
continue;
|
||||
|
||||
STAILQ_FOREACH(object_props, worksheet->embedded_image_props,
|
||||
list_pointers) {
|
||||
|
||||
if (object_props->is_duplicate)
|
||||
continue;
|
||||
|
||||
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
||||
"xl/media/image%d.%s", index++,
|
||||
object_props->extension);
|
||||
|
||||
if (!object_props->is_image_buffer) {
|
||||
/* Check that the image file exists and can be opened. */
|
||||
image_stream = lxw_fopen(object_props->filename, "rb");
|
||||
if (!image_stream) {
|
||||
LXW_WARN_FORMAT1("Error adding image to xlsx file: file "
|
||||
"doesn't exist or can't be opened: %s.",
|
||||
object_props->filename);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
}
|
||||
|
||||
err = _add_file_to_zip(self, image_stream, filename);
|
||||
fclose(image_stream);
|
||||
}
|
||||
else {
|
||||
err = _add_buffer_to_zip(self,
|
||||
object_props->image_buffer,
|
||||
object_props->image_buffer_size,
|
||||
filename);
|
||||
}
|
||||
|
||||
RETURN_ON_ERROR(err);
|
||||
}
|
||||
|
||||
STAILQ_FOREACH(object_props, worksheet->image_props, list_pointers) {
|
||||
|
||||
if (object_props->is_duplicate)
|
||||
@ -1053,6 +1087,10 @@ _write_metadata_file(lxw_packager *self)
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
metadata->has_embedded_images = self->workbook->has_embedded_images;
|
||||
metadata->num_embedded_images = self->workbook->num_embedded_images;
|
||||
metadata->has_dynamic_functions = self->workbook->has_dynamic_functions;
|
||||
|
||||
lxw_metadata_assemble_xml_file(metadata);
|
||||
|
||||
err = _add_to_zip(self, metadata->file, &buffer, &buffer_size,
|
||||
@ -1067,6 +1105,176 @@ mem_error:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the rdrichvalue.xml file.
|
||||
*/
|
||||
STATIC lxw_error
|
||||
_write_rich_value_file(lxw_packager *self)
|
||||
{
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
lxw_rich_value *rich_value;
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
|
||||
if (!self->workbook->has_embedded_images)
|
||||
return LXW_NO_ERROR;
|
||||
|
||||
rich_value = lxw_rich_value_new();
|
||||
rich_value->workbook = self->workbook;
|
||||
|
||||
if (!rich_value) {
|
||||
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
rich_value->file =
|
||||
lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
|
||||
if (!rich_value->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
lxw_rich_value_assemble_xml_file(rich_value);
|
||||
|
||||
err = _add_to_zip(self, rich_value->file, &buffer, &buffer_size,
|
||||
"xl/richData/rdrichvalue.xml");
|
||||
|
||||
fclose(rich_value->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_rich_value_free(rich_value);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the richValueRel.xml file.
|
||||
*/
|
||||
STATIC lxw_error
|
||||
_write_rich_value_rel_file(lxw_packager *self)
|
||||
{
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
lxw_rich_value_rel *rich_value_rel;
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
|
||||
if (!self->workbook->has_embedded_images)
|
||||
return LXW_NO_ERROR;
|
||||
|
||||
rich_value_rel = lxw_rich_value_rel_new();
|
||||
rich_value_rel->num_embedded_images = self->workbook->num_embedded_images;
|
||||
|
||||
if (!rich_value_rel) {
|
||||
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
rich_value_rel->file =
|
||||
lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
|
||||
if (!rich_value_rel->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
lxw_rich_value_rel_assemble_xml_file(rich_value_rel);
|
||||
|
||||
err = _add_to_zip(self, rich_value_rel->file, &buffer, &buffer_size,
|
||||
"xl/richData/richValueRel.xml");
|
||||
|
||||
fclose(rich_value_rel->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_rich_value_rel_free(rich_value_rel);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the rdRichValueTypes.xml file.
|
||||
*/
|
||||
STATIC lxw_error
|
||||
_write_rich_value_types_file(lxw_packager *self)
|
||||
{
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
lxw_rich_value_types *rich_value_types;
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
|
||||
if (!self->workbook->has_embedded_images)
|
||||
return LXW_NO_ERROR;
|
||||
|
||||
rich_value_types = lxw_rich_value_types_new();
|
||||
|
||||
if (!rich_value_types) {
|
||||
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
rich_value_types->file =
|
||||
lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
|
||||
if (!rich_value_types->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
lxw_rich_value_types_assemble_xml_file(rich_value_types);
|
||||
|
||||
err = _add_to_zip(self, rich_value_types->file, &buffer, &buffer_size,
|
||||
"xl/richData/rdRichValueTypes.xml");
|
||||
|
||||
fclose(rich_value_types->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_rich_value_types_free(rich_value_types);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the rdrichvaluestructure.xml file.
|
||||
*/
|
||||
STATIC lxw_error
|
||||
_write_rich_value_structure_file(lxw_packager *self)
|
||||
{
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
lxw_rich_value_structure *rich_value_structure;
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
|
||||
if (!self->workbook->has_embedded_images)
|
||||
return LXW_NO_ERROR;
|
||||
|
||||
rich_value_structure = lxw_rich_value_structure_new();
|
||||
|
||||
if (!rich_value_structure) {
|
||||
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
rich_value_structure->file =
|
||||
lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
|
||||
if (!rich_value_structure->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
lxw_rich_value_structure_assemble_xml_file(rich_value_structure);
|
||||
|
||||
err = _add_to_zip(self, rich_value_structure->file, &buffer, &buffer_size,
|
||||
"xl/richData/rdrichvaluestructure.xml");
|
||||
|
||||
fclose(rich_value_structure->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_rich_value_structure_free(rich_value_structure);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the custom.xml file.
|
||||
*/
|
||||
@ -1327,6 +1535,9 @@ _write_content_types_file(lxw_packager *self)
|
||||
if (workbook->has_metadata)
|
||||
lxw_ct_add_metadata(content_types);
|
||||
|
||||
if (workbook->has_embedded_images)
|
||||
lxw_ct_add_rich_value(content_types);
|
||||
|
||||
lxw_content_types_assemble_xml_file(content_types);
|
||||
|
||||
err = _add_to_zip(self, content_types->file, &buffer, &buffer_size,
|
||||
@ -1397,6 +1608,9 @@ _write_workbook_rels_file(lxw_packager *self)
|
||||
if (workbook->has_metadata)
|
||||
lxw_add_document_relationship(rels, "/sheetMetadata", "metadata.xml");
|
||||
|
||||
if (workbook->has_embedded_images)
|
||||
lxw_add_rich_value_relationship(rels);
|
||||
|
||||
lxw_relationships_assemble_xml_file(rels);
|
||||
|
||||
err = _add_to_zip(self, rels->file, &buffer, &buffer_size,
|
||||
@ -1715,6 +1929,75 @@ mem_error:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the richValueRel.xml.rels files for embedded images.
|
||||
*/
|
||||
STATIC lxw_error
|
||||
_write_rich_value_rels_file(lxw_packager *self)
|
||||
{
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_sheet *sheet;
|
||||
lxw_worksheet *worksheet;
|
||||
lxw_object_properties *object_props;
|
||||
|
||||
lxw_relationships *rels;
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
|
||||
char target[LXW_FILENAME_LENGTH] = { 0 };
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
uint32_t index = 1;
|
||||
|
||||
if (!workbook->has_embedded_images)
|
||||
return LXW_NO_ERROR;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
|
||||
if (sheet->is_chartsheet)
|
||||
continue;
|
||||
else
|
||||
worksheet = sheet->u.worksheet;
|
||||
|
||||
if (STAILQ_EMPTY(worksheet->embedded_image_props))
|
||||
continue;
|
||||
|
||||
STAILQ_FOREACH(object_props, worksheet->embedded_image_props,
|
||||
list_pointers) {
|
||||
|
||||
if (object_props->is_duplicate)
|
||||
continue;
|
||||
|
||||
lxw_snprintf(target, LXW_FILENAME_LENGTH,
|
||||
"../media/image%d.%s", index++,
|
||||
object_props->extension);
|
||||
|
||||
lxw_add_document_relationship(rels, "/image", target);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
|
||||
"xl/richData/_rels/richValueRel.xml.rels");
|
||||
|
||||
lxw_relationships_assemble_xml_file(rels);
|
||||
|
||||
err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
|
||||
|
||||
fclose(rels->file);
|
||||
free(buffer);
|
||||
lxw_free_relationships(rels);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the _rels/.rels xml file.
|
||||
*/
|
||||
@ -1954,6 +2237,21 @@ lxw_create_package(lxw_packager *self)
|
||||
error = _write_metadata_file(self);
|
||||
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
|
||||
|
||||
error = _write_rich_value_file(self);
|
||||
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
|
||||
|
||||
error = _write_rich_value_rel_file(self);
|
||||
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
|
||||
|
||||
error = _write_rich_value_types_file(self);
|
||||
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
|
||||
|
||||
error = _write_rich_value_structure_file(self);
|
||||
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
|
||||
|
||||
error = _write_rich_value_rels_file(self);
|
||||
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
|
||||
|
||||
error = _write_app_file(self);
|
||||
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
|
||||
|
||||
|
@ -244,3 +244,26 @@ lxw_add_worksheet_relationship(lxw_relationships *self, const char *type,
|
||||
{
|
||||
_add_relationship(self, LXW_SCHEMA_DOCUMENT, type, target, target_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a richValue relationship to sheet .rels xml files.
|
||||
*/
|
||||
void
|
||||
lxw_add_rich_value_relationship(lxw_relationships *self)
|
||||
{
|
||||
_add_relationship(self,
|
||||
"http://schemas.microsoft.com/office/2022/10/relationships/",
|
||||
"richValueRel", "richData/richValueRel.xml", NULL);
|
||||
_add_relationship(self,
|
||||
"http://schemas.microsoft.com/office/2017/06/relationships/",
|
||||
"rdRichValue", "richData/rdrichvalue.xml", NULL);
|
||||
_add_relationship(self,
|
||||
"http://schemas.microsoft.com/office/2017/06/relationships/",
|
||||
"rdRichValueStructure",
|
||||
"richData/rdrichvaluestructure.xml", NULL);
|
||||
_add_relationship(self,
|
||||
"http://schemas.microsoft.com/office/2017/06/relationships/",
|
||||
"rdRichValueTypes", "richData/rdRichValueTypes.xml",
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
190
src/rich_value.c
Normal file
190
src/rich_value.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*****************************************************************************
|
||||
* rich_value - A library for creating Excel XLSX rich_value files.
|
||||
*
|
||||
* Used in conjunction with the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter/xmlwriter.h"
|
||||
#include "xlsxwriter/rich_value.h"
|
||||
#include "xlsxwriter/utility.h"
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Create a new rich_value object.
|
||||
*/
|
||||
lxw_rich_value *
|
||||
lxw_rich_value_new(void)
|
||||
{
|
||||
lxw_rich_value *rich_value = calloc(1, sizeof(lxw_rich_value));
|
||||
GOTO_LABEL_ON_MEM_ERROR(rich_value, mem_error);
|
||||
|
||||
return rich_value;
|
||||
|
||||
mem_error:
|
||||
lxw_rich_value_free(rich_value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a rich_value object.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_free(lxw_rich_value *rich_value)
|
||||
{
|
||||
if (!rich_value)
|
||||
return;
|
||||
|
||||
free(rich_value);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Write the XML declaration.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_xml_declaration(lxw_rich_value *self)
|
||||
{
|
||||
lxw_xml_declaration(self->file);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML file assembly functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Write the <v> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_write_v(lxw_rich_value *self, char *value)
|
||||
{
|
||||
lxw_xml_data_element(self->file, "v", value, NULL);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <rv> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_write_rv(lxw_rich_value *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("s", "0");
|
||||
|
||||
lxw_xml_start_tag(self->file, "rv", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the metadata for each embedded image.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_write_images(lxw_rich_value *self)
|
||||
{
|
||||
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_sheet *sheet;
|
||||
lxw_worksheet *worksheet;
|
||||
lxw_object_properties *object_props;
|
||||
char value[LXW_UINT32_T_LENGTH];
|
||||
uint32_t index = 0;
|
||||
uint8_t type = 5;
|
||||
|
||||
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
|
||||
if (sheet->is_chartsheet)
|
||||
continue;
|
||||
else
|
||||
worksheet = sheet->u.worksheet;
|
||||
|
||||
STAILQ_FOREACH(object_props, worksheet->embedded_image_props,
|
||||
list_pointers) {
|
||||
|
||||
if (object_props->is_duplicate)
|
||||
continue;
|
||||
|
||||
if (object_props->decorative)
|
||||
type = 6;
|
||||
|
||||
/* Write the rv element. */
|
||||
_rich_value_write_rv(self);
|
||||
|
||||
/* Write the v element. */
|
||||
lxw_snprintf(value, LXW_UINT32_T_LENGTH, "%u", index);
|
||||
_rich_value_write_v(self, value);
|
||||
|
||||
lxw_snprintf(value, LXW_UINT32_T_LENGTH, "%u", type);
|
||||
_rich_value_write_v(self, value);
|
||||
|
||||
lxw_xml_end_tag(self->file, "rv");
|
||||
|
||||
index++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <rvData> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_write_rv_data(lxw_rich_value *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
char xmlns[] =
|
||||
"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata";
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
|
||||
LXW_PUSH_ATTRIBUTES_INT("count", self->workbook->num_embedded_images);
|
||||
|
||||
lxw_xml_start_tag(self->file, "rvData", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Assemble and write the XML file.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_assemble_xml_file(lxw_rich_value *self)
|
||||
{
|
||||
/* Write the XML declaration. */
|
||||
_rich_value_xml_declaration(self);
|
||||
|
||||
/* Write the rvData element. */
|
||||
_rich_value_write_rv_data(self);
|
||||
|
||||
lxw_rich_value_write_images(self);
|
||||
|
||||
lxw_xml_end_tag(self->file, "rvData");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Public functions.
|
||||
*
|
||||
****************************************************************************/
|
142
src/rich_value_rel.c
Normal file
142
src/rich_value_rel.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*****************************************************************************
|
||||
* rich_value_rel - A library for creating Excel XLSX rich_value_rel files.
|
||||
*
|
||||
* Used in conjunction with the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter/xmlwriter.h"
|
||||
#include "xlsxwriter/rich_value_rel.h"
|
||||
#include "xlsxwriter/utility.h"
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Create a new rich_value_rel object.
|
||||
*/
|
||||
lxw_rich_value_rel *
|
||||
lxw_rich_value_rel_new(void)
|
||||
{
|
||||
lxw_rich_value_rel *rich_value_rel =
|
||||
calloc(1, sizeof(lxw_rich_value_rel));
|
||||
GOTO_LABEL_ON_MEM_ERROR(rich_value_rel, mem_error);
|
||||
|
||||
return rich_value_rel;
|
||||
|
||||
mem_error:
|
||||
lxw_rich_value_rel_free(rich_value_rel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a rich_value_rel object.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_rel_free(lxw_rich_value_rel *rich_value_rel)
|
||||
{
|
||||
if (!rich_value_rel)
|
||||
return;
|
||||
|
||||
free(rich_value_rel);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Write the XML declaration.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_rel_xml_declaration(lxw_rich_value_rel *self)
|
||||
{
|
||||
lxw_xml_declaration(self->file);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML file assembly functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Write the <rel> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_rel_write_rel(lxw_rich_value_rel *self, uint32_t rel_index)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
|
||||
|
||||
lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", rel_index);
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("r:id", r_id);
|
||||
|
||||
lxw_xml_empty_tag(self->file, "rel", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <richValueRels> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_rel_write_rich_value_rels(lxw_rich_value_rel *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
char xmlns[] =
|
||||
"http://schemas.microsoft.com/office/spreadsheetml/2022/richvaluerel";
|
||||
char xmlns_r[] =
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns:r", xmlns_r);
|
||||
|
||||
lxw_xml_start_tag(self->file, "richValueRels", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Assemble and write the XML file.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_rel_assemble_xml_file(lxw_rich_value_rel *self)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/* Write the XML declaration. */
|
||||
_rich_value_rel_xml_declaration(self);
|
||||
|
||||
/* Write the richValueRels element. */
|
||||
_rich_value_rel_write_rich_value_rels(self);
|
||||
|
||||
for (i = 1; i <= self->num_embedded_images; i++) {
|
||||
/* Write the rel element. */
|
||||
_rich_value_rel_write_rel(self, i);
|
||||
}
|
||||
|
||||
lxw_xml_end_tag(self->file, "richValueRels");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Public functions.
|
||||
*
|
||||
****************************************************************************/
|
176
src/rich_value_structure.c
Normal file
176
src/rich_value_structure.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*****************************************************************************
|
||||
* rich_value_structure - A library for creating Excel XLSX rich_value_structure files.
|
||||
*
|
||||
* Used in conjunction with the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter/xmlwriter.h"
|
||||
#include "xlsxwriter/rich_value_structure.h"
|
||||
#include "xlsxwriter/utility.h"
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Create a new rich_value_structure object.
|
||||
*/
|
||||
lxw_rich_value_structure *
|
||||
lxw_rich_value_structure_new(void)
|
||||
{
|
||||
lxw_rich_value_structure *rich_value_structure =
|
||||
calloc(1, sizeof(lxw_rich_value_structure));
|
||||
GOTO_LABEL_ON_MEM_ERROR(rich_value_structure, mem_error);
|
||||
|
||||
return rich_value_structure;
|
||||
|
||||
mem_error:
|
||||
lxw_rich_value_structure_free(rich_value_structure);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a rich_value_structure object.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_structure_free(lxw_rich_value_structure *rich_value_structure)
|
||||
{
|
||||
if (!rich_value_structure)
|
||||
return;
|
||||
|
||||
free(rich_value_structure);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Write the XML declaration.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_structure_xml_declaration(lxw_rich_value_structure *self)
|
||||
{
|
||||
lxw_xml_declaration(self->file);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML file assembly functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Write the <k> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_structure_write_k2(lxw_rich_value_structure *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("n", "CalcOrigin");
|
||||
LXW_PUSH_ATTRIBUTES_STR("t", "i");
|
||||
|
||||
lxw_xml_empty_tag(self->file, "k", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <k> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_structure_write_k1(lxw_rich_value_structure *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("n", "_rvRel:LocalImageIdentifier");
|
||||
LXW_PUSH_ATTRIBUTES_STR("t", "i");
|
||||
|
||||
lxw_xml_empty_tag(self->file, "k", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <s> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_structure_write_s(lxw_rich_value_structure *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("t", "_localImage");
|
||||
|
||||
lxw_xml_start_tag(self->file, "s", &attributes);
|
||||
|
||||
/* Write the k element. */
|
||||
_rich_value_structure_write_k1(self);
|
||||
_rich_value_structure_write_k2(self);
|
||||
|
||||
lxw_xml_end_tag(self->file, "s");
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <rvStructures> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_structure_write_rv_structures(lxw_rich_value_structure *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
char xmlns[] =
|
||||
"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata";
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
|
||||
LXW_PUSH_ATTRIBUTES_STR("count", "1");
|
||||
|
||||
lxw_xml_start_tag(self->file, "rvStructures", &attributes);
|
||||
|
||||
/* Write the s element. */
|
||||
_rich_value_structure_write_s(self);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Assemble and write the XML file.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_structure_assemble_xml_file(lxw_rich_value_structure *self)
|
||||
{
|
||||
/* Write the XML declaration. */
|
||||
_rich_value_structure_xml_declaration(self);
|
||||
|
||||
/* Write the rvStructures element. */
|
||||
_rich_value_structure_write_rv_structures(self);
|
||||
|
||||
lxw_xml_end_tag(self->file, "rvStructures");
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Public functions.
|
||||
*
|
||||
****************************************************************************/
|
199
src/rich_value_types.c
Normal file
199
src/rich_value_types.c
Normal file
@ -0,0 +1,199 @@
|
||||
/*****************************************************************************
|
||||
* rich_value_types - A library for creating Excel XLSX rich_value_types files.
|
||||
*
|
||||
* Used in conjunction with the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter/xmlwriter.h"
|
||||
#include "xlsxwriter/rich_value_types.h"
|
||||
#include "xlsxwriter/utility.h"
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Create a new rich_value_types object.
|
||||
*/
|
||||
lxw_rich_value_types *
|
||||
lxw_rich_value_types_new(void)
|
||||
{
|
||||
lxw_rich_value_types *rich_value_types =
|
||||
calloc(1, sizeof(lxw_rich_value_types));
|
||||
GOTO_LABEL_ON_MEM_ERROR(rich_value_types, mem_error);
|
||||
|
||||
return rich_value_types;
|
||||
|
||||
mem_error:
|
||||
lxw_rich_value_types_free(rich_value_types);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a rich_value_types object.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_types_free(lxw_rich_value_types *rich_value_types)
|
||||
{
|
||||
if (!rich_value_types)
|
||||
return;
|
||||
|
||||
free(rich_value_types);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Write the XML declaration.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_types_xml_declaration(lxw_rich_value_types *self)
|
||||
{
|
||||
lxw_xml_declaration(self->file);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XML file assembly functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Write the <rvTypesInfo> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_types_write_rv_types_info(lxw_rich_value_types *self)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
char xmlns[] =
|
||||
"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2";
|
||||
char xmlns_mc[] =
|
||||
"http://schemas.openxmlformats.org/markup-compatibility/2006";
|
||||
char xmlns_x[] =
|
||||
"http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
||||
char mc_ignorable[] = "x";
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns:mc", xmlns_mc);
|
||||
LXW_PUSH_ATTRIBUTES_STR("mc:Ignorable", mc_ignorable);
|
||||
LXW_PUSH_ATTRIBUTES_STR("xmlns:x", xmlns_x);
|
||||
|
||||
lxw_xml_start_tag(self->file, "rvTypesInfo", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <flag> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_types_write_flag(lxw_rich_value_types *self, char *name)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("name", name);
|
||||
LXW_PUSH_ATTRIBUTES_STR("value", "1");
|
||||
|
||||
lxw_xml_empty_tag(self->file, "flag", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <key> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_types_write_key(lxw_rich_value_types *self, char *name)
|
||||
{
|
||||
struct xml_attribute_list attributes;
|
||||
struct xml_attribute *attribute;
|
||||
|
||||
LXW_INIT_ATTRIBUTES();
|
||||
LXW_PUSH_ATTRIBUTES_STR("name", name);
|
||||
|
||||
lxw_xml_start_tag(self->file, "key", &attributes);
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the <keyFlags> element.
|
||||
*/
|
||||
STATIC void
|
||||
_rich_value_types_write_key_flags(lxw_rich_value_types *self)
|
||||
{
|
||||
int i;
|
||||
char *key_flags[10][3] = {
|
||||
{"_Self", "ExcludeFromFile", "ExcludeFromCalcComparison"},
|
||||
{"_DisplayString", "ExcludeFromCalcComparison", ""},
|
||||
{"_Flags", "ExcludeFromCalcComparison", ""},
|
||||
{"_Format", "ExcludeFromCalcComparison", ""},
|
||||
{"_SubLabel", "ExcludeFromCalcComparison", ""},
|
||||
{"_Attribution", "ExcludeFromCalcComparison", ""},
|
||||
{"_Icon", "ExcludeFromCalcComparison", ""},
|
||||
{"_Display", "ExcludeFromCalcComparison", ""},
|
||||
{"_CanonicalPropertyNames", "ExcludeFromCalcComparison", ""},
|
||||
{"_ClassificationId", "ExcludeFromCalcComparison", ""},
|
||||
};
|
||||
|
||||
lxw_xml_start_tag(self->file, "global", NULL);
|
||||
lxw_xml_start_tag(self->file, "keyFlags", NULL);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
char **flags = key_flags[i];
|
||||
|
||||
_rich_value_types_write_key(self, flags[0]);
|
||||
_rich_value_types_write_flag(self, flags[1]);
|
||||
|
||||
if (*flags[2]) {
|
||||
_rich_value_types_write_flag(self, flags[2]);
|
||||
|
||||
}
|
||||
|
||||
lxw_xml_end_tag(self->file, "key");
|
||||
}
|
||||
|
||||
lxw_xml_end_tag(self->file, "keyFlags");
|
||||
lxw_xml_end_tag(self->file, "global");
|
||||
}
|
||||
|
||||
/*
|
||||
* Assemble and write the XML file.
|
||||
*/
|
||||
void
|
||||
lxw_rich_value_types_assemble_xml_file(lxw_rich_value_types *self)
|
||||
{
|
||||
/* Write the XML declaration. */
|
||||
_rich_value_types_xml_declaration(self);
|
||||
|
||||
/* Write the rvTypesInfo element. */
|
||||
_rich_value_types_write_rv_types_info(self);
|
||||
|
||||
/* Write the keyFlags element. */
|
||||
_rich_value_types_write_key_flags(self);
|
||||
|
||||
lxw_xml_end_tag(self->file, "rvTypesInfo");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Public functions.
|
||||
*
|
||||
****************************************************************************/
|
@ -217,6 +217,7 @@ lxw_workbook_free(lxw_workbook *workbook)
|
||||
free(workbook->chartsheet_names);
|
||||
}
|
||||
|
||||
/* TODO add macro for these RB image frees. */
|
||||
if (workbook->image_md5s) {
|
||||
for (image_md5 = RB_MIN(lxw_image_md5s, workbook->image_md5s);
|
||||
image_md5; image_md5 = next_image_md5) {
|
||||
@ -231,12 +232,30 @@ lxw_workbook_free(lxw_workbook *workbook)
|
||||
free(workbook->image_md5s);
|
||||
}
|
||||
|
||||
if (workbook->embedded_image_md5s) {
|
||||
for (image_md5 =
|
||||
RB_MIN(lxw_image_md5s, workbook->embedded_image_md5s); image_md5;
|
||||
image_md5 = next_image_md5) {
|
||||
|
||||
next_image_md5 =
|
||||
RB_NEXT(lxw_image_md5s, workbook->embedded_image_md5s,
|
||||
image_md5);
|
||||
RB_REMOVE(lxw_image_md5s, workbook->embedded_image_md5s,
|
||||
image_md5);
|
||||
free(image_md5->md5);
|
||||
free(image_md5);
|
||||
}
|
||||
|
||||
free(workbook->embedded_image_md5s);
|
||||
}
|
||||
|
||||
if (workbook->header_image_md5s) {
|
||||
for (image_md5 = RB_MIN(lxw_image_md5s, workbook->header_image_md5s);
|
||||
image_md5; image_md5 = next_image_md5) {
|
||||
|
||||
next_image_md5 =
|
||||
RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
|
||||
RB_NEXT(lxw_image_md5s, workbook->header_image_md5s,
|
||||
image_md5);
|
||||
RB_REMOVE(lxw_image_md5s, workbook->header_image_md5s, image_md5);
|
||||
free(image_md5->md5);
|
||||
free(image_md5);
|
||||
@ -250,7 +269,7 @@ lxw_workbook_free(lxw_workbook *workbook)
|
||||
image_md5; image_md5 = next_image_md5) {
|
||||
|
||||
next_image_md5 =
|
||||
RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
|
||||
RB_NEXT(lxw_image_md5s, workbook->background_md5s, image_md5);
|
||||
RB_REMOVE(lxw_image_md5s, workbook->background_md5s, image_md5);
|
||||
free(image_md5->md5);
|
||||
free(image_md5);
|
||||
@ -1082,6 +1101,7 @@ _prepare_drawings(lxw_workbook *self)
|
||||
}
|
||||
|
||||
if (STAILQ_EMPTY(worksheet->image_props)
|
||||
&& STAILQ_EMPTY(worksheet->embedded_image_props)
|
||||
&& STAILQ_EMPTY(worksheet->chart_data)
|
||||
&& !worksheet->has_header_vml && !worksheet->has_background_image) {
|
||||
continue;
|
||||
@ -1089,6 +1109,44 @@ _prepare_drawings(lxw_workbook *self)
|
||||
|
||||
drawing_id++;
|
||||
|
||||
/* Prepare embedded worksheet images. */
|
||||
STAILQ_FOREACH(object_props, worksheet->embedded_image_props,
|
||||
list_pointers) {
|
||||
|
||||
_store_image_type(self, object_props->image_type);
|
||||
|
||||
/* Check for duplicate images and only store the first instance. */
|
||||
if (object_props->md5) {
|
||||
tmp_image_md5.md5 = object_props->md5;
|
||||
found_duplicate_image = RB_FIND(lxw_image_md5s,
|
||||
self->embedded_image_md5s,
|
||||
&tmp_image_md5);
|
||||
}
|
||||
|
||||
if (found_duplicate_image) {
|
||||
ref_id = found_duplicate_image->id;
|
||||
object_props->is_duplicate = LXW_TRUE;
|
||||
}
|
||||
else {
|
||||
image_ref_id++;
|
||||
ref_id = image_ref_id;
|
||||
self->num_embedded_images++;
|
||||
|
||||
#ifndef USE_NO_MD5
|
||||
new_image_md5 = calloc(1, sizeof(lxw_image_md5));
|
||||
#endif
|
||||
if (new_image_md5 && object_props->md5) {
|
||||
new_image_md5->id = ref_id;
|
||||
new_image_md5->md5 = lxw_strdup(object_props->md5);
|
||||
|
||||
RB_INSERT(lxw_image_md5s, self->embedded_image_md5s,
|
||||
new_image_md5);
|
||||
}
|
||||
}
|
||||
|
||||
worksheet_set_error_cell(worksheet, object_props, ref_id);
|
||||
}
|
||||
|
||||
/* Prepare background images. */
|
||||
if (worksheet->has_background_image) {
|
||||
|
||||
@ -1830,6 +1888,11 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
||||
GOTO_LABEL_ON_MEM_ERROR(workbook->image_md5s, mem_error);
|
||||
RB_INIT(workbook->image_md5s);
|
||||
|
||||
/* Add the embedded image MD5 tree. */
|
||||
workbook->embedded_image_md5s = calloc(1, sizeof(struct lxw_image_md5s));
|
||||
GOTO_LABEL_ON_MEM_ERROR(workbook->embedded_image_md5s, mem_error);
|
||||
RB_INIT(workbook->embedded_image_md5s);
|
||||
|
||||
/* Add the header image MD5 tree. */
|
||||
workbook->header_image_md5s = calloc(1, sizeof(struct lxw_image_md5s));
|
||||
GOTO_LABEL_ON_MEM_ERROR(workbook->header_image_md5s, mem_error);
|
||||
@ -2153,8 +2216,16 @@ workbook_close(lxw_workbook *self)
|
||||
if (worksheet->index == self->active_sheet)
|
||||
worksheet->active = LXW_TRUE;
|
||||
|
||||
if (worksheet->has_dynamic_arrays)
|
||||
if (worksheet->has_dynamic_functions) {
|
||||
self->has_metadata = LXW_TRUE;
|
||||
self->has_dynamic_functions = LXW_TRUE;
|
||||
|
||||
}
|
||||
|
||||
if (!STAILQ_EMPTY(worksheet->embedded_image_props)) {
|
||||
self->has_metadata = LXW_TRUE;
|
||||
self->has_embedded_images = LXW_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set workbook and worksheet VBA codenames if a macro has been added. */
|
||||
|
173
src/worksheet.c
173
src/worksheet.c
@ -142,6 +142,11 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
||||
GOTO_LABEL_ON_MEM_ERROR(worksheet->image_props, mem_error);
|
||||
STAILQ_INIT(worksheet->image_props);
|
||||
|
||||
worksheet->embedded_image_props =
|
||||
calloc(1, sizeof(struct lxw_embedded_image_props));
|
||||
GOTO_LABEL_ON_MEM_ERROR(worksheet->embedded_image_props, mem_error);
|
||||
STAILQ_INIT(worksheet->embedded_image_props);
|
||||
|
||||
worksheet->chart_data = calloc(1, sizeof(struct lxw_chart_props));
|
||||
GOTO_LABEL_ON_MEM_ERROR(worksheet->chart_data, mem_error);
|
||||
STAILQ_INIT(worksheet->chart_data);
|
||||
@ -368,7 +373,8 @@ _free_cell(lxw_cell *cell)
|
||||
return;
|
||||
|
||||
if (cell->type != NUMBER_CELL && cell->type != STRING_CELL
|
||||
&& cell->type != BLANK_CELL && cell->type != BOOLEAN_CELL) {
|
||||
&& cell->type != BLANK_CELL && cell->type != BOOLEAN_CELL
|
||||
&& cell->type != ERROR_CELL) {
|
||||
|
||||
free((void *) cell->u.string);
|
||||
}
|
||||
@ -607,6 +613,17 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
||||
free(worksheet->image_props);
|
||||
}
|
||||
|
||||
if (worksheet->embedded_image_props) {
|
||||
while (!STAILQ_EMPTY(worksheet->embedded_image_props)) {
|
||||
object_props = STAILQ_FIRST(worksheet->embedded_image_props);
|
||||
STAILQ_REMOVE_HEAD(worksheet->embedded_image_props,
|
||||
list_pointers);
|
||||
_free_object_properties(object_props);
|
||||
}
|
||||
|
||||
free(worksheet->embedded_image_props);
|
||||
}
|
||||
|
||||
if (worksheet->chart_data) {
|
||||
while (!STAILQ_EMPTY(worksheet->chart_data)) {
|
||||
object_props = STAILQ_FIRST(worksheet->chart_data);
|
||||
@ -991,6 +1008,25 @@ _new_boolean_cell(lxw_row_t row_num, lxw_col_t col_num, int value,
|
||||
return cell;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new worksheet error cell object.
|
||||
*/
|
||||
STATIC lxw_cell *
|
||||
_new_error_cell(lxw_row_t row_num, lxw_col_t col_num, uint32_t value,
|
||||
lxw_format *format)
|
||||
{
|
||||
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
|
||||
RETURN_ON_MEM_ERROR(cell, cell);
|
||||
|
||||
cell->row_num = row_num;
|
||||
cell->col_num = col_num;
|
||||
cell->type = ERROR_CELL;
|
||||
cell->format = format;
|
||||
cell->u.number = value;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new comment cell object.
|
||||
*/
|
||||
@ -4522,6 +4558,15 @@ _write_boolean_cell(lxw_worksheet *self, lxw_cell *cell)
|
||||
lxw_xml_data_element(self->file, "v", data, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out a error worksheet cell.
|
||||
*/
|
||||
STATIC void
|
||||
_write_error_cell(lxw_worksheet *self)
|
||||
{
|
||||
lxw_xml_data_element(self->file, "v", "#VALUE!", NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the "spans" attribute of the <row> tag. This is an XLSX
|
||||
* optimization and isn't strictly required. However, it makes comparing
|
||||
@ -4652,6 +4697,13 @@ _write_cell(lxw_worksheet *self, lxw_cell *cell, lxw_format *row_format)
|
||||
_write_array_formula_num_cell(self, cell);
|
||||
lxw_xml_end_tag(self->file, "c");
|
||||
}
|
||||
else if (cell->type == ERROR_CELL) {
|
||||
LXW_PUSH_ATTRIBUTES_STR("t", "e");
|
||||
LXW_PUSH_ATTRIBUTES_DBL("vm", cell->u.number);
|
||||
lxw_xml_start_tag(self->file, "c", &attributes);
|
||||
_write_error_cell(self);
|
||||
lxw_xml_end_tag(self->file, "c");
|
||||
}
|
||||
|
||||
LXW_FREE_ATTRIBUTES();
|
||||
}
|
||||
@ -8093,7 +8145,7 @@ _store_array_formula(lxw_worksheet *self,
|
||||
_insert_cell(self, first_row, first_col, cell);
|
||||
|
||||
if (is_dynamic)
|
||||
self->has_dynamic_arrays = LXW_TRUE;
|
||||
self->has_dynamic_functions = LXW_TRUE;
|
||||
|
||||
/* Pad out the rest of the area with formatted zeroes. */
|
||||
if (!self->optimize) {
|
||||
@ -10591,6 +10643,108 @@ worksheet_insert_image_buffer(lxw_worksheet *self,
|
||||
image_buffer, image_size, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Embed an image with options into the worksheet.
|
||||
*/
|
||||
lxw_error
|
||||
worksheet_embed_image_opt(lxw_worksheet *self,
|
||||
lxw_row_t row_num, lxw_col_t col_num,
|
||||
const char *filename,
|
||||
lxw_image_options *user_options)
|
||||
{
|
||||
FILE *image_stream;
|
||||
const char *description;
|
||||
lxw_object_properties *object_props;
|
||||
lxw_error err;
|
||||
|
||||
if (!filename) {
|
||||
LXW_WARN("worksheet_embed_image()/_opt(): "
|
||||
"filename must be specified.");
|
||||
return LXW_ERROR_NULL_PARAMETER_IGNORED;
|
||||
}
|
||||
|
||||
/* Check that the image file exists and can be opened. */
|
||||
image_stream = lxw_fopen(filename, "rb");
|
||||
if (!image_stream) {
|
||||
LXW_WARN_FORMAT1("worksheet_embed_image()/_opt(): "
|
||||
"file doesn't exist or can't be opened: %s.",
|
||||
filename);
|
||||
return LXW_ERROR_PARAMETER_VALIDATION;
|
||||
}
|
||||
|
||||
/* Use the filename as the default description, like Excel. */
|
||||
description = lxw_basename(filename);
|
||||
if (!description) {
|
||||
LXW_WARN_FORMAT1("worksheet_embed_image()/_opt(): "
|
||||
"couldn't get basename for file: %s.", filename);
|
||||
fclose(image_stream);
|
||||
return LXW_ERROR_PARAMETER_VALIDATION;
|
||||
}
|
||||
|
||||
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Create a new object to hold the image properties. */
|
||||
object_props = calloc(1, sizeof(lxw_object_properties));
|
||||
if (!object_props) {
|
||||
fclose(image_stream);
|
||||
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
if (user_options) {
|
||||
object_props->x_offset = user_options->x_offset;
|
||||
object_props->y_offset = user_options->y_offset;
|
||||
object_props->x_scale = user_options->x_scale;
|
||||
object_props->y_scale = user_options->y_scale;
|
||||
object_props->object_position = user_options->object_position;
|
||||
object_props->url = lxw_strdup(user_options->url);
|
||||
object_props->tip = lxw_strdup(user_options->tip);
|
||||
object_props->decorative = user_options->decorative;
|
||||
|
||||
if (user_options->description)
|
||||
description = user_options->description;
|
||||
}
|
||||
|
||||
/* Copy other options or set defaults. */
|
||||
object_props->filename = lxw_strdup(filename);
|
||||
object_props->description = lxw_strdup(description);
|
||||
object_props->stream = image_stream;
|
||||
object_props->row = row_num;
|
||||
object_props->col = col_num;
|
||||
|
||||
if (object_props->x_scale == 0.0)
|
||||
object_props->x_scale = 1;
|
||||
|
||||
if (object_props->y_scale == 0.0)
|
||||
object_props->y_scale = 1;
|
||||
|
||||
if (_get_image_properties(object_props) == LXW_NO_ERROR) {
|
||||
STAILQ_INSERT_TAIL(self->embedded_image_props, object_props,
|
||||
list_pointers);
|
||||
fclose(image_stream);
|
||||
|
||||
return LXW_NO_ERROR;
|
||||
}
|
||||
else {
|
||||
_free_object_properties(object_props);
|
||||
fclose(image_stream);
|
||||
return LXW_ERROR_IMAGE_DIMENSIONS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Embed an image into the worksheet.
|
||||
*/
|
||||
lxw_error
|
||||
worksheet_embed_image(lxw_worksheet *self,
|
||||
lxw_row_t row_num, lxw_col_t col_num,
|
||||
const char *filename)
|
||||
{
|
||||
return worksheet_embed_image_opt(self, row_num, col_num, filename, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set an image as a worksheet background.
|
||||
*/
|
||||
@ -11421,3 +11575,18 @@ worksheet_ignore_errors(lxw_worksheet *self, uint8_t type, const char *range)
|
||||
|
||||
return LXW_NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an error cell for versions of Excel that don't support embedded images.
|
||||
*/
|
||||
void
|
||||
worksheet_set_error_cell(lxw_worksheet *self,
|
||||
lxw_object_properties *object_props, uint32_t ref_id)
|
||||
{
|
||||
lxw_row_t row_num = object_props->row;
|
||||
lxw_col_t col_num = object_props->col;
|
||||
|
||||
lxw_cell *cell = _new_error_cell(row_num, col_num, ref_id, NULL);
|
||||
_insert_cell(self, row_num, col_num, cell);
|
||||
|
||||
}
|
||||
|
21
test/functional/src/test_embed_image01.c
Normal file
21
test/functional/src/test_embed_image01.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image01.xlsx");
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet, CELL("A1"), "images/red.png");
|
||||
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
21
test/functional/src/test_embed_image02.c
Normal file
21
test/functional/src/test_embed_image02.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image02.xlsx");
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet, 0, 0, "images/red.png");
|
||||
worksheet_embed_image(worksheet, 8, 4, "images/red.png");
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
21
test/functional/src/test_embed_image03.c
Normal file
21
test/functional/src/test_embed_image03.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image03.xlsx");
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet, 0, 0, "images/red.png");
|
||||
worksheet_embed_image(worksheet, 8, 4, "images/blue.png");
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
22
test/functional/src/test_embed_image04.c
Normal file
22
test/functional/src/test_embed_image04.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image04.xlsx");
|
||||
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
|
||||
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet1, 0, 0, "images/red.png");
|
||||
worksheet_embed_image(worksheet2, 8, 4, "images/blue.png");
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
22
test/functional/src/test_embed_image05.c
Normal file
22
test/functional/src/test_embed_image05.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image05.xlsx");
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_write_dynamic_array_formula(worksheet, 0, 0, 2, 0, "=LEN(B1:B3)", NULL);
|
||||
|
||||
worksheet_embed_image(worksheet, 8, 4, "images/red.png");
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
21
test/functional/src/test_embed_image06.c
Normal file
21
test/functional/src/test_embed_image06.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image06.xlsx");
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet, 0, 0, "images/red.png");
|
||||
worksheet_insert_image(worksheet, 8, 4, "images/red.png");
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
22
test/functional/src/test_embed_image07.c
Normal file
22
test/functional/src/test_embed_image07.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image07.xlsx");
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet, 0, 0, "images/red.png");
|
||||
worksheet_embed_image(worksheet, 2, 0, "images/blue.png");
|
||||
worksheet_insert_image(worksheet, 8, 4, "images/red.png");
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
23
test/functional/src/test_embed_image11.c
Normal file
23
test/functional/src/test_embed_image11.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image11.xlsx");
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_set_column(worksheet, 0, 0, 11, NULL);
|
||||
worksheet_set_row(worksheet, 0, 72, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet, 0, 0, "images/red.png");
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
34
test/functional/src/test_embed_image13.c
Normal file
34
test/functional/src/test_embed_image13.c
Normal file
@ -0,0 +1,34 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Test to compare output against Excel files.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook *workbook = workbook_new("test_embed_image13.xlsx");
|
||||
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet1, 0, 0, "images/red.png");
|
||||
worksheet_embed_image(worksheet1, 2, 0, "images/blue.png");
|
||||
worksheet_embed_image(worksheet1, 4, 0, "images/yellow.png");
|
||||
|
||||
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet2, 0, 0, "images/yellow.png");
|
||||
worksheet_embed_image(worksheet2, 2, 0, "images/red.png");
|
||||
worksheet_embed_image(worksheet2, 4, 0, "images/blue.png");
|
||||
|
||||
lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_embed_image(worksheet3, 0, 0, "images/blue.png");
|
||||
worksheet_embed_image(worksheet3, 2, 0, "images/yellow.png");
|
||||
worksheet_embed_image(worksheet3, 4, 0, "images/red.png");
|
||||
|
||||
return workbook_close(workbook);
|
||||
}
|
47
test/functional/test_embed_image.py
Normal file
47
test/functional/test_embed_image.py
Normal file
@ -0,0 +1,47 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Tests for libxlsxwriter.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
# Copyright 2014-2024, John McNamara, jmcnamara@cpan.org.
|
||||
#
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import base_test_class
|
||||
|
||||
class TestCompareXLSXFiles(base_test_class.XLSXBaseTest):
|
||||
"""
|
||||
Test file created with libxlsxwriter against a file created by Excel.
|
||||
|
||||
"""
|
||||
|
||||
def test_embed_image01(self):
|
||||
self.run_exe_test('test_embed_image01')
|
||||
|
||||
# Some of the following tests require MD5 hash support to remove duplicate images.
|
||||
@pytest.mark.skipif(os.environ.get('USE_NO_MD5'), reason="compiled without MD5 support")
|
||||
def test_embed_image02(self):
|
||||
self.run_exe_test('test_embed_image02')
|
||||
|
||||
def test_embed_image03(self):
|
||||
self.run_exe_test('test_embed_image03')
|
||||
|
||||
def test_embed_image04(self):
|
||||
self.run_exe_test('test_embed_image04')
|
||||
|
||||
def test_embed_image05(self):
|
||||
self.run_exe_test('test_embed_image05')
|
||||
|
||||
def test_embed_image06(self):
|
||||
self.run_exe_test('test_embed_image06')
|
||||
|
||||
def test_embed_image07(self):
|
||||
self.run_exe_test('test_embed_image07')
|
||||
|
||||
def test_embed_image11(self):
|
||||
self.run_exe_test('test_embed_image11')
|
||||
|
||||
@pytest.mark.skipif(os.environ.get('USE_NO_MD5'), reason="compiled without MD5 support")
|
||||
def test_embed_image13(self):
|
||||
self.run_exe_test('test_embed_image13')
|
BIN
test/functional/xlsx_files/embed_image01.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image01.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/embed_image02.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image02.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/embed_image03.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image03.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/embed_image04.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image04.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/embed_image05.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image05.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/embed_image06.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image06.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/embed_image07.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image07.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/embed_image11.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image11.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/embed_image13.xlsx
Normal file
BIN
test/functional/xlsx_files/embed_image13.xlsx
Normal file
Binary file not shown.
@ -43,6 +43,10 @@ SRCS += $(wildcard vml/test*.c)
|
||||
SRCS += $(wildcard comment/test*.c)
|
||||
SRCS += $(wildcard metadata/test*.c)
|
||||
SRCS += $(wildcard table/test*.c)
|
||||
SRCS += $(wildcard rich_value/test*.c)
|
||||
SRCS += $(wildcard rich_value_rel/test*.c)
|
||||
SRCS += $(wildcard rich_value_types/test*.c)
|
||||
SRCS += $(wildcard rich_value_structure/test*.c)
|
||||
# End of SRCS
|
||||
|
||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
@ -80,6 +84,10 @@ all :
|
||||
$(Q)$(MAKE) -C comment
|
||||
$(Q)$(MAKE) -C metadata
|
||||
$(Q)$(MAKE) -C table
|
||||
$(Q)$(MAKE) -C rich_value
|
||||
$(Q)$(MAKE) -C rich_value_rel
|
||||
$(Q)$(MAKE) -C rich_value_types
|
||||
$(Q)$(MAKE) -C rich_value_structure
|
||||
# END make all
|
||||
|
||||
clean :
|
||||
@ -102,6 +110,10 @@ clean :
|
||||
$(Q)$(MAKE) clean -C comment
|
||||
$(Q)$(MAKE) clean -C metadata
|
||||
$(Q)$(MAKE) clean -C table
|
||||
$(Q)$(MAKE) clean -C rich_value
|
||||
$(Q)$(MAKE) clean -C rich_value_rel
|
||||
$(Q)$(MAKE) clean -C rich_value_types
|
||||
$(Q)$(MAKE) clean -C rich_value_structure
|
||||
# END make clean
|
||||
|
||||
|
||||
|
8
test/unit/rich_value/Makefile
Normal file
8
test/unit/rich_value/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Makefile for libxlsxwriter library.
|
||||
#
|
||||
# Copyright 2014-2015, John McNamara, jmcnamara@cpan.org
|
||||
#
|
||||
|
||||
include ../Makefile.unit
|
15
test/unit/rich_value/main.c
Normal file
15
test/unit/rich_value/main.c
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Test runner for xmlwriter using ctest.
|
||||
*
|
||||
* Copyright 2014-2024 John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
#define CTEST_MAIN
|
||||
|
||||
#include "../ctest.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
return ctest_main(argc, argv);
|
||||
}
|
||||
|
28
test/unit/rich_value/test_rich_value_xml_declaration.c
Normal file
28
test/unit/rich_value/test_rich_value_xml_declaration.c
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Tests for the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ctest.h"
|
||||
#include "../helper.h"
|
||||
|
||||
#include "xlsxwriter/rich_value.h"
|
||||
|
||||
// Test _xml_declaration().
|
||||
CTEST(rich_value, xml_declaration) {
|
||||
|
||||
char* got;
|
||||
char exp[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
||||
FILE* testfile = tmpfile();
|
||||
|
||||
lxw_rich_value *rich_value = lxw_rich_value_new();
|
||||
rich_value->file = testfile;
|
||||
|
||||
_rich_value_xml_declaration(rich_value);
|
||||
|
||||
RUN_XLSX_STREQ(exp, got);
|
||||
|
||||
lxw_rich_value_free(rich_value);
|
||||
}
|
8
test/unit/rich_value_rel/Makefile
Normal file
8
test/unit/rich_value_rel/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Makefile for libxlsxwriter library.
|
||||
#
|
||||
# Copyright 2014-2015, John McNamara, jmcnamara@cpan.org
|
||||
#
|
||||
|
||||
include ../Makefile.unit
|
15
test/unit/rich_value_rel/main.c
Normal file
15
test/unit/rich_value_rel/main.c
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Test runner for xmlwriter using ctest.
|
||||
*
|
||||
* Copyright 2014-2024 John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
#define CTEST_MAIN
|
||||
|
||||
#include "../ctest.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
return ctest_main(argc, argv);
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Tests for the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ctest.h"
|
||||
#include "../helper.h"
|
||||
|
||||
#include "xlsxwriter/rich_value_rel.h"
|
||||
|
||||
// Test _xml_declaration().
|
||||
CTEST(rich_value_rel, xml_declaration) {
|
||||
|
||||
char* got;
|
||||
char exp[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
||||
FILE* testfile = tmpfile();
|
||||
|
||||
lxw_rich_value_rel *rich_value_rel = lxw_rich_value_rel_new();
|
||||
rich_value_rel->file = testfile;
|
||||
|
||||
_rich_value_rel_xml_declaration(rich_value_rel);
|
||||
|
||||
RUN_XLSX_STREQ(exp, got);
|
||||
|
||||
lxw_rich_value_rel_free(rich_value_rel);
|
||||
}
|
8
test/unit/rich_value_structure/Makefile
Normal file
8
test/unit/rich_value_structure/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Makefile for libxlsxwriter library.
|
||||
#
|
||||
# Copyright 2014-2015, John McNamara, jmcnamara@cpan.org
|
||||
#
|
||||
|
||||
include ../Makefile.unit
|
15
test/unit/rich_value_structure/main.c
Normal file
15
test/unit/rich_value_structure/main.c
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Test runner for xmlwriter using ctest.
|
||||
*
|
||||
* Copyright 2014-2024 John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
#define CTEST_MAIN
|
||||
|
||||
#include "../ctest.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
return ctest_main(argc, argv);
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Tests for the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ctest.h"
|
||||
#include "../helper.h"
|
||||
|
||||
#include "xlsxwriter/rich_value_structure.h"
|
||||
|
||||
// Test _xml_declaration().
|
||||
CTEST(rich_value_structure, xml_declaration) {
|
||||
|
||||
char* got;
|
||||
char exp[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
||||
FILE* testfile = tmpfile();
|
||||
|
||||
lxw_rich_value_structure *rich_value_structure = lxw_rich_value_structure_new();
|
||||
rich_value_structure->file = testfile;
|
||||
|
||||
_rich_value_structure_xml_declaration(rich_value_structure);
|
||||
|
||||
RUN_XLSX_STREQ(exp, got);
|
||||
|
||||
lxw_rich_value_structure_free(rich_value_structure);
|
||||
}
|
8
test/unit/rich_value_types/Makefile
Normal file
8
test/unit/rich_value_types/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Makefile for libxlsxwriter library.
|
||||
#
|
||||
# Copyright 2014-2015, John McNamara, jmcnamara@cpan.org
|
||||
#
|
||||
|
||||
include ../Makefile.unit
|
15
test/unit/rich_value_types/main.c
Normal file
15
test/unit/rich_value_types/main.c
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Test runner for xmlwriter using ctest.
|
||||
*
|
||||
* Copyright 2014-2024 John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
#define CTEST_MAIN
|
||||
|
||||
#include "../ctest.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
return ctest_main(argc, argv);
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Tests for the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2024, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ctest.h"
|
||||
#include "../helper.h"
|
||||
|
||||
#include "xlsxwriter/rich_value_types.h"
|
||||
|
||||
// Test _xml_declaration().
|
||||
CTEST(rich_value_types, xml_declaration) {
|
||||
|
||||
char* got;
|
||||
char exp[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
||||
FILE* testfile = tmpfile();
|
||||
|
||||
lxw_rich_value_types *rich_value_types = lxw_rich_value_types_new();
|
||||
rich_value_types->file = testfile;
|
||||
|
||||
_rich_value_types_xml_declaration(rich_value_types);
|
||||
|
||||
RUN_XLSX_STREQ(exp, got);
|
||||
|
||||
lxw_rich_value_types_free(rich_value_types);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user