This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, master has been updated via c23cf7d15a7d1535d837b81022cc9d41ac095f2f (commit) via 6fa181b2108180d30144c84a08416c918cbacf69 (commit) from 439dd5a9d066e953868fb93356a8b48e362ef7c2 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/c23cf7d15a7d1535d837b81022cc9d41ac095...
commit c23cf7d15a7d1535d837b81022cc9d41ac095f2f Author: Cyril Hrubis metan@ucw.cz Date: Sun Apr 7 19:12:41 2013 +0200
loaders: BMP: Experimental BMP writer for RGB888.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/include/loaders/GP_BMP.h b/include/loaders/GP_BMP.h index 63473ea..e5ad3a7 100644 --- a/include/loaders/GP_BMP.h +++ b/include/loaders/GP_BMP.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -63,6 +63,13 @@ GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback); GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback);
/* + * Saves BMP to a file. Zero is returned on succes. Upon failure non-zero is + * returned and errno is filled accordingly. + */ +int GP_SaveBMP(const GP_Context *src, const char *dst_path, + GP_ProgressCallback *callback); + +/* * Match BMP signature. */ int GP_MatchBMP(const void *buf); diff --git a/libs/loaders/GP_BMP.c b/libs/loaders/GP_BMP.c index 42cfa23..8254bac 100644 --- a/libs/loaders/GP_BMP.c +++ b/libs/loaders/GP_BMP.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -39,7 +39,9 @@ #include "core/GP_Debug.h" #include "core/GP_Pixel.h" #include "core/GP_GetPutPixel.h" -#include "GP_BMP.h" + +#include "loaders/GP_ByteUtils.h" +#include "loaders/GP_BMP.h"
#define BMP_HEADER_OFFSET 0x0a /* info header offset - 4 bytes */
@@ -619,21 +621,144 @@ GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback) return GP_ReadBMP(f, callback); }
+/* + * Rows in bmp are four byte aligned. + */ +static uint32_t bmp_align_row_size(uint32_t width_bits) +{ + uint32_t bytes = (width_bits/8) + !!(width_bits%8);
+ if (bytes%4) + bytes += 4 - bytes%4;
-int GP_SaveBMP(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback) + return bytes; +} + +/* + * For uncompressd images + */ +static uint32_t bmp_count_bitmap_size(struct bitmap_info_header *header) { - FILE *f; + return header->h * bmp_align_row_size(header->bpp * header->w); +} + +static int bmp_write_header(struct bitmap_info_header *header, FILE *f) +{ + uint32_t bitmap_size = bmp_count_bitmap_size(header); + uint32_t file_size = bitmap_size + header->header_size + 14; + + /* Bitmap Header */ + if (GP_FWrite(f, "%a2%l4%x00%x00%x00%x00%l4", "BM", + file_size, header->pixel_offset) != 7) + return EIO; + + /* Bitmap Info Header */ + if (GP_FWrite(f, "%l4%l4%l4%l2%l2%l4%l4%l4%l4%l4%l4", + header->header_size, header->w, header->h, 1, + header->bpp, header->compress_type, bitmap_size, 0, 0, + header->palette_colors, 0) != 11) + return EIO; + + return 0; +}
+static int bmp_fill_header(const GP_Context *src, struct bitmap_info_header *header) +{ switch (src->pixel_type) { case GP_PIXEL_RGB888: - + header->bpp = 24; break; default: - errno = ENOSYS; - return 1; + GP_DEBUG(1, "Unsupported pixel type (%s)", + GP_PixelTypeName(src->pixel_type)); + return ENOSYS; }
- GP_DEBUG(1, "Saving PNG Image '%s'", dst_path); + header->w = src->w; + header->h = src->h; + + /* Most common 40 bytes Info Header */ + header->header_size = BITMAPINFOHEADER; + + /* No compression or palette */ + header->palette_colors = 0; + header->compress_type = COMPRESS_RGB; + + /* image data follows the header */ + header->pixel_offset = header->header_size + 14; + + return 0; +} + +static int bmp_write_data(FILE *f, const GP_Context *src, GP_ProgressCallback *callback) +{ + int y; + uint32_t padd_len = 0; + char padd[3] = {0}; + + if (src->bytes_per_row%4) + padd_len = 4 - src->bytes_per_row%4; + + for (y = src->h - 1; y >= 0; y--) { + void *row = GP_PIXEL_ADDR(src, 0, y); + + if (fwrite(row, src->bytes_per_row, 1, f) != 1) + return EIO;
+ /* write padding */ + if (padd_len) + if (fwrite(padd, padd_len, 1, f) != 1) + return EIO; + + if (GP_ProgressCallbackReport(callback, y, src->h, src->w)) { + GP_DEBUG(1, "Operation aborted"); + return ECANCELED; + } + } + + return 0; +} + +int GP_SaveBMP(const GP_Context *src, const char *dst_path, + GP_ProgressCallback *callback) +{ + struct bitmap_info_header header; + FILE *f; + int err; + + GP_DEBUG(1, "Saving BMP Image '%s'", dst_path); + + if ((err = bmp_fill_header(src, &header))) + goto err0; + + f = fopen(dst_path, "wb"); + + if (f == NULL) { + err = errno; + GP_DEBUG(1, "Failed to open '%s' for writing: %s", + dst_path, strerror(errno)); + goto err0; + } + + if ((err = bmp_write_header(&header, f))) + goto err1; + + if ((err = bmp_write_data(f, src, callback))) + goto err1; + + if (fclose(f)) { + err = errno; + GP_DEBUG(1, "Failed to close file '%s': %s", + dst_path, strerror(errno)); + goto err1; + } + + GP_ProgressCallbackDone(callback); + + return 0; +err1: + fclose(f); +err0: + errno = err; + return 1; } diff --git a/libs/loaders/GP_Loader.c b/libs/loaders/GP_Loader.c index 9f4f4ad..f084576 100644 --- a/libs/loaders/GP_Loader.c +++ b/libs/loaders/GP_Loader.c @@ -77,7 +77,7 @@ static GP_Loader ppm_loader = {
static GP_Loader bmp_loader = { .Load = GP_LoadBMP, - .Save = NULL, + .Save = GP_SaveBMP, .Match = GP_MatchBMP, .fmt_name = "BMP", .next = &ppm_loader,
http://repo.or.cz/w/gfxprim.git/commit/6fa181b2108180d30144c84a08416c918cbac...
commit 6fa181b2108180d30144c84a08416c918cbacf69 Author: Cyril Hrubis metan@ucw.cz Date: Sun Apr 7 17:41:45 2013 +0200
loaders: Add ByteUtils.
ByteUtils provide GP_FWrite() and GP_FRead() functions to ease reading and writing image file headers.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile index 547fdfd..b4a24d2 100644 --- a/demos/c_simple/Makefile +++ b/demos/c_simple/Makefile @@ -19,7 +19,7 @@ APPS=backend_example loaders_example loaders filters_symmetry gfx_koch v4l2_show v4l2_grab convolution weighted_median shapetest koch input_example fileview linetest randomshapetest fonttest loaders_register blittest textaligntest abort sin_AA x11_windows- debug_handler gaussian_noise + debug_handler gaussian_noise byte_utils
ifeq ($(HAVE_LIBSDL),yes) APPS+=SDL_glue diff --git a/demos/c_simple/byte_utils.c b/demos/c_simple/byte_utils.c new file mode 100644 index 0000000..0b122f0 --- /dev/null +++ b/demos/c_simple/byte_utils.c @@ -0,0 +1,93 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +/* + * Byte utils are utils to ease reading and parsing various image headers. + * + * This is internal API for loaders. + */ + +#include <stdint.h> +#include <stdio.h> + +#include <loaders/GP_ByteUtils.h> + +#define FILENAME "file.tmp" + +static void write_file(void) +{ + FILE *f; + int ret; + + f = fopen(FILENAME, "wb"); + + if (f == NULL) { + fprintf(stderr, "Failed to open file '" FILENAME "'"); + return; + } + + uint16_t w = 800; + uint16_t h = 600; + uint8_t bpp = 4; + char *sig = "MG"; + + ret = GP_FWrite(f, "%a2%x00%x00%b2%b2%b1", sig, w, h, bpp); + + if (ret != 6) + printf("Failed to write header, ret = %in", ret); + + fclose(f); +} + +static void read_file(void) +{ + FILE *f; + int ret; + + f = fopen(FILENAME, "rb"); + + if (f == NULL) { + fprintf(stderr, "Failed to open file '" FILENAME "'"); + return; + } + + uint16_t w; + uint16_t h; + uint8_t bpp; + char sig[3] = {0}; + + ret = GP_FRead(f, "%a2%x00%x00%b2%b2%b1", sig, &w, &h, &bpp); + + if (ret != 6) + printf("Failed to read header, ret = %in", ret); + + printf("SIG=%s, w=%u, h=%u, bpp=%un", sig, w, h, bpp); + + fclose(f); +} + +int main(void) +{ + write_file(); + read_file(); + return 0; +} diff --git a/include/loaders/GP_ByteUtils.h b/include/loaders/GP_ByteUtils.h new file mode 100644 index 0000000..0ec4732 --- /dev/null +++ b/include/loaders/GP_ByteUtils.h @@ -0,0 +1,70 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + + /* + + Utils to read/write bytes in specified endianity. + + */ + +#ifndef LOADERS_GP_BYTE_UTILS_H +#define LOADERS_GP_BYTE_UTILS_H + +#include <stdio.h> + +/* + * The format string examples: + * + * %l1 or %b1 assigns one byte + * %l2 assign two bytes in little endian + * %b4 assign four bytes in big endian + * %a6 read six bytes into array + * + * To read and write header with two byte signature, two reserved zero bytes + * and size in 16 bit unsigned little endian variables. + * + * uint16_t w; + * uint16_t h; + * char sig[2]; + * + * if (GP_FWrite(f, "%a2%x00%x00%l2%l2", "SG", w, h) != 5) + * //ERROR + * + * if (GP_FRead(f, "%a2%x00%x00%l2%l2", sig, &w, &h) != 5) + * //ERROR + */ + +/* + * Printf-like function to read bytes from a file. + * + * Returns number of characters read. + */ +int GP_FRead(FILE *f, const char *fmt, ...); + +/* + * Printf-like function to write bytes to a file. + * + * Returns number of characters read. + */ +int GP_FWrite(FILE *f, const char *fmt, ...); + +#endif /* LOADERS_GP_BYTE_UTILS_H */ diff --git a/libs/loaders/GP_ByteUtils.c b/libs/loaders/GP_ByteUtils.c new file mode 100644 index 0000000..e1c6ac0 --- /dev/null +++ b/libs/loaders/GP_ByteUtils.c @@ -0,0 +1,276 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#include <stdarg.h> + +#include "core/GP_Debug.h" + +#include "loaders/GP_ByteUtils.h" + +enum fmt_type { + BYTE_ARRAY, + BIG_ENDIAN_VAR, + LITTLE_ENDIAN_VAR, + IGNORE, + CONST_BYTE, +}; + +static int ctoi(char c, int *i) +{ + switch (c) { + case '0' ... '9': + *i += c - '0'; + break; + default: + return 1; + } + + return 0; +} + +static int ctoh(char c, int *i) +{ + switch (c) { + case '0' ... '9': + *i += c - '0'; + break; + case 'a' ... 'f': + *i += c - 'a' + 10; + break; + case 'A' ... 'F': + *i += c - 'A' + 10; + break; + case '0': + GP_WARN("Unexpected end of the format string"); + return 1; + default: + GP_WARN("Expected [0-9]|[a-f][A-F] in hex constant, got '%c'", c); + return 1; + } + + return 0; +} + +static const char *get_hex(const char *fmt, int *type, int *val) +{ + *type = CONST_BYTE; + + *val = 0; + + if (ctoh(fmt[0], val)) + return NULL; + + (*val)<<=4; + + if (ctoh(fmt[1], val)) + return NULL; + + return fmt + 2; +} + +static const char *get_int(const char *fmt, int *val) +{ + int i = 0; + + *val = 0; + + if (ctoi(fmt[i++], val)) + return fmt; + + while (!ctoi(fmt[i], val)) { + *val *= 10; + i++; + } + + return fmt + i; +} + +static const char *get_array(const char *fmt, int *type, int *val) +{ + *type = BYTE_ARRAY; + + fmt = get_int(fmt, val); + + /* array for one element "%a" */ + if (*val == 0) + *val = 1; + + return fmt; +} + +static const char *get_lb_size(const char *fmt, int *val) +{ + *val = 0; + + if (ctoi(fmt[0], val)) { + GP_WARN("Expected number after %%l or %%b, got '%c'", fmt[0]); + return NULL; + } + + switch (*val) { + case 1: + case 2: + case 4: + return fmt + 1; + } + + GP_WARN("Invalid little/big endian variable size '%i'", *val); + return NULL; +} + +static const char *get_next(const char *fmt, int *type, int *val) +{ + if (fmt[0] == '0') + return NULL; + + if (fmt[0] != '%') { + GP_WARN("Unexpected character in format string '%c'", fmt[0]); + return NULL; + } + + switch (fmt[1]) { + /* byte array */ + case 'a': + return get_array(fmt + 2, type, val); + break; + /* hexadecimal constant */ + case 'x': + return get_hex(fmt + 2, type, val); + break; + /* 1, 2, 4 bytes long variable in defined endianity */ + case 'l': + *type = LITTLE_ENDIAN_VAR; + return get_lb_size(fmt + 2, val); + break; + case 'b': + *type = BIG_ENDIAN_VAR; + return get_lb_size(fmt + 2, val); + break; + case 'i': + + break; + case '0': + GP_WARN("Unexpecned end of format string"); + return NULL; + break; + } + + GP_WARN("Unexpected character in format string '%c'", fmt[0]); + return NULL; +} + +int GP_FRead(FILE *f, const char *fmt, ...) +{ + int type, val, ret = 0; + va_list va; + + va_start(va, fmt); + + for (;;) { + fmt = get_next(fmt, &type, &val); + + /* end of the string or error */ + if (fmt == NULL) + goto end; + + switch (type) { + case BYTE_ARRAY: + if (fread(va_arg(va, void*), val, 1, f) != 1) + goto end; + break; + case CONST_BYTE: + if (fgetc(f) != val) + goto end; + break; + case LITTLE_ENDIAN_VAR: + case BIG_ENDIAN_VAR: + if (fread(va_arg(va, void*), val, 1, f) != 1) + goto end; + //TODO: Fix byteorder + break; + case IGNORE: + + break; + } + + ret++; + + } +end: + va_end(va); + return ret; +} + +int GP_FWrite(FILE *f, const char *fmt, ...) +{ + int type, val, ret = 0; + va_list va; + + va_start(va, fmt); + + for (;;) { + fmt = get_next(fmt, &type, &val); + + /* end of the string or error */ + if (fmt == NULL) + goto end; + + switch (type) { + case BYTE_ARRAY: + if (fwrite(va_arg(va, void*), val, 1, f) != 1) + goto end; + break; + case CONST_BYTE: + if (fwrite(&val, 1, 1, f) != 1) + goto end; + break; + case LITTLE_ENDIAN_VAR: + case BIG_ENDIAN_VAR: + switch (val) { + case 1: { + uint8_t c = va_arg(va, int); + if (fwrite(&c, 1, 1, f) != 1) + goto end; + } break; + case 2: { + uint16_t c = va_arg(va, int); + if (fwrite(&c, 2, 1, f) != 1) + goto end; + } break; + case 4: { + uint32_t c = va_arg(va, int); + if (fwrite(&c, 4, 1, f) != 1) + goto end; + } break; + } + break; + default: + GP_WARN("Wrong format type for writing"); + goto end; + } + + ret++; + } +end: + va_end(va); + return ret; +}
-----------------------------------------------------------------------
Summary of changes: demos/c_simple/Makefile | 2 +- demos/c_simple/{showimage.c => byte_utils.c} | 91 ++++--- include/loaders/GP_BMP.h | 9 +- .../{gfx/GP_HLineAA.h => loaders/GP_ByteUtils.h} | 57 +++-- libs/loaders/GP_BMP.c | 141 ++++++++++- libs/loaders/GP_ByteUtils.c | 276 ++++++++++++++++++++ libs/loaders/GP_Loader.c | 2 +- 7 files changed, 508 insertions(+), 70 deletions(-) copy demos/c_simple/{showimage.c => byte_utils.c} (62%) copy include/{gfx/GP_HLineAA.h => loaders/GP_ByteUtils.h} (63%) create mode 100644 libs/loaders/GP_ByteUtils.c
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.