mirror of
https://github.com/rupertwh/bmplib.git
synced 2026-02-04 05:35:48 +00:00
Add support for OS/2 BA bitmap arrays
This commit is contained in:
12
bmp-common.h
12
bmp-common.h
@@ -102,6 +102,7 @@ enum ReadState {
|
||||
RS_DIMENSIONS_QUERIED,
|
||||
RS_LOAD_STARTED,
|
||||
RS_LOAD_DONE,
|
||||
RS_ARRAY,
|
||||
RS_FATAL,
|
||||
};
|
||||
|
||||
@@ -111,6 +112,9 @@ struct Bmpread {
|
||||
size_t bytes_read; /* number of bytes we have read from the file */
|
||||
struct Bmpfile *fh;
|
||||
struct Bmpinfo *ih;
|
||||
struct Arraylist *arrayimgs;
|
||||
int narrayimgs;
|
||||
bool is_arrayimg;
|
||||
unsigned int insanity_limit;
|
||||
int width;
|
||||
int height;
|
||||
@@ -337,6 +341,14 @@ struct Bmpinfo {
|
||||
enum BmpInfoVer version;
|
||||
};
|
||||
|
||||
struct Bmparray {
|
||||
uint16_t type;
|
||||
uint32_t size;
|
||||
uint32_t offsetnext;
|
||||
uint16_t screenwidth;
|
||||
uint16_t screenheight;
|
||||
};
|
||||
|
||||
#define IH_PROFILEDATA_OFFSET (14L + 112L)
|
||||
|
||||
#define MAX_ICCPROFILE_SIZE (1UL << 20)
|
||||
|
||||
353
bmp-read-icons.c
Normal file
353
bmp-read-icons.c
Normal file
@@ -0,0 +1,353 @@
|
||||
/* bmplib - bmp-read-icons.c
|
||||
*
|
||||
* Copyright (c) 2025, Rupert Weber.
|
||||
*
|
||||
* This file is part of bmplib.
|
||||
* bmplib 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 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 this library.
|
||||
* If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BMPLIB_LIB
|
||||
|
||||
#include "config.h"
|
||||
#include "bmplib.h"
|
||||
#include "logging.h"
|
||||
#include "bmp-common.h"
|
||||
#include "bmp-read-icons.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* bmpread_array_num
|
||||
*******************************************************/
|
||||
|
||||
API int bmpread_array_num(BMPHANDLE h)
|
||||
{
|
||||
BMPREAD rp;
|
||||
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
if (rp->read_state != RS_ARRAY) {
|
||||
logerr(rp->c.log, "Not a bitmap array");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rp->narrayimgs;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* bmpread_array_info
|
||||
*******************************************************/
|
||||
|
||||
API BMPRESULT bmpread_array_info(BMPHANDLE h, struct BmpArrayInfo *ai, int idx)
|
||||
{
|
||||
BMPREAD rp;
|
||||
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
if (rp->read_state != RS_ARRAY) {
|
||||
logerr(rp->c.log, "Not a bitmap array");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= rp->narrayimgs) {
|
||||
logerr(rp->c.log, "Invalid array index %d. Max is %d", idx, rp->narrayimgs - 1);
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (!ai) {
|
||||
logerr(rp->c.log, "Invalid array info pointer (NULL)");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
struct Arraylist *img = &rp->arrayimgs[idx];
|
||||
BMPREAD imgrp = (BMPREAD)img->handle;
|
||||
|
||||
memset(ai, 0, sizeof *ai);
|
||||
|
||||
ai->type = imgrp->fh->type;
|
||||
ai->handle = img->handle;
|
||||
ai->width = imgrp->width;
|
||||
ai->height = imgrp->height;
|
||||
if (imgrp->ih->bitcount <= 8)
|
||||
ai->ncolors = 1 << imgrp->ih->bitcount;
|
||||
else
|
||||
ai->ncolors = 0;
|
||||
ai->screenwidth = img->ah.screenwidth;
|
||||
ai->screenheight = img->ah.screenheight;
|
||||
|
||||
return BMP_RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* icon_read_array
|
||||
*******************************************************/
|
||||
static bool s_read_array_header(BMPREAD_R rp, struct Bmparray *ah);
|
||||
static void s_array_header_from_file_header(struct Bmparray *ah, struct Bmpfile *fh);
|
||||
|
||||
bool icon_read_array(BMPREAD_R rp)
|
||||
{
|
||||
struct Arraylist *imgs = NULL;
|
||||
struct Bmparray ah = { 0 };
|
||||
int n = 0;
|
||||
const int nmax = 16;
|
||||
bool invalid = false;
|
||||
|
||||
if (!(imgs = calloc(nmax, sizeof *imgs))) {
|
||||
logsyserr(rp->c.log, "Allocating bitmap array list");
|
||||
rp->lasterr = BMP_ERR_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
s_array_header_from_file_header(&ah, rp->fh);
|
||||
|
||||
while (n < nmax) {
|
||||
if (ah.type != BMPFILE_BA)
|
||||
break;
|
||||
|
||||
memcpy(&imgs[n].ah, &ah, sizeof ah);
|
||||
|
||||
imgs[n].handle = bmpread_new(rp->file);
|
||||
if (imgs[n].handle) {
|
||||
if (BMP_RESULT_OK == bmpread_load_info(imgs[n].handle)) {
|
||||
((BMPREAD)imgs[n].handle)->is_arrayimg = true;
|
||||
n++;
|
||||
} else {
|
||||
bmp_free(imgs[n].handle);
|
||||
invalid = true;
|
||||
rp->lasterr = BMP_ERR_HEADER;
|
||||
}
|
||||
} else {
|
||||
invalid = true;
|
||||
rp->lasterr = BMP_ERR_HEADER;
|
||||
}
|
||||
|
||||
if (!ah.offsetnext)
|
||||
break;
|
||||
|
||||
#if ( LONG_MAX <= 0x7fffffffL )
|
||||
if (ah.offsetnext > (unsigned long)LONG_MAX) {
|
||||
logerr(rp->c.log, "Invalid offset to next array image: %lu", (unsigned long)ah.offsetnext);
|
||||
invalid = true;
|
||||
rp->lasterr = BMP_ERR_HEADER;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (fseek(rp->file, ah.offsetnext, SEEK_SET)) {
|
||||
logsyserr(rp->c.log, "Seeking next array header");
|
||||
invalid = true;
|
||||
rp->lasterr = BMP_ERR_FILEIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!s_read_array_header(rp, &ah)) {
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rp->arrayimgs = imgs;
|
||||
rp->narrayimgs = n;
|
||||
|
||||
return !invalid;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* s_read_array_header
|
||||
*******************************************************/
|
||||
|
||||
static bool s_read_array_header(BMPREAD_R rp, struct Bmparray *ah)
|
||||
{
|
||||
if (read_u16_le(rp->file, &ah->type) &&
|
||||
read_u32_le(rp->file, &ah->size) &&
|
||||
read_u32_le(rp->file, &ah->offsetnext) &&
|
||||
read_u16_le(rp->file, &ah->screenwidth) &&
|
||||
read_u16_le(rp->file, &ah->screenheight)) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (feof(rp->file)) {
|
||||
logerr(rp->c.log, "unexpected end-of-file while reading "
|
||||
"array header");
|
||||
rp->lasterr = BMP_ERR_TRUNCATED;
|
||||
} else {
|
||||
logsyserr(rp->c.log, "error reading array header");
|
||||
rp->lasterr = BMP_ERR_FILEIO;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* s_array_header_from_file_header
|
||||
*******************************************************/
|
||||
|
||||
static void s_array_header_from_file_header(struct Bmparray *ah, struct Bmpfile *fh)
|
||||
{
|
||||
ah->type = fh->type;
|
||||
ah->size = fh->size;
|
||||
ah->offsetnext = (uint32_t)fh->reserved2 << 16 | fh->reserved1;
|
||||
ah->screenwidth = fh->offbits & 0xffff;
|
||||
ah->screenheight = (fh->offbits >> 16) & 0xffff;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* icon_load_masks
|
||||
*******************************************************/
|
||||
|
||||
long icon_load_masks(BMPREAD_R rp)
|
||||
{
|
||||
/* OS/2 icons and pointers contain 1-bit AND and XOR masks, stacked in a single
|
||||
* image. For monochrome (IC/PT), that's all the image; for color (CI/CP), these are
|
||||
* followed by a complete color image (including headers), the masks are only used
|
||||
* for transparency information.
|
||||
*/
|
||||
|
||||
BMPHANDLE hmono = NULL;
|
||||
BMPREAD rpmono;
|
||||
unsigned char *monobuf = NULL;
|
||||
size_t bufsize;
|
||||
unsigned bmptype = rp->fh->type;
|
||||
long posmono = 0, poscolor = 0;
|
||||
|
||||
if (fseek(rp->file, -14, SEEK_CUR)) {
|
||||
logsyserr(rp->c.log, "Seeking to start of icon/pointer");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (-1 == (posmono = ftell(rp->file))) {
|
||||
logsyserr(rp->c.log, "Saving file position");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* first, load monochrome XOR/AND bitmap. We'll use the
|
||||
* AND bitmap as alpha channel for the color bitmap
|
||||
*/
|
||||
|
||||
if (!(hmono = bmpread_new(rp->file))) {
|
||||
logerr(rp->c.log, "Getting handle for monochrome XOR/AND map");
|
||||
goto abort;
|
||||
}
|
||||
rpmono = cm_read_handle(hmono);
|
||||
|
||||
rpmono->read_state = RS_EXPECT_ICON_MASK;
|
||||
if (BMP_RESULT_OK != bmpread_load_info(hmono)) {
|
||||
logerr(rp->c.log, "%s", bmp_errmsg(hmono));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (rpmono->fh->type != bmptype) {
|
||||
logerr(rp->c.log, "File type mismatch. Have 0x%04x, expected 0x%04x",
|
||||
(unsigned)rpmono->fh->type, bmptype);
|
||||
}
|
||||
|
||||
if (rp->fh->type == BMPFILE_CI || rp->fh->type == BMPFILE_CP) {
|
||||
if (-1 == (poscolor = ftell(rp->file))) {
|
||||
logsyserr(rp->c.log, "Saving position of color header");
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(rpmono->width > 0 && rpmono->height > 0 && rpmono->width <=512 && rpmono->height <= 512)) {
|
||||
logerr(rp->c.log, "Invalid icon/pointer dimensions: %dx%d", rpmono->width, rpmono->height);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (rpmono->ih->bitcount != 1) {
|
||||
logerr(rp->c.log, "Invalid icon/pointer monochrome bitcount: %d", rpmono->ih->bitcount);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (rpmono->height & 1) {
|
||||
logerr(rp->c.log, "Invalid odd icon/pointer height: %d (must be even)", rpmono->height);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
int width, height, bitsperchannel, channels;
|
||||
if (BMP_RESULT_OK != bmpread_dimensions(hmono, &width, &height, &channels, &bitsperchannel, NULL)) {
|
||||
logerr(rp->c.log, "%s", bmp_errmsg(hmono));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
height /= 2; /* mochrome contains two stacked bitmaps (AND and XOR) */
|
||||
|
||||
if (channels != 3 || bitsperchannel != 8) {
|
||||
logerr(rp->c.log, "Unexpected result color depth for monochrome image: "
|
||||
"%d channels, %d bits/channel", channels, bitsperchannel);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* store the AND/XOR bitmaps in the main BMPREAD struct */
|
||||
|
||||
bufsize = bmpread_buffersize(hmono);
|
||||
if (BMP_RESULT_OK != bmpread_load_image(hmono, &monobuf)) {
|
||||
logerr(rp->c.log, "%s", bmp_errmsg(hmono));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!(bufsize > 0 && monobuf != NULL)) {
|
||||
logerr(rp->c.log, "Panic! unkown error while loading monochrome bitmap");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!(rp->icon_mono_and = malloc(width * height))) {
|
||||
logsyserr(rp->c.log, "Allocating mono AND bitmap");
|
||||
goto abort;
|
||||
}
|
||||
if (!(rp->icon_mono_xor = malloc(width * height))) {
|
||||
logsyserr(rp->c.log, "Allocating mono XOR bitmap");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
for (int i = 0; i < width * height; i++)
|
||||
rp->icon_mono_and[i] = 255 - monobuf[3 * i];
|
||||
|
||||
for (int i = 0; i < width * height; i++)
|
||||
rp->icon_mono_xor[i] = monobuf[3 * (width * height + i)];
|
||||
|
||||
rp->icon_mono_width = width;
|
||||
rp->icon_mono_height = height;
|
||||
free(monobuf);
|
||||
monobuf = NULL;
|
||||
bmp_free(hmono);
|
||||
hmono = NULL;
|
||||
|
||||
if (rp->fh->type == BMPFILE_CI || rp->fh->type == BMPFILE_CP)
|
||||
return poscolor;
|
||||
|
||||
return posmono;
|
||||
|
||||
abort:
|
||||
if (hmono)
|
||||
bmp_free(hmono);
|
||||
if (monobuf)
|
||||
free(monobuf);
|
||||
return -1;
|
||||
}
|
||||
28
bmp-read-icons.h
Normal file
28
bmp-read-icons.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* bmplib - bmp-read-icons.h
|
||||
*
|
||||
* Copyright (c) 2025, Rupert Weber.
|
||||
*
|
||||
* This file is part of bmplib.
|
||||
* bmplib 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 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 this library.
|
||||
* If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
struct Arraylist {
|
||||
struct Bmparray ah;
|
||||
BMPHANDLE handle;
|
||||
};
|
||||
|
||||
long icon_load_masks(BMPREAD_R rp);
|
||||
bool icon_read_array(BMPREAD_R rp);
|
||||
@@ -130,6 +130,11 @@ static BMPRESULT s_load_image_or_line(BMPREAD_R rp, unsigned char **restrict buf
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (rp->read_state >= RS_ARRAY) {
|
||||
logerr(rp->c.log, "Invalid operation on bitmap array");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (rp->read_state >= RS_LOAD_DONE) {
|
||||
logerr(rp->c.log, "Cannot load image more than once!");
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
183
bmp-read.c
183
bmp-read.c
@@ -32,6 +32,7 @@
|
||||
#include "bmplib.h"
|
||||
#include "logging.h"
|
||||
#include "bmp-common.h"
|
||||
#include "bmp-read-icons.h"
|
||||
#include "bmp-read.h"
|
||||
|
||||
|
||||
@@ -92,7 +93,6 @@ abort:
|
||||
*****************************************************************************/
|
||||
static bool s_read_file_header(BMPREAD_R rp);
|
||||
static bool s_read_info_header(BMPREAD_R rp);
|
||||
static long s_load_icon_masks(BMPREAD_R rp);
|
||||
static bool s_is_bmptype_supported(BMPREAD_R rp);
|
||||
static struct Palette* s_read_palette(BMPREAD_R rp);
|
||||
static bool s_read_colormasks(BMPREAD_R rp);
|
||||
@@ -123,7 +123,7 @@ API BMPRESULT bmpread_load_info(BMPHANDLE h)
|
||||
case BMPFILE_IC:
|
||||
case BMPFILE_PT:
|
||||
if (rp->read_state < RS_EXPECT_ICON_MASK) {
|
||||
pos = s_load_icon_masks(rp);
|
||||
pos = icon_load_masks(rp);
|
||||
if (pos < 0)
|
||||
goto abort;
|
||||
|
||||
@@ -151,9 +151,18 @@ API BMPRESULT bmpread_load_info(BMPHANDLE h)
|
||||
break;
|
||||
|
||||
case BMPFILE_BA:
|
||||
logerr(rp->c.log, "OS/2 Bitmap arrays not supported");
|
||||
rp->lasterr = BMP_ERR_UNSUPPORTED;
|
||||
goto abort;
|
||||
if (rp->is_arrayimg) {
|
||||
logerr(rp->c.log, "Invalid nested bitmap array");
|
||||
goto abort;
|
||||
}
|
||||
if (!icon_read_array(rp)) {
|
||||
logerr(rp->c.log, "Failed to read icon array index");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
rp->read_state = RS_ARRAY;
|
||||
return BMP_RESULT_ARRAY;
|
||||
|
||||
|
||||
default:
|
||||
logerr(rp->c.log, "Unkown BMP type 0x%04x\n", (unsigned int) rp->fh->type);
|
||||
@@ -262,141 +271,6 @@ abort:
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* s_load_icon_masks
|
||||
*****************************************************************************/
|
||||
|
||||
static long s_load_icon_masks(BMPREAD_R rp)
|
||||
{
|
||||
/* OS/2 icons and pointers contain 1-bit AND and XOR masks, stacked in a single
|
||||
* image. For monochrome (IC/PT), that's all the image; for color (CI/CP), these are
|
||||
* followed by a complete color image (including headers), the masks are only used
|
||||
* for transparency information.
|
||||
*/
|
||||
|
||||
BMPHANDLE hmono = NULL;
|
||||
BMPREAD rpmono;
|
||||
unsigned char *monobuf = NULL;
|
||||
size_t bufsize;
|
||||
unsigned bmptype = rp->fh->type;
|
||||
long posmono = 0, poscolor = 0;
|
||||
|
||||
if (fseek(rp->file, -14, SEEK_CUR)) {
|
||||
logsyserr(rp->c.log, "Seeking to start of icon/pointer");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (-1 == (posmono = ftell(rp->file))) {
|
||||
logsyserr(rp->c.log, "Saving file position");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* first, load monochrome XOR/AND bitmap. We'll use the
|
||||
* AND bitmap as alpha channel
|
||||
*/
|
||||
|
||||
if (!(hmono = bmpread_new(rp->file))) {
|
||||
logerr(rp->c.log, "Getting handle for monochrome XOR/AND map");
|
||||
goto abort;
|
||||
}
|
||||
rpmono = cm_read_handle(hmono);
|
||||
|
||||
rpmono->read_state = RS_EXPECT_ICON_MASK;
|
||||
if (BMP_RESULT_OK != bmpread_load_info(hmono)) {
|
||||
logerr(rp->c.log, "%s", bmp_errmsg(hmono));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (rpmono->fh->type != bmptype) {
|
||||
logerr(rp->c.log, "File type mismatch. Have 0x%04x, expected 0x%04x",
|
||||
(unsigned)rpmono->fh->type, bmptype);
|
||||
}
|
||||
|
||||
if (rp->fh->type == BMPFILE_CI || rp->fh->type == BMPFILE_CP) {
|
||||
if (-1 == (poscolor = ftell(rp->file))) {
|
||||
logsyserr(rp->c.log, "Saving position of color header");
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(rpmono->width > 0 && rpmono->height > 0 && rpmono->width <=512 && rpmono->height <= 512)) {
|
||||
logerr(rp->c.log, "Invalid icon/pointer dimensions: %dx%d", rpmono->width, rpmono->height);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (rpmono->ih->bitcount != 1) {
|
||||
logerr(rp->c.log, "Invalid icon/pointer monochrome bitcount: %d", rpmono->ih->bitcount);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (rpmono->height & 1) {
|
||||
logerr(rp->c.log, "Invalid odd icon/pointer height: %d (must be even)", rpmono->height);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
int width, height, bitsperchannel, channels;
|
||||
if (BMP_RESULT_OK != bmpread_dimensions(hmono, &width, &height, &channels, &bitsperchannel, NULL)) {
|
||||
logerr(rp->c.log, "%s", bmp_errmsg(hmono));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
height /= 2; /* mochrome contains two stacked bitmaps (AND and XOR) */
|
||||
|
||||
if (channels != 3 || bitsperchannel != 8) {
|
||||
logerr(rp->c.log, "Unexpected result color depth for monochrome image: %d channels, %d bits/channel",
|
||||
channels, bitsperchannel);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* store the AND/XOR bitmaps in the main BMPREAD struct */
|
||||
|
||||
bufsize = bmpread_buffersize(hmono);
|
||||
if (BMP_RESULT_OK != bmpread_load_image(hmono, &monobuf)) {
|
||||
logerr(rp->c.log, "%s", bmp_errmsg(hmono));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!(bufsize > 0 && monobuf != NULL)) {
|
||||
logerr(rp->c.log, "Panic! unkown error while loading monochrome bitmap");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!(rp->icon_mono_and = malloc(width * height))) {
|
||||
logsyserr(rp->c.log, "Allocating mono AND bitmap");
|
||||
goto abort;
|
||||
}
|
||||
if (!(rp->icon_mono_xor = malloc(width * height))) {
|
||||
logsyserr(rp->c.log, "Allocating mono XOR bitmap");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
for (int i = 0; i < width * height; i++)
|
||||
rp->icon_mono_and[i] = 255 - monobuf[3 * i];
|
||||
|
||||
for (int i = 0; i < width * height; i++)
|
||||
rp->icon_mono_xor[i] = monobuf[3 * (width * height + i)];
|
||||
|
||||
rp->icon_mono_width = width;
|
||||
rp->icon_mono_height = height;
|
||||
free(monobuf);
|
||||
monobuf = NULL;
|
||||
bmp_free(hmono);
|
||||
hmono = NULL;
|
||||
|
||||
if (rp->fh->type == BMPFILE_CI || rp->fh->type == BMPFILE_CP)
|
||||
return poscolor;
|
||||
|
||||
return posmono;
|
||||
|
||||
abort:
|
||||
if (hmono)
|
||||
bmp_free(hmono);
|
||||
if (monobuf)
|
||||
free(monobuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* bmpread_set_64bit_conv
|
||||
*****************************************************************************/
|
||||
@@ -454,7 +328,7 @@ API int bmpread_is_64bit(BMPHANDLE h)
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return 0;
|
||||
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL)
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY)
|
||||
return 0;
|
||||
|
||||
if (rp->ih->bitcount == 64)
|
||||
@@ -475,7 +349,7 @@ API size_t bmpread_iccprofile_size(BMPHANDLE h)
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return 0;
|
||||
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL)
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY)
|
||||
return 0;
|
||||
|
||||
if (rp->ih->cstype == PROFILE_EMBEDDED && rp->ih->profilesize <= MAX_ICCPROFILE_SIZE) {
|
||||
@@ -501,7 +375,7 @@ API BMPRESULT bmpread_load_iccprofile(BMPHANDLE h, unsigned char **profile)
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
goto abort;
|
||||
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) {
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) {
|
||||
logerr(rp->c.log, "Must load info before loading ICC profile");
|
||||
goto abort;
|
||||
}
|
||||
@@ -598,7 +472,7 @@ API BMPRESULT bmpread_dimensions(BMPHANDLE h, int* restrict width,
|
||||
if (rp->read_state < RS_HEADER_OK)
|
||||
bmpread_load_info((BMPHANDLE)(void*)rp);
|
||||
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL)
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY)
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
if (width) {
|
||||
@@ -643,6 +517,9 @@ BMPRESULT br_set_number_format(BMPREAD_R rp, enum BmpFormat format)
|
||||
return BMP_RESULT_OK;
|
||||
}
|
||||
|
||||
if (rp->read_state >= RS_ARRAY)
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
switch (format) {
|
||||
case BMP_FORMAT_INT:
|
||||
/* always ok */
|
||||
@@ -737,7 +614,7 @@ static int s_single_dim_val(BMPHANDLE h, enum Dimint dim)
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return 0;
|
||||
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL)
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY)
|
||||
return 0;
|
||||
|
||||
switch (dim) {
|
||||
@@ -789,7 +666,7 @@ API size_t bmpread_buffersize(BMPHANDLE h)
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return 0;
|
||||
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL)
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY)
|
||||
return 0;
|
||||
|
||||
rp->read_state = MAX(RS_DIMENSIONS_QUERIED, rp->read_state);
|
||||
@@ -877,6 +754,16 @@ void br_free(BMPREAD rp)
|
||||
{
|
||||
rp->c.magic = 0;
|
||||
|
||||
if (rp->is_arrayimg)
|
||||
return;
|
||||
|
||||
if (rp->arrayimgs) {
|
||||
for (int i = 0; i < rp->narrayimgs; i++) {
|
||||
((BMPREAD)rp->arrayimgs[i].handle)->is_arrayimg = false;
|
||||
br_free((BMPREAD)rp->arrayimgs[i].handle);
|
||||
}
|
||||
free(rp->arrayimgs);
|
||||
}
|
||||
if (rp->icon_mono_and)
|
||||
free(rp->icon_mono_and);
|
||||
if (rp->icon_mono_xor)
|
||||
@@ -1696,7 +1583,7 @@ static int s_info_int(BMPHANDLE h, enum Infoint info)
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return 0;
|
||||
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL)
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY)
|
||||
return 0;
|
||||
|
||||
switch (info) {
|
||||
@@ -1767,7 +1654,7 @@ API BMPRESULT bmpread_info_channel_bits(BMPHANDLE h, int *r, int *g, int *b, int
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL)
|
||||
if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY)
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
if (rp->ih->compression == BI_OS2_RLE24) {
|
||||
|
||||
8
bmplib.h
8
bmplib.h
@@ -245,9 +245,10 @@ enum BmpImagetype {
|
||||
typedef enum BmpImagetype BMPIMAGETYPE;
|
||||
|
||||
struct BmpArrayInfo {
|
||||
BMPHANDLE handle;
|
||||
BMPIMAGETYPE type;
|
||||
int width, height;
|
||||
int ncolors; /* -1 = RGB */
|
||||
int ncolors; /* 0 = RGB */
|
||||
int screenwidth, screenheight; /* typically 0, or 1024x768 for 'hi-res' */
|
||||
};
|
||||
|
||||
@@ -290,6 +291,11 @@ APIDECL BMPRESULT bmpread_set_64bit_conv(BMPHANDLE h, BMPCONV64 conv);
|
||||
APIDECL size_t bmpread_iccprofile_size(BMPHANDLE h);
|
||||
APIDECL BMPRESULT bmpread_load_iccprofile(BMPHANDLE h, unsigned char **profile);
|
||||
|
||||
|
||||
APIDECL int bmpread_array_num(BMPHANDLE h);
|
||||
APIDECL BMPRESULT bmpread_array_info(BMPHANDLE h, struct BmpArrayInfo *ai, int idx);
|
||||
|
||||
|
||||
APIDECL BMPINFOVER bmpread_info_header_version(BMPHANDLE h);
|
||||
APIDECL const char* bmpread_info_header_name(BMPHANDLE h);
|
||||
APIDECL int bmpread_info_header_size(BMPHANDLE h);
|
||||
|
||||
@@ -37,6 +37,7 @@ bmplib_sources = ['bmp-read.c',
|
||||
'bmp-write.c',
|
||||
'bmp-read-loadimage.c',
|
||||
'bmp-read-loadindexed.c',
|
||||
'bmp-read-icons.c',
|
||||
'bmp-common.c',
|
||||
'huffman.c',
|
||||
'logging.c']
|
||||
@@ -74,6 +75,7 @@ test_read_conversions = executable('test_read_conversions',
|
||||
'test-read-conversions.c',
|
||||
'bmp-common.c',
|
||||
'bmp-read.c',
|
||||
'bmp-read-icons.c',
|
||||
'bmp-write.c',
|
||||
'huffman.c',
|
||||
'logging.c',
|
||||
@@ -85,6 +87,7 @@ test_read_io = executable('test_read_io',
|
||||
'test-read-io.c',
|
||||
'bmp-common.c',
|
||||
'bmp-read.c',
|
||||
'bmp-read-icons.c',
|
||||
'bmp-write.c',
|
||||
'huffman.c',
|
||||
'logging.c',
|
||||
@@ -97,6 +100,7 @@ test_write_io = executable('test_write_io',
|
||||
'test-write-io.c',
|
||||
'bmp-common.c',
|
||||
'bmp-read.c',
|
||||
'bmp-read-icons.c',
|
||||
'bmp-read-loadimage.c',
|
||||
'huffman.c',
|
||||
'logging.c',
|
||||
|
||||
Reference in New Issue
Block a user