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 1bd709f7b02e6cf8c47318125d75d21092a8bcd9 (commit) from bf70bc758e8d915a99250ce0422f05f414785e5d (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/1bd709f7b02e6cf8c47318125d75d21092a8b...
commit 1bd709f7b02e6cf8c47318125d75d21092a8bcd9 Author: Cyril Hrubis metan@ucw.cz Date: Mon Jan 9 18:37:53 2012 +0100
loaders: Initial support for BMP images.
diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_BMP.h similarity index 67% copy from include/loaders/GP_Loaders.h copy to include/loaders/GP_BMP.h index b327744..2f81017 100644 --- a/include/loaders/GP_Loaders.h +++ b/include/loaders/GP_BMP.h @@ -16,37 +16,39 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos * - * jiri.bluebear.dluhos@gmail.com * - * * - * Copyright (C) 2009-2011 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
- /* - - Core include file for loaders API. - - */ - -#ifndef LOADERS_GP_LOADERS_H -#define LOADERS_GP_LOADERS_H +#ifndef LOADERS_GP_BMP_H +#define LOADERS_GP_BMP_H
#include "core/GP_Context.h" #include "core/GP_ProgressCallback.h"
-#include "GP_PBM.h" -#include "GP_PGM.h" -#include "GP_PPM.h" - -#include "GP_PNG.h" +/* + * Opens up a bmp file, checks signature, parses metadata. + * + * The width and height and pixel type are filled upon succcessful return. + */ +GP_RetCode GP_OpenBMP(const char *src_path, FILE **f, + GP_Size *w, GP_Size *h, GP_PixelType *pixel_type);
-#include "GP_JPG.h" +/* + * Reads a BMP from a opened file. + * + * Upon successful return context to store bitmap is allocated and image is + * loaded. + * + */ +GP_RetCode GP_ReadBMP(FILE *f, GP_Context **res, + GP_ProgressCallback *callback);
/* - * Tries to load image accordingly to extension. + * Does both GP_OpenBMP and GP_ReadBMP. */ -GP_RetCode GP_LoadImage(const char *src_path, GP_Context **res, - GP_ProgressCallback *callback); +GP_RetCode GP_LoadBMP(const char *src_path, GP_Context **res, + GP_ProgressCallback *callback); +
-#endif /* LOADERS_GP_LOADERS_H */ +#endif /* LOADERS_GP_BMP_H */ diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_Loaders.h index b327744..96b26c8 100644 --- a/include/loaders/GP_Loaders.h +++ b/include/loaders/GP_Loaders.h @@ -19,7 +19,7 @@ * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos * * jiri.bluebear.dluhos@gmail.com * * * - * Copyright (C) 2009-2011 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -39,8 +39,8 @@ #include "GP_PGM.h" #include "GP_PPM.h"
+#include "GP_BMP.h" #include "GP_PNG.h" - #include "GP_JPG.h"
/* diff --git a/libs/loaders/GP_BMP.c b/libs/loaders/GP_BMP.c new file mode 100644 index 0000000..b820dc8 --- /dev/null +++ b/libs/loaders/GP_BMP.c @@ -0,0 +1,355 @@ +/***************************************************************************** + * 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-2012 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +/* + + BMP loader. + + Thanks wikipedia for the format specification. + + */ + +#include <stdint.h> +#include <inttypes.h> + +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> + +#include "core/GP_Debug.h" +#include "GP_BMP.h" + +#define BMP_HEADER_OFFSET 0x0e /* info header offset */ +#define BMP_PIXELS_OFFSET_OFFSET 0x0a /* offset to offset to pixel data */ + +struct bitmap_info_header { + int32_t w; + int32_t h; + uint16_t bpp; + uint32_t compress_type; + uint32_t palette_colors; +}; + +enum bitmap_compress { + COMPRESS_NONE = 0, + COMPRESS_RLE8 = 1, + COMPRESS_RLE4 = 2, + COMPRESS_BITFIELDS = 3, + COMPRESS_JPEG = 4, /* only for printers */ + COMPRESS_PNG = 5, /* only for printers */ + COMPRESS_ALPHABITFIELDS = 6, + COMPRESS_MAX = COMPRESS_ALPHABITFIELDS, +}; + +static const char *bitmap_compress_names[] = { + "None", + "RLE8", + "RLE4", + "BITFIELDS", + "JPEG", + "PNG", + "ALPHABITFIELDS", +}; + +static const char *bitmap_compress_name(uint32_t compress) +{ + if (compress >= COMPRESS_MAX) + return "Unknown"; + + return bitmap_compress_names[compress]; +} + +enum bitmap_info_header_sizes { + BITMAPCOREHEADER = 12, /* old OS/2 format + win 3.0 */ + BITMAPCOREHEADER2 = 64, /* OS/2 */ + BITMAPINFOHEADER = 40, /* most common */ + BITMAPINFOHEADER2 = 52, /* Undocummented */ + BITMAPINFOHEADER3 = 56, /* Undocummented */ + BITMAPINFOHEADER4 = 108, /* adds color space + gamma - win 95/NT4 */ + BITMAPINFOHEADER5 = 124, /* adds ICC color profiles win 98+ */ +}; + +static const char *bitmap_info_header_size_name(uint32_t size) +{ + switch (size) { + case BITMAPCOREHEADER: + return "BitmapCoreHeader"; + case BITMAPCOREHEADER2: + return "BitmapCoreHeader2"; + case BITMAPINFOHEADER: + return "BitmapInfoHeader"; + case BITMAPINFOHEADER2: + return "BitmapInfoHeader2"; + case BITMAPINFOHEADER3: + return "BitmapInfoHeader3"; + case BITMAPINFOHEADER4: + return "BitmapInfoHeader4"; + case BITMAPINFOHEADER5: + return "BitmapInfoHeader5"; + } + + return "Unknown"; +} + +static GP_RetCode read_bitmap_info_header(FILE *f, + struct bitmap_info_header *header) +{ + if (fseek(f, BMP_HEADER_OFFSET, SEEK_SET)) { + GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'", + BMP_HEADER_OFFSET, strerror(errno)); + return GP_EBADFILE; + } + + char buf[36]; + uint32_t header_size; + + /* Read info header size, header size determines header type */ + if (fread(buf, 1, 4, f) != 4) { + GP_DEBUG(1, "Failed to read info header size"); + return GP_EBADFILE; + } + + header_size = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); + + GP_DEBUG(2, "BMP header type '%s'", + bitmap_info_header_size_name(header_size)); + + switch (header_size) { + case BITMAPCOREHEADER: + case BITMAPCOREHEADER2: + return GP_ENOIMPL; + /* The bitmap core header only adds filelds to the end of the header */ + default: + break; + }; + + if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) { + GP_DEBUG(1, "Failed to read bitmap info header"); + return 1; + } + + header->h = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); + header->w = buf[4] + (buf[5]<<8) + (buf[6]<<16) + (buf[7]<<24); + + header->bpp = buf[10] + (buf[11]<<8); + + header->compress_type = buf[12] + (buf[13]<<8) + + (buf[14]<<16) + (buf[15]<<24); + + header->palette_colors = buf[32] + (buf[33]<<8) + + (buf[34]<<16) + (buf[35]<<24); + + GP_DEBUG(2, "Have BMP bitmap size %"PRId32"x%"PRId32" %"PRIu16" " + "bpp, %"PRIu32" pallete colors, '%s' compression", + header->w, header->h, header->bpp, header->palette_colors, + bitmap_compress_name(header->compress_type)); + + return 0; +} + +GP_RetCode read_pixels_offset(FILE *f, uint32_t *offset) +{ + if (fseek(f, BMP_PIXELS_OFFSET_OFFSET, SEEK_SET)) { + GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'", + BMP_HEADER_OFFSET, strerror(errno)); + return GP_EBADFILE; + } + + char buf[4]; + + /* Read info header size, header size determines header type */ + if (fread(buf, 1, 4, f) != 4) { + GP_DEBUG(1, "Failed to read info header size"); + return GP_EBADFILE; + } + + *offset = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); + + return GP_ESUCCESS; +} + +GP_PixelType match_pixel_type(struct bitmap_info_header *header) +{ + switch (header->bpp) { + case 24: + return GP_PIXEL_RGB888; + } + + return GP_PIXEL_UNKNOWN; +} + +GP_RetCode read_rgb888(FILE *f, struct bitmap_info_header *header, + GP_Context *context, GP_ProgressCallback *callback) +{ + int32_t y; + uint32_t row_size = 3 * header->w; + + for (y = header->h - 1; y >= 0; y--) { + uint8_t *row = GP_PIXEL_ADDR(context, 0, y); + + if (fread(row, 1, row_size, f) != row_size) + return GP_EBADFILE; + + /* Rows are four byte aligned */ + switch (row_size % 4) { + case 3: + fgetc(f); + case 2: + fgetc(f); + case 1: + fgetc(f); + case 0: + break; + } + + if (GP_ProgressCallbackReport(callback, header->h - y -1, + context->h, context->w)) { + GP_DEBUG(1, "Operation aborted"); + return GP_EINTR; + } + } + + GP_ProgressCallbackDone(callback); + return GP_ESUCCESS; +} + +GP_RetCode read_bitmap_pixels(FILE *f, struct bitmap_info_header *header, + GP_Context *context, GP_ProgressCallback *callback) +{ + uint32_t pixels_offset; + GP_RetCode ret; + + if ((ret = read_pixels_offset(f, &pixels_offset))) + return ret; + + GP_DEBUG(2, "Offset to BMP pixels is 0x%x (%ubytes)", + pixels_offset, pixels_offset); + + if (fseek(f, pixels_offset, SEEK_SET)) { + GP_DEBUG(1, "fseek(f, 0x%02x (pixels_offset)) failed: '%s'", + pixels_offset, strerror(errno)); + return GP_EBADFILE; + } + + switch (header->bpp) { + case 24: + return read_rgb888(f, header, context, callback); + } + + return GP_ENOIMPL; +} + +GP_RetCode GP_OpenBMP(const char *src_path, FILE **f, + GP_Size *w, GP_Size *h, GP_PixelType *pixel_type) +{ + GP_RetCode ret = GP_EBADFILE; + + *f = fopen(src_path, "rb"); + + if (*f == NULL) { + GP_DEBUG(1, "Failed to open '%s' : %s", + src_path, strerror(errno)); + return GP_EBADFILE; + } + + int ch1 = fgetc(*f); + int ch2 = fgetc(*f); + + if (ch1 != 'B' || ch2 != 'M') { + GP_DEBUG(1, "Unexpected bitmap header 0x%02x (%c) 0x%02x (%c)", + ch1, isascii(ch1) ? ch1 : ' ', + ch2, isascii(ch2) ? ch2 : ' '); + goto err; + } + + if (w != NULL || h != NULL || pixel_type != NULL) { + struct bitmap_info_header header; + + if ((ret = read_bitmap_info_header(*f, &header))) + goto err; + + if (w != NULL) + *w = header.w; + + if (h != NULL) + *h = header.h; + } + + return GP_ESUCCESS; +err: + fclose(*f); + return GP_EBADFILE; +} + +GP_RetCode GP_ReadBMP(FILE *f, GP_Context **res, + GP_ProgressCallback *callback) +{ + struct bitmap_info_header header; + GP_RetCode ret; + GP_PixelType pixel_type; + + if ((ret = read_bitmap_info_header(f, &header))) + goto err; + + if (header.compress_type != COMPRESS_NONE) { + ret = GP_ENOIMPL; + goto err; + } + + if ((pixel_type = match_pixel_type(&header)) == GP_PIXEL_UNKNOWN) { + ret = GP_ENOIMPL; + goto err; + } + + GP_Context *context = GP_ContextAlloc(header.w, header.h, pixel_type); + + if (context == NULL) { + ret = GP_ENOMEM; + goto err; + } + + if ((ret = read_bitmap_pixels(f, &header, context, callback))) + goto err1; + + *res = context; + + return GP_ESUCCESS; +err1: + GP_ContextFree(context); +err: + fclose(f); + return ret; +} + +GP_RetCode GP_LoadBMP(const char *src_path, GP_Context **res, + GP_ProgressCallback *callback) +{ + FILE *f; + GP_RetCode ret; + + if ((ret = GP_OpenBMP(src_path, &f, NULL, NULL, NULL))) + return ret; + + return GP_ReadBMP(f, res, callback); +} + diff --git a/libs/loaders/GP_Loaders.c b/libs/loaders/GP_Loaders.c index 8a57c59..8ef8c63 100644 --- a/libs/loaders/GP_Loaders.c +++ b/libs/loaders/GP_Loaders.c @@ -46,6 +46,9 @@ GP_RetCode GP_LoadImage(const char *src_path, GP_Context **res, return GP_EBADFILE; }
+ if (len < 3) + goto skip_filename_check; + switch (src_path[len - 1]) { /* PNG, JPG, JPEG */ case 'g': @@ -97,8 +100,22 @@ GP_RetCode GP_LoadImage(const char *src_path, GP_Context **res, break; } break; + /* BMP */ + case 'P': + case 'p': + switch (src_path[len - 2]) { + case 'M': + case 'm': + if (src_path[len - 3] == 'B' || + src_path[len - 3] == 'b') + ret = GP_LoadBMP(src_path, res, callback); + break; + } + break; }
+skip_filename_check: + //TODO file signature based check
return ret;
-----------------------------------------------------------------------
Summary of changes: include/loaders/{GP_JPG.h => GP_BMP.h} | 40 ++-- include/loaders/GP_Loaders.h | 4 +- libs/loaders/GP_BMP.c | 355 ++++++++++++++++++++++++++++++++ libs/loaders/GP_Loaders.c | 17 ++ 4 files changed, 391 insertions(+), 25 deletions(-) copy include/loaders/{GP_JPG.h => GP_BMP.h} (71%) create mode 100644 libs/loaders/GP_BMP.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.