[GH-ISSUE #125] Feature request: insert_image - allow to pass in-memory graphic #105

Closed
opened 2026-05-05 11:41:04 -06:00 by gitea-mirror · 6 comments
Owner

Originally created by @petricf on GitHub (Sep 4, 2017).
Original GitHub issue: https://github.com/jmcnamara/libxlsxwriter/issues/125

Originally assigned to: @jmcnamara on GitHub.

Many programs have the images inside the executable as resources. They load them from there. An explicit file is not available.
An other possibility could be that the images are created on the fly by the program logic.

lxw_worksheet only allows to insert an image from a file. So the in-memory picture must be written to an image file, inserted into the sheet and deleted afterwards.

This requested feature allows to pass a memory location / size containing the data of a picture (for example in png format) to an insert_image function derivation.

This avoids the additional disk operations and might be faster overall.

Originally created by @petricf on GitHub (Sep 4, 2017). Original GitHub issue: https://github.com/jmcnamara/libxlsxwriter/issues/125 Originally assigned to: @jmcnamara on GitHub. Many programs have the images inside the executable as resources. They load them from there. An explicit file is not available. An other possibility could be that the images are created on the fly by the program logic. lxw_worksheet only allows to insert an image from a file. So the in-memory picture must be written to an image file, inserted into the sheet and deleted afterwards. This requested feature allows to pass a memory location / size containing the data of a picture (for example in png format) to an insert_image function derivation. This avoids the additional disk operations and might be faster overall.
gitea-mirror 2026-05-05 11:41:04 -06:00
Author
Owner

@jmcnamara commented on GitHub (Sep 5, 2017):

lxw_worksheet only allows to insert an image from a file. So the in-memory picture must be written to an image file, inserted into the sheet and deleted afterwards.

This feature is in the Python version of the library: worksheet.insert_image().

I'll add it to libxlsxwriter if I get a few more +1s for this feature.

<!-- gh-comment-id:327161412 --> @jmcnamara commented on GitHub (Sep 5, 2017): > lxw_worksheet only allows to insert an image from a file. So the in-memory picture must be written to an image file, inserted into the sheet and deleted afterwards. This feature is in the Python version of the library: [worksheet.insert_image()](http://xlsxwriter.readthedocs.io/worksheet.html#worksheet-insert-image). I'll add it to libxlsxwriter if I get a few more +1s for this feature.
Author
Owner

@jmcnamara commented on GitHub (Aug 6, 2018):

If you would like to make a donation to accelerate this feature you can do so via PayPal or contact me directly. Currently $100 of $300.

<!-- gh-comment-id:410817088 --> @jmcnamara commented on GitHub (Aug 6, 2018): If you would like to make a donation to accelerate this feature you can do so via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ATE9EFWNF7PBJ) or contact me [directly](jmcnamara@cpan.org). Currently $100 of $300.
Author
Owner

@KengoSawa2 commented on GitHub (Aug 14, 2018):

Thank you for the great library.I respect your work:)
Although it is small amount, I donated.
I am glad if you get motivated

Open source is made of good intentions and progress.
Let's share your code, or donate!

<!-- gh-comment-id:412741291 --> @KengoSawa2 commented on GitHub (Aug 14, 2018): Thank you for the great library.I respect your work:) Although it is small amount, I donated. I am glad if you get motivated Open source is made of good intentions and progress. Let's share your code, or donate!
Author
Owner

@jmcnamara commented on GitHub (Aug 28, 2018):

I've added the initial working version of this feature to the in_mem_image branch. It needs more tests and documentation but I'm sharing it now for some early feedback.

An example program would look like this:

#include "xlsxwriter.h"


unsigned char red_png[] = {
    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 red_png_size = 200;

int main() {

    lxw_workbook  *workbook  = workbook_new("test_image51.xlsx");
    lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);

    worksheet_insert_image_buffer(worksheet, CELL("E9"), red_png, red_png_size, "red.png");

    return workbook_close(workbook);
}

Output:

screenshot

The interfaces, undocumented for now, are:

/**
 *
 * @param worksheet
 * @param row_num
 * @param col_num
 * @param image_buffer
 * @param image_size
 * @param filename
 * @param user_options
 * @return
 */
lxw_error worksheet_insert_image_buffer_opt(lxw_worksheet *worksheet,
                                            lxw_row_t row_num,
                                            lxw_col_t col_num,
                                            unsigned char *image_buffer,
                                            size_t image_size,
                                            const char *filename,
                                            lxw_image_options *user_options);

/**
 *
 * @param worksheet
 * @param row_num
 * @param col_num
 * @param image_buffer
 * @param image_size
 * @param filename
 * @return
 */
lxw_error worksheet_insert_image_buffer(lxw_worksheet *worksheet,
                                        lxw_row_t row_num,
                                        lxw_col_t col_num,
                                        unsigned char *image_buffer,
                                        size_t image_size,
                                        const char *filename);

The filename parameter is required metadata for Excel so that images can be identified in the interface. It doesn't have to be an existing filename.

In the final interface it will be optional and will be automatically replaced with image_1_1.jpg or similar. Or the parameter may be moved to the lxw_image_options struct.

If you would like to try it and have any feedback, let me know.

<!-- gh-comment-id:416778223 --> @jmcnamara commented on GitHub (Aug 28, 2018): I've added the initial working version of this feature to the `in_mem_image` branch. It needs more tests and documentation but I'm sharing it now for some early feedback. An example program would look like this: ```C #include "xlsxwriter.h" unsigned char red_png[] = { 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 red_png_size = 200; int main() { lxw_workbook *workbook = workbook_new("test_image51.xlsx"); lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); worksheet_insert_image_buffer(worksheet, CELL("E9"), red_png, red_png_size, "red.png"); return workbook_close(workbook); } ``` Output: ![screenshot](https://user-images.githubusercontent.com/94267/44757398-c65eab00-ab26-11e8-965f-0199c230af68.png) The interfaces, undocumented for now, are: ```C /** * * @param worksheet * @param row_num * @param col_num * @param image_buffer * @param image_size * @param filename * @param user_options * @return */ lxw_error worksheet_insert_image_buffer_opt(lxw_worksheet *worksheet, lxw_row_t row_num, lxw_col_t col_num, unsigned char *image_buffer, size_t image_size, const char *filename, lxw_image_options *user_options); /** * * @param worksheet * @param row_num * @param col_num * @param image_buffer * @param image_size * @param filename * @return */ lxw_error worksheet_insert_image_buffer(lxw_worksheet *worksheet, lxw_row_t row_num, lxw_col_t col_num, unsigned char *image_buffer, size_t image_size, const char *filename); ``` The `filename` parameter is required metadata for Excel so that images can be identified in the interface. It doesn't have to be an existing filename. In the final interface it will be optional and will be automatically replaced with `image_1_1.jpg` or similar. Or the parameter may be moved to the `lxw_image_options` struct. If you would like to try it and have any feedback, let me know.
Author
Owner

@jmcnamara commented on GitHub (Aug 29, 2018):

Here is the revised interface:

/**
 *
 * @param worksheet
 * @param row_num
 * @param col_num
 * @param image_buffer
 * @param image_size
 * @param user_options
 * @return
 */
lxw_error worksheet_insert_image_buffer_opt(lxw_worksheet *worksheet,
                                            lxw_row_t row_num,
                                            lxw_col_t col_num,
                                            unsigned char *image_buffer,
                                            size_t image_size,
                                            lxw_image_options *user_options);

/**
 *
 * @param worksheet
 * @param row_num
 * @param col_num
 * @param image_buffer
 * @param image_size
 * @return
 */
lxw_error worksheet_insert_image_buffer(lxw_worksheet *worksheet,
                                        lxw_row_t row_num,
                                        lxw_col_t col_num,
                                        unsigned char *image_buffer,
                                        size_t image_size);

And an example:

#include "xlsxwriter.h"


unsigned char red_png[] = {
    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 red_png_size = 200;

int main() {

    lxw_workbook  *workbook  = workbook_new("test_image82.xlsx");
    lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);

    worksheet_insert_image_buffer(worksheet, CELL("E9"), red_png, red_png_size);

    return workbook_close(workbook);
}

This will probably be the final interface.

<!-- gh-comment-id:417140412 --> @jmcnamara commented on GitHub (Aug 29, 2018): Here is the revised interface: ```C /** * * @param worksheet * @param row_num * @param col_num * @param image_buffer * @param image_size * @param user_options * @return */ lxw_error worksheet_insert_image_buffer_opt(lxw_worksheet *worksheet, lxw_row_t row_num, lxw_col_t col_num, unsigned char *image_buffer, size_t image_size, lxw_image_options *user_options); /** * * @param worksheet * @param row_num * @param col_num * @param image_buffer * @param image_size * @return */ lxw_error worksheet_insert_image_buffer(lxw_worksheet *worksheet, lxw_row_t row_num, lxw_col_t col_num, unsigned char *image_buffer, size_t image_size); ``` And an example: ```C #include "xlsxwriter.h" unsigned char red_png[] = { 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 red_png_size = 200; int main() { lxw_workbook *workbook = workbook_new("test_image82.xlsx"); lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); worksheet_insert_image_buffer(worksheet, CELL("E9"), red_png, red_png_size); return workbook_close(workbook); } ``` This will probably be the final interface.
Author
Owner

@jmcnamara commented on GitHub (Aug 30, 2018):

This feature has been release in version 0.7.8 of libxlsxwriter.

See http://libxlsxwriter.github.io/worksheet_8h.html#aebd5cc71a42ab0e4a9ce45fe9a6f6908

Thanks to @KengoSawa2 for the sponsorship.

<!-- gh-comment-id:417496009 --> @jmcnamara commented on GitHub (Aug 30, 2018): This feature has been release in version 0.7.8 of libxlsxwriter. See http://libxlsxwriter.github.io/worksheet_8h.html#aebd5cc71a42ab0e4a9ce45fe9a6f6908 Thanks to @KengoSawa2 for the sponsorship.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/libxlsxwriter#105
No description provided.