diff --git a/examples/embed_image_buffer.c b/examples/embed_image_buffer.c new file mode 100644 index 00000000..1fe5623f --- /dev/null +++ b/examples/embed_image_buffer.c @@ -0,0 +1,48 @@ +/* + * An example of embedding an image from a memory buffer into a worksheet + * using the libxlsxwriter library. + * + * Copyright 2014-2024 John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + + +/* Simple array with some PNG data. */ +unsigned char image_buffer[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, + 0x08, 0x02, 0x00, 0x00, 0x00, 0xfc, 0x18, 0xed, 0xa3, 0x00, 0x00, 0x00, + 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, + 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, + 0x61, 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, + 0x7a, 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, + 0x80, 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, + 0x3a, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, + 0x00, 0x46, 0x49, 0x44, 0x41, 0x54, 0x48, 0x4b, 0x63, 0xfc, 0xcf, 0x40, + 0x63, 0x00, 0xb4, 0x80, 0xa6, 0x88, 0xb6, 0xa6, 0x83, 0x82, 0x87, 0xa6, + 0xce, 0x1f, 0xb5, 0x80, 0x98, 0xe0, 0x1d, 0x8d, 0x03, 0x82, 0xa1, 0x34, + 0x1a, 0x44, 0xa3, 0x41, 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, + 0xa3, 0x41, 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, 0xa3, 0x41, + 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, 0x03, 0x1f, 0x44, 0x00, + 0xaa, 0x35, 0xdd, 0x4e, 0xe6, 0xd5, 0xa1, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + +unsigned int image_size = 200; + + +int main() { + + /* Create a new workbook and add a worksheet. */ + lxw_workbook *workbook = workbook_new("embed_image_buffer.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + /* Embed the image from the buffer. */ + worksheet_embed_image_buffer(worksheet, CELL("B3"), image_buffer, image_size); + + workbook_close(workbook); + + return 0; +} diff --git a/include/xlsxwriter/workbook.h b/include/xlsxwriter/workbook.h index f32ad0cf..e6350067 100644 --- a/include/xlsxwriter/workbook.h +++ b/include/xlsxwriter/workbook.h @@ -323,6 +323,7 @@ typedef struct lxw_workbook { uint16_t num_format_count; uint16_t drawing_count; uint16_t comment_count; + uint32_t num_embedded_images; uint16_t font_count; uint16_t border_count; @@ -340,8 +341,7 @@ typedef struct lxw_workbook { uint8_t has_metadata; uint8_t has_embedded_images; uint8_t has_dynamic_functions; - - uint32_t num_embedded_images; + uint8_t has_embedded_image_descriptions; lxw_hash_table *used_xf_formats; lxw_hash_table *used_dxf_formats; diff --git a/include/xlsxwriter/worksheet.h b/include/xlsxwriter/worksheet.h index 9a28b397..793891b6 100644 --- a/include/xlsxwriter/worksheet.h +++ b/include/xlsxwriter/worksheet.h @@ -1738,6 +1738,9 @@ typedef struct lxw_image_options { /** Add an optional mouseover tip for a hyperlink to the image. */ const char *tip; + /** TODO */ + lxw_format *cell_format; + } lxw_image_options; /** @@ -1809,6 +1812,7 @@ typedef struct lxw_object_properties { char *md5; char *image_position; uint8_t decorative; + lxw_format *format; STAILQ_ENTRY (lxw_object_properties) list_pointers; } lxw_object_properties; @@ -2255,6 +2259,7 @@ typedef struct lxw_worksheet { uint8_t has_header_vml; uint8_t has_background_image; uint8_t has_buttons; + uint8_t storing_embedded_image; lxw_rel_tuple *external_vml_comment_link; lxw_rel_tuple *external_comment_link; lxw_rel_tuple *external_vml_header_link; @@ -3814,6 +3819,40 @@ lxw_error worksheet_embed_image_opt(lxw_worksheet *worksheet, const char *filename, lxw_image_options *options); +/** + * @brief TODO + * + * @param worksheet + * @param row + * @param col + * @param image_buffer + * @param image_size + * @return lxw_error + */ +lxw_error worksheet_embed_image_buffer(lxw_worksheet *worksheet, + lxw_row_t row, + lxw_col_t col, + const unsigned char *image_buffer, + size_t image_size); + +/** + * @brief TODO + * + * @param worksheet + * @param row + * @param col + * @param image_buffer + * @param image_size + * @param options + * @return lxw_error + */ +lxw_error 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); + /** * @brief Set the background image for a worksheet. * diff --git a/src/packager.c b/src/packager.c index c455f653..bb0b6ce3 100644 --- a/src/packager.c +++ b/src/packager.c @@ -1120,13 +1120,13 @@ _write_rich_value_file(lxw_packager *self) 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->workbook = self->workbook; + rich_value->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir); if (!rich_value->file) { @@ -1163,13 +1163,13 @@ _write_rich_value_rel_file(lxw_packager *self) 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->num_embedded_images = self->workbook->num_embedded_images; + rich_value_rel->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir); if (!rich_value_rel->file) { @@ -1206,7 +1206,6 @@ _write_rich_value_types_file(lxw_packager *self) 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; @@ -1248,12 +1247,14 @@ _write_rich_value_structure_file(lxw_packager *self) 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->has_embedded_image_descriptions = + self->workbook->has_embedded_image_descriptions; + rich_value_structure->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir); if (!rich_value_structure->file) { diff --git a/src/rich_value.c b/src/rich_value.c index f5476bad..b9da82fd 100644 --- a/src/rich_value.c +++ b/src/rich_value.c @@ -137,13 +137,14 @@ lxw_rich_value_write_images(lxw_rich_value *self) lxw_snprintf(value, LXW_UINT32_T_LENGTH, "%u", type); _rich_value_write_v(self, value); + if (object_props->description && *object_props->description) + _rich_value_write_v(self, object_props->description); + lxw_xml_end_tag(self->file, "rv"); index++; - } } - } /* diff --git a/src/rich_value_structure.c b/src/rich_value_structure.c index 43bd7b58..fc614a50 100644 --- a/src/rich_value_structure.c +++ b/src/rich_value_structure.c @@ -75,32 +75,15 @@ _rich_value_structure_xml_declaration(lxw_rich_value_structure *self) * Write the element. */ STATIC void -_rich_value_structure_write_k2(lxw_rich_value_structure *self) +_rich_value_structure_write_k(lxw_rich_value_structure *self, char *name, + char *type) { 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 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_PUSH_ATTRIBUTES_STR("n", name); + LXW_PUSH_ATTRIBUTES_STR("t", type); lxw_xml_empty_tag(self->file, "k", &attributes); @@ -122,8 +105,11 @@ _rich_value_structure_write_s(lxw_rich_value_structure *self) lxw_xml_start_tag(self->file, "s", &attributes); /* Write the k element. */ - _rich_value_structure_write_k1(self); - _rich_value_structure_write_k2(self); + _rich_value_structure_write_k(self, "_rvRel:LocalImageIdentifier", "i"); + _rich_value_structure_write_k(self, "CalcOrigin", "i"); + + if (self->has_embedded_image_descriptions) + _rich_value_structure_write_k(self, "Text", "s"); lxw_xml_end_tag(self->file, "s"); diff --git a/src/workbook.c b/src/workbook.c index dbd2f28c..bbb355c5 100644 --- a/src/workbook.c +++ b/src/workbook.c @@ -217,7 +217,6 @@ 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) { @@ -1115,6 +1114,10 @@ _prepare_drawings(lxw_workbook *self) _store_image_type(self, object_props->image_type); + /* Check for images with alt-text. */ + if (object_props->description) + self->has_embedded_image_descriptions = LXW_TRUE; + /* Check for duplicate images and only store the first instance. */ if (object_props->md5) { tmp_image_md5.md5 = object_props->md5; diff --git a/src/worksheet.c b/src/worksheet.c index 44c2b28f..971a95ba 100644 --- a/src/worksheet.c +++ b/src/worksheet.c @@ -8523,9 +8523,13 @@ worksheet_write_url_opt(lxw_worksheet *self, else format = user_format; - err = worksheet_write_string(self, row_num, col_num, string_copy, format); - if (err) - goto mem_error; + if (!self->storing_embedded_image) { + err = + worksheet_write_string(self, row_num, col_num, string_copy, + format); + if (err) + goto mem_error; + } /* Reset default error condition. */ err = LXW_ERROR_MEMORY_MALLOC_FAILED; @@ -10487,9 +10491,9 @@ worksheet_insert_image_opt(lxw_worksheet *self, 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->object_position = user_options->object_position; object_props->decorative = user_options->decorative; if (user_options->description) @@ -10653,7 +10657,6 @@ worksheet_embed_image_opt(lxw_worksheet *self, lxw_image_options *user_options) { FILE *image_stream; - const char *description; lxw_object_properties *object_props; lxw_error err; @@ -10672,15 +10675,7 @@ worksheet_embed_image_opt(lxw_worksheet *self, 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; - } - + /* Check and store the cell dimensions. */ err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE); if (err) return err; @@ -10692,23 +10687,38 @@ worksheet_embed_image_opt(lxw_worksheet *self, return LXW_ERROR_MEMORY_MALLOC_FAILED; } + /* We only copy/use a limited number of options for embedded images. */ 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->cell_format) + object_props->format = user_options->cell_format; + + /* The url for embedded images is written as a cell url. */ + if (user_options->url) { + if (!user_options->cell_format) + object_props->format = self->default_url_format; + + self->storing_embedded_image = LXW_TRUE; + err = worksheet_write_url(self, + row_num, + col_num, + user_options->url, + object_props->format); + if (err) { + _free_object_properties(object_props); + fclose(image_stream); + return err; + } + + self->storing_embedded_image = LXW_FALSE; + } + object_props->decorative = user_options->decorative; if (user_options->description) - description = user_options->description; + object_props->description = lxw_strdup(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; @@ -10731,7 +10741,6 @@ worksheet_embed_image_opt(lxw_worksheet *self, fclose(image_stream); return LXW_ERROR_IMAGE_DIMENSIONS; } - } /* @@ -10745,6 +10754,144 @@ worksheet_embed_image(lxw_worksheet *self, return worksheet_embed_image_opt(self, row_num, col_num, filename, NULL); } +/* + * Embed an image buffer, with options, into the worksheet. + */ +lxw_error +worksheet_embed_image_buffer_opt(lxw_worksheet *self, + lxw_row_t row_num, + lxw_col_t col_num, + const unsigned char *image_buffer, + size_t image_size, + lxw_image_options *user_options) +{ + FILE *image_stream; + lxw_object_properties *object_props; + lxw_error err; + + if (!image_size) { + LXW_WARN("worksheet_embed_image_buffer()/_opt(): " + "size must be non-zero."); + return LXW_ERROR_NULL_PARAMETER_IGNORED; + } + + /* Write the image buffer to a file (preferably in memory) so we can read + * the dimensions like an ordinary file. For embedded images we really only + * need the image type. */ +#ifdef USE_FMEMOPEN + image_stream = fmemopen((void *) image_buffer, image_size, "rb"); + + if (!image_stream) + return LXW_ERROR_CREATING_TMPFILE; +#else + image_stream = lxw_tmpfile(self->tmpdir); + + if (!image_stream) + return LXW_ERROR_CREATING_TMPFILE; + + if (fwrite(image_buffer, 1, image_size, image_stream) != image_size) { + fclose(image_stream); + return LXW_ERROR_CREATING_TMPFILE; + } + + rewind(image_stream); +#endif + + /* Check and store the cell dimensions. */ + 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; + } + + /* Store the image data in the properties structure. */ + object_props->image_buffer = calloc(1, image_size); + if (!object_props->image_buffer) { + _free_object_properties(object_props); + fclose(image_stream); + return LXW_ERROR_MEMORY_MALLOC_FAILED; + } + else { + memcpy(object_props->image_buffer, image_buffer, image_size); + object_props->image_buffer_size = image_size; + object_props->is_image_buffer = LXW_TRUE; + } + + /* We only copy/use a limited number of options for embedded images. */ + if (user_options) { + if (user_options->cell_format) + object_props->format = user_options->cell_format; + + /* The url for embedded images is written as a cell url. */ + if (user_options->url) { + if (!user_options->cell_format) + object_props->format = self->default_url_format; + + self->storing_embedded_image = LXW_TRUE; + err = worksheet_write_url(self, + row_num, + col_num, + user_options->url, + object_props->format); + if (err) { + _free_object_properties(object_props); + fclose(image_stream); + return err; + } + + self->storing_embedded_image = LXW_FALSE; + } + + object_props->decorative = user_options->decorative; + if (user_options->description) + object_props->description = lxw_strdup(user_options->description); + } + + /* Copy other options or set defaults. */ + object_props->filename = lxw_strdup("image_buffer"); + 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; + } +} + +/* + * Insert an image buffer into the worksheet. + */ +lxw_error +worksheet_embed_image_buffer(lxw_worksheet *self, + lxw_row_t row_num, + lxw_col_t col_num, + const unsigned char *image_buffer, + size_t image_size) +{ + return worksheet_embed_image_buffer_opt(self, row_num, col_num, + image_buffer, image_size, NULL); +} + /* * Set an image as a worksheet background. */ @@ -11586,7 +11733,8 @@ worksheet_set_error_cell(lxw_worksheet *self, 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); + lxw_cell *cell = + _new_error_cell(row_num, col_num, ref_id, object_props->format); _insert_cell(self, row_num, col_num, cell); } diff --git a/test/functional/src/test_embed_image08.c b/test/functional/src/test_embed_image08.c new file mode 100644 index 00000000..2220b6ff --- /dev/null +++ b/test/functional/src/test_embed_image08.c @@ -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_image08.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + lxw_image_options image_options = {.description = "Some alt text"}; + + worksheet_embed_image_opt(worksheet, 0, 0, "images/red.png", &image_options); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_embed_image09.c b/test/functional/src/test_embed_image09.c new file mode 100644 index 00000000..bc4d06b9 --- /dev/null +++ b/test/functional/src/test_embed_image09.c @@ -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_image09.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + lxw_image_options image_options = {.description = "Some alt text", .decorative = LXW_TRUE}; + + worksheet_embed_image_opt(worksheet, 0, 0, "images/red.png", &image_options); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_embed_image10.c b/test/functional/src/test_embed_image10.c new file mode 100644 index 00000000..4afba2b7 --- /dev/null +++ b/test/functional/src/test_embed_image10.c @@ -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_image10.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + lxw_image_options image_options = {.url = "http://www.cpan.org/"}; + + worksheet_embed_image_opt(worksheet, 0, 0, "images/red.png", &image_options); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_embed_image12.c b/test/functional/src/test_embed_image12.c new file mode 100644 index 00000000..3a1a015d --- /dev/null +++ b/test/functional/src/test_embed_image12.c @@ -0,0 +1,25 @@ +/***************************************************************************** + * 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_image12.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + lxw_format *format1 = workbook_add_format(workbook); + format_set_bg_color( format1, 0xFFFF00); + + lxw_image_options image_options = {.cell_format = format1}; + + worksheet_embed_image_opt(worksheet, 0, 0, "images/red.png", &image_options); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_embed_image51.c b/test/functional/src/test_embed_image51.c new file mode 100644 index 00000000..71d0e280 --- /dev/null +++ b/test/functional/src/test_embed_image51.c @@ -0,0 +1,44 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Test to compare output against Excel files. + * + * SPDX-License-Identifier: BSD-2-Clause + * Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. + * + */ + +#include "xlsxwriter.h" + + +unsigned char image_buffer[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, + 0x08, 0x02, 0x00, 0x00, 0x00, 0xfc, 0x18, 0xed, 0xa3, 0x00, 0x00, 0x00, + 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, + 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, + 0x61, 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, + 0x7a, 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, + 0x80, 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, + 0x3a, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, + 0x00, 0x46, 0x49, 0x44, 0x41, 0x54, 0x48, 0x4b, 0x63, 0xfc, 0xcf, 0x40, + 0x63, 0x00, 0xb4, 0x80, 0xa6, 0x88, 0xb6, 0xa6, 0x83, 0x82, 0x87, 0xa6, + 0xce, 0x1f, 0xb5, 0x80, 0x98, 0xe0, 0x1d, 0x8d, 0x03, 0x82, 0xa1, 0x34, + 0x1a, 0x44, 0xa3, 0x41, 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, + 0xa3, 0x41, 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, 0xa3, 0x41, + 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, 0x03, 0x1f, 0x44, 0x00, + 0xaa, 0x35, 0xdd, 0x4e, 0xe6, 0xd5, 0xa1, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + +unsigned int image_size = 200; + +int main() { + + lxw_workbook *workbook = workbook_new("test_embed_image51.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + worksheet_embed_image_buffer(worksheet, 0, 0, image_buffer, image_size); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_embed_image52.c b/test/functional/src/test_embed_image52.c new file mode 100644 index 00000000..4b67cdee --- /dev/null +++ b/test/functional/src/test_embed_image52.c @@ -0,0 +1,46 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Test to compare output against Excel files. + * + * SPDX-License-Identifier: BSD-2-Clause + * Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. + * + */ + +#include "xlsxwriter.h" + + +unsigned char image_buffer[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, + 0x08, 0x02, 0x00, 0x00, 0x00, 0xfc, 0x18, 0xed, 0xa3, 0x00, 0x00, 0x00, + 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, + 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, + 0x61, 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, + 0x7a, 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, + 0x80, 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, + 0x3a, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, + 0x00, 0x46, 0x49, 0x44, 0x41, 0x54, 0x48, 0x4b, 0x63, 0xfc, 0xcf, 0x40, + 0x63, 0x00, 0xb4, 0x80, 0xa6, 0x88, 0xb6, 0xa6, 0x83, 0x82, 0x87, 0xa6, + 0xce, 0x1f, 0xb5, 0x80, 0x98, 0xe0, 0x1d, 0x8d, 0x03, 0x82, 0xa1, 0x34, + 0x1a, 0x44, 0xa3, 0x41, 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, + 0xa3, 0x41, 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, 0xa3, 0x41, + 0x44, 0x30, 0x04, 0x08, 0x2a, 0x18, 0x4d, 0x45, 0x03, 0x1f, 0x44, 0x00, + 0xaa, 0x35, 0xdd, 0x4e, 0xe6, 0xd5, 0xa1, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + +unsigned int image_size = 200; + +int main() { + + lxw_workbook *workbook = workbook_new("test_embed_image52.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + lxw_image_options image_options = {.description = "Some alt text"}; + + worksheet_embed_image_buffer_opt(worksheet, 0, 0, image_buffer, image_size, &image_options); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_format12.c b/test/functional/src/test_format12.c index a46f1c93..9434ccb6 100644 --- a/test/functional/src/test_format12.c +++ b/test/functional/src/test_format12.c @@ -1,7 +1,7 @@ /***************************************************************************** * Test cases for libxlsxwriter. * - * Simple test case for TODO. + * Test to compare output against Excel files. * * SPDX-License-Identifier: BSD-2-Clause * Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. diff --git a/test/functional/src/test_landscape01.c b/test/functional/src/test_landscape01.c index f982aa99..760933fb 100644 --- a/test/functional/src/test_landscape01.c +++ b/test/functional/src/test_landscape01.c @@ -1,7 +1,7 @@ /***************************************************************************** * Test cases for libxlsxwriter. * - * Simple test case for TODO. + * Test to compare output against Excel files. * * SPDX-License-Identifier: BSD-2-Clause * Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. diff --git a/test/functional/src/test_print_across01.c b/test/functional/src/test_print_across01.c index 6ea5d055..86893f45 100644 --- a/test/functional/src/test_print_across01.c +++ b/test/functional/src/test_print_across01.c @@ -1,7 +1,7 @@ /***************************************************************************** * Test cases for libxlsxwriter. * - * Simple test case for TODO. + * Test to compare output against Excel files. * * SPDX-License-Identifier: BSD-2-Clause * Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. diff --git a/test/functional/src/test_simple03.c b/test/functional/src/test_simple03.c index 0d1f81d3..4d64eae7 100644 --- a/test/functional/src/test_simple03.c +++ b/test/functional/src/test_simple03.c @@ -1,7 +1,7 @@ /***************************************************************************** * Test cases for libxlsxwriter. * - * Simple test case for TODO. + * Test to compare output against Excel files. * * SPDX-License-Identifier: BSD-2-Clause * Copyright 2014-2024, John McNamara, jmcnamara@cpan.org. diff --git a/test/functional/test_embed_image.py b/test/functional/test_embed_image.py index 05d49933..c8536f99 100644 --- a/test/functional/test_embed_image.py +++ b/test/functional/test_embed_image.py @@ -39,9 +39,30 @@ def test_embed_image06(self): def test_embed_image07(self): self.run_exe_test('test_embed_image07') - def test_embed_image11(self): + def test_embed_image08(self): + self.run_exe_test('test_embed_image08') + + def test_embed_image09(self): + self.run_exe_test('test_embed_image09') + + def test_embed_image10(self): + # Ignore the missing "display" parameter. + self.ignore_elements = {'xl/worksheets/sheet1.xml': ['