Skip to content

Commit

Permalink
worksheet: add embedded image options
Browse files Browse the repository at this point in the history
  • Loading branch information
jmcnamara committed Jul 30, 2024
1 parent 34b2d20 commit 1dc5977
Show file tree
Hide file tree
Showing 23 changed files with 493 additions and 65 deletions.
48 changes: 48 additions & 0 deletions examples/embed_image_buffer.c
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 2 additions & 2 deletions include/xlsxwriter/workbook.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
39 changes: 39 additions & 0 deletions include/xlsxwriter/worksheet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
*
Expand Down
13 changes: 7 additions & 6 deletions src/packager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
5 changes: 3 additions & 2 deletions src/rich_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++;

}
}

}

/*
Expand Down
32 changes: 9 additions & 23 deletions src/rich_value_structure.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,32 +75,15 @@ _rich_value_structure_xml_declaration(lxw_rich_value_structure *self)
* Write the <k> 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 <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_PUSH_ATTRIBUTES_STR("n", name);
LXW_PUSH_ATTRIBUTES_STR("t", type);

lxw_xml_empty_tag(self->file, "k", &attributes);

Expand All @@ -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");

Expand Down
5 changes: 4 additions & 1 deletion src/workbook.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 1dc5977

Please # to comment.