Initial png file parsing.

This commit is contained in:
John McNamara 2015-12-28 11:22:17 +00:00
parent fa450b2950
commit 186862a138
6 changed files with 213 additions and 34 deletions

1
.indent.pro vendored
View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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);
}