Add support for OS/2 BA bitmap arrays

This commit is contained in:
Rupert
2025-05-25 23:00:29 +02:00
committed by Rupert
parent 10657851d1
commit 5cd33b22ca
7 changed files with 444 additions and 149 deletions

View File

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

View File

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

View File

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

View File

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

View File

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