mirror of
https://github.com/jmcnamara/libxlsxwriter.git
synced 2026-05-21 06:45:21 -06:00
Initial png file parsing.
This commit is contained in:
parent
fa450b2950
commit
186862a138
6 changed files with 213 additions and 34 deletions
1
.indent.pro
vendored
1
.indent.pro
vendored
|
|
@ -65,6 +65,7 @@
|
|||
-T lxw_hash_table
|
||||
-T lxw_header_footer_options
|
||||
-T lxw_heading_pair
|
||||
-T lxw_image_meta
|
||||
-T lxw_image_options
|
||||
-T lxw_merged_range
|
||||
-T lxw_packager
|
||||
|
|
|
|||
|
|
@ -19,16 +19,15 @@
|
|||
#define STATIC
|
||||
#endif
|
||||
|
||||
#define LXW_SHEETNAME_MAX 32
|
||||
#define LXW_SHEETNAME_LEN 65
|
||||
#define LXW_UINT32_T_LEN 11 /* Length of 4294967296. */
|
||||
|
||||
enum lxw_boolean {
|
||||
LXW_FALSE,
|
||||
LXW_TRUE
|
||||
};
|
||||
|
||||
#define LXW_IGNORE 1
|
||||
#define LXW_SHEETNAME_MAX 32
|
||||
#define LXW_SHEETNAME_LEN 65
|
||||
#define LXW_UINT32_T_LEN 11 /* Length of 4294967296\0. */
|
||||
#define LXW_IGNORE 1
|
||||
|
||||
#define LXW_ERROR(message) \
|
||||
fprintf(stderr, "[ERROR][%s:%d]: " message "\n", __FILE__, __LINE__)
|
||||
|
|
@ -55,10 +54,19 @@ enum lxw_boolean {
|
|||
}
|
||||
|
||||
#define LXW_WARN(message) \
|
||||
fprintf(stderr, "[WARN] %s(): " message "\n", __func__)
|
||||
fprintf(stderr, "[WARN]: " message "\n")
|
||||
|
||||
#define LXW_WARN_FORMAT(message, var) \
|
||||
fprintf(stderr, "[WARN] %s(): " message "\n", __func__, var)
|
||||
fprintf(stderr, "[WARN]: " message "\n", var)
|
||||
|
||||
#ifndef LXW_BIG_ENDIAN
|
||||
#define LXW_UINT32_NETWORK(n) ((((n) & 0xFF) << 24) | \
|
||||
(((n) & 0xFF00) << 8) | \
|
||||
(((n) & 0xFF0000) >> 8) | \
|
||||
(((n) & 0xFF000000) >> 24))
|
||||
#else
|
||||
#define LXW_UINT32_NETWORK(n) (n)
|
||||
#endif
|
||||
|
||||
/* Compilers that have a native snprintf() can use it directly. */
|
||||
#ifdef _MSC_VER
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "worksheet.h"
|
||||
#include "shared_strings.h"
|
||||
|
|
@ -192,6 +193,7 @@ typedef struct lxw_workbook {
|
|||
uint16_t active_sheet;
|
||||
uint16_t num_xf_formats;
|
||||
uint16_t num_format_count;
|
||||
uint16_t drawing_count;
|
||||
|
||||
uint16_t font_count;
|
||||
uint16_t border_count;
|
||||
|
|
|
|||
|
|
@ -137,6 +137,13 @@ enum pane_types {
|
|||
FREEZE_SPLIT_PANES
|
||||
};
|
||||
|
||||
enum image_types {
|
||||
IMAGE_UNKNOWN = 0,
|
||||
IMAGE_PNG,
|
||||
IMAGE_JPG,
|
||||
IMAGE_BMP
|
||||
};
|
||||
|
||||
/* Define the tree.h RB structs for the red-black head types. */
|
||||
RB_HEAD(lxw_table_cells, lxw_cell);
|
||||
|
||||
|
|
@ -271,6 +278,15 @@ typedef struct lxw_image_options {
|
|||
char *tip;
|
||||
uint8_t anchor;
|
||||
|
||||
/* Internal metadata. */
|
||||
FILE *stream;
|
||||
uint8_t image_type;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
char *short_name;
|
||||
double x_dpi;
|
||||
double y_dpi;
|
||||
|
||||
STAILQ_ENTRY (lxw_image_options) list_pointers;
|
||||
|
||||
} lxw_image_options;
|
||||
|
|
|
|||
168
src/workbook.c
168
src/workbook.c
|
|
@ -538,6 +538,171 @@ mem_error:
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract width and height information from a PNG file.
|
||||
*/
|
||||
STATIC int
|
||||
_process_png(lxw_image_options *image_options)
|
||||
{
|
||||
uint32_t length;
|
||||
uint32_t offset;
|
||||
char type[4];
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
double x_dpi = 96;
|
||||
double y_dpi = 96;
|
||||
|
||||
FILE *stream = image_options->stream;
|
||||
|
||||
/* Skip another 4 bytes to the end of the PNG header. */
|
||||
fseek(stream, 4, SEEK_CUR);
|
||||
|
||||
while (!feof(stream)) {
|
||||
|
||||
/* Read the PNG length and type fields for the sub-section. */
|
||||
if (fread(&length, sizeof(length), 1, stream) < 1)
|
||||
break;
|
||||
|
||||
if (fread(&type, 1, 4, stream) < 4)
|
||||
break;
|
||||
|
||||
/* Convert the length to network order. */
|
||||
length = LXW_UINT32_NETWORK(length);
|
||||
|
||||
/* The offset for next fseek() is the field length + type length. */
|
||||
offset = length + 4;
|
||||
|
||||
if (memcmp(type, "IHDR", 4) == 0) {
|
||||
if (fread(&width, sizeof(width), 1, stream) < 1)
|
||||
break;
|
||||
|
||||
if (fread(&height, sizeof(height), 1, stream) < 1)
|
||||
break;
|
||||
|
||||
width = LXW_UINT32_NETWORK(width);
|
||||
height = LXW_UINT32_NETWORK(height);
|
||||
|
||||
/* Reduce the offset by the length of previous freads(). */
|
||||
offset -= 8;
|
||||
}
|
||||
|
||||
if (memcmp(type, "pHYs", 4) == 0) {
|
||||
uint32_t x_ppu = 0;
|
||||
uint32_t y_ppu = 0;
|
||||
uint8_t units = 1;
|
||||
|
||||
if (fread(&x_ppu, sizeof(x_ppu), 1, stream) < 1)
|
||||
break;
|
||||
|
||||
if (fread(&y_ppu, sizeof(y_ppu), 1, stream) < 1)
|
||||
break;
|
||||
|
||||
if (fread(&units, sizeof(units), 1, stream) < 1)
|
||||
break;
|
||||
|
||||
if (units == 1) {
|
||||
x_dpi = (double) x_ppu *0.0254;
|
||||
y_dpi = (double) y_ppu *0.0254;
|
||||
}
|
||||
|
||||
/* Reduce the offset by the length of previous freads(). */
|
||||
offset -= 9;
|
||||
}
|
||||
|
||||
if (memcmp(type, "IEND", 4) == 0)
|
||||
break;
|
||||
|
||||
if (!feof(stream))
|
||||
fseek(stream, offset, SEEK_CUR);
|
||||
}
|
||||
|
||||
/* Ensure that we read some valid data from the file. */
|
||||
if (width == 0) {
|
||||
LXW_WARN_FORMAT("worksheet_insert_image()/_opts(): "
|
||||
"no size data found in file: %s\n",
|
||||
image_options->filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the image metadata. */
|
||||
image_options->image_type = IMAGE_PNG;
|
||||
image_options->width = width;
|
||||
image_options->height = height;
|
||||
image_options->x_dpi = x_dpi;
|
||||
image_options->y_dpi = y_dpi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract information from the image file such as dimension, type, filename,
|
||||
* and extension.
|
||||
*/
|
||||
STATIC int
|
||||
_get_image_properties(lxw_image_options *image_options)
|
||||
{
|
||||
char *short_name;
|
||||
char signature[4];
|
||||
|
||||
/* Read 4 bytes to look for the file header/signature. */
|
||||
if (fread(signature, 1, 4, image_options->stream) < 4)
|
||||
return -1;
|
||||
|
||||
if (memcmp(&signature[1], "PNG", 3) == 0) {
|
||||
_process_png(image_options);
|
||||
}
|
||||
else {
|
||||
LXW_WARN_FORMAT("worksheet_insert_image()/_opts(): "
|
||||
"unsupported image format for file: %s\n",
|
||||
image_options->filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the filename from the full path to add to the Drawing object. */
|
||||
short_name = basename(image_options->filename);
|
||||
if (short_name)
|
||||
image_options->short_name = lxw_strdup(short_name);
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate through the worksheets and set up any chart or image drawings.
|
||||
*/
|
||||
STATIC void
|
||||
_prepare_drawings(lxw_workbook *self)
|
||||
{
|
||||
lxw_worksheet *worksheet;
|
||||
lxw_image_options *image_options;
|
||||
uint16_t image_ref_id = 0;
|
||||
uint16_t drawing_id = 0;
|
||||
|
||||
STAILQ_FOREACH(worksheet, self->worksheets, list_pointers) {
|
||||
|
||||
if (STAILQ_EMPTY(worksheet->images))
|
||||
continue;
|
||||
|
||||
drawing_id++;
|
||||
|
||||
STAILQ_FOREACH(image_options, worksheet->images, list_pointers) {
|
||||
|
||||
if (_get_image_properties(image_options) != 0)
|
||||
continue;
|
||||
|
||||
image_ref_id++;
|
||||
|
||||
/*sheet->_prepare_image(index, image_ref_id, drawing_id, width,
|
||||
height, name, type);
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
self->drawing_count = drawing_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate through the worksheets and store any defined names used for print
|
||||
* ranges or repeat rows/columns.
|
||||
|
|
@ -1117,6 +1282,9 @@ workbook_close(lxw_workbook *self)
|
|||
/* Set the defined names for the worksheets such as Print Titles. */
|
||||
_prepare_defined_names(self);
|
||||
|
||||
/* Prepare the drawings, charts and images. */
|
||||
_prepare_drawings(self);
|
||||
|
||||
/* Create a packager object to assemble sub-elements into a zip file. */
|
||||
packager = _new_packager(self->filename);
|
||||
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ _free_image_options(lxw_image_options *image)
|
|||
return;
|
||||
|
||||
free(image->filename);
|
||||
free(image->short_name);
|
||||
free(image->url);
|
||||
free(image->tip);
|
||||
free(image);
|
||||
|
|
@ -3718,7 +3719,8 @@ worksheet_set_zoom(lxw_worksheet *self, uint16_t scale)
|
|||
{
|
||||
/* Confine the scale to Excel"s range */
|
||||
if (scale < 10 || scale > 400) {
|
||||
LXW_WARN("Zoom factor scale outside range: 10 <= zoom <= 400");
|
||||
LXW_WARN("worksheet_set_zoom(): "
|
||||
"Zoom factor scale outside range: 10 <= zoom <= 400");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3807,24 +3809,23 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|||
const char *filename,
|
||||
lxw_image_options *user_options)
|
||||
{
|
||||
FILE *file;
|
||||
FILE *image_stream;
|
||||
lxw_image_options *options;
|
||||
|
||||
if (!filename) {
|
||||
LXW_WARN("filename must be specified");
|
||||
LXW_WARN("worksheet_insert_image()/_opts(): "
|
||||
"filename must be specified");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check that the image file exists and can be opened. */
|
||||
file = fopen(filename, "rb");
|
||||
if (!file) {
|
||||
LXW_WARN_FORMAT("file doesn't exist or can't be opened: %s",
|
||||
image_stream = fopen(filename, "rb");
|
||||
if (!image_stream) {
|
||||
LXW_WARN_FORMAT("worksheet_insert_image()/_opts(): "
|
||||
"file doesn't exist or can't be opened: %s",
|
||||
filename);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* Create a new object to hold the image options. */
|
||||
options = calloc(1, sizeof(lxw_image_options));
|
||||
|
|
@ -3838,6 +3839,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|||
|
||||
/* Copy other options or set defaults. */
|
||||
options->filename = lxw_strdup(filename);
|
||||
options->stream = image_stream;
|
||||
|
||||
if (!options->x_scale)
|
||||
options->x_scale = 1;
|
||||
|
|
@ -3861,23 +3863,5 @@ worksheet_insert_image(lxw_worksheet *self,
|
|||
lxw_row_t row_num, lxw_col_t col_num,
|
||||
const char *filename)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
if (!filename) {
|
||||
LXW_WARN("filename must be specified");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check that the image file exists and can be opened. */
|
||||
file = fopen(filename, "rb");
|
||||
if (!file) {
|
||||
LXW_WARN_FORMAT("file doesn't exist or can't be opened: %s",
|
||||
filename);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return worksheet_insert_image_opt(self, row_num, col_num, filename, NULL);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue