From 742be08ccce58399da08b52141b2f6d1e9554baf Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 01:49:46 -0400
Subject: [PATCH 01/64] added current state of aabb
---
CMakeLists.txt | 2 +
include/lexlib/aabb.h | 61 ++++++++++++++++++++++++
src/aabb.c | 106 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 169 insertions(+)
create mode 100644 include/lexlib/aabb.h
create mode 100644 src/aabb.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3fc61fe..25b2048 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,6 +7,7 @@ project("lexlib" VERSION 1.4.0)
# lexlib itself and src
add_library(${PROJECT_NAME} STATIC)
target_sources(${PROJECT_NAME} PRIVATE
+ src/color/aabb.c
src/color/color.c
src/color/colorflt.c
src/file.c
@@ -29,6 +30,7 @@ set_source_files_properties(src/path.c PROPERTIES COMPILE_FLAGS -Wdeprecated-dec
# explicitly define public headers
target_sources(${PROJECT_NAME} PUBLIC FILE_SET HEADERS
FILES
+ include/lexlib/aabb.h
include/lexlib/color.h
include/lexlib/common.h
include/lexlib/defines.h
diff --git a/include/lexlib/aabb.h b/include/lexlib/aabb.h
new file mode 100644
index 0000000..7bfa659
--- /dev/null
+++ b/include/lexlib/aabb.h
@@ -0,0 +1,61 @@
+// Copyright 2023 alexevier
+// licensed under the MIT or Apache 2.0 (at your option)
+
+#ifndef lexlib_aabb_h
+#define lexlib_aabb_h
+#include"common.h"
+
+#include
+
+// NOTE s
+// the length extends across the axis in the +.
+
+// structs //
+
+// the [0] of each component is the pos and [1] is the length.
+struct LexlibAABB {
+ float x[2];
+ float y[2];
+ float z[2];
+};
+
+// ..structs.. //
+
+
+
+// typedefs //
+#ifndef __cplusplus
+typedef struct LexlibAABB LexlibAABB;
+#endif
+// ..typedefs.. //
+
+
+
+// creation //
+
+LEXLIB_EXTERN LexlibAABB lexlibAABBNewUni3(float x, float y, float z, float size);
+
+// ..creation.. //
+
+
+
+// intersects //
+
+LEXLIB_EXTERN uint8_t lexlibAABBIntersect(const LexlibAABB* a, const LexlibAABB* b);
+
+// ..intersects.. //
+
+
+
+// misc //
+#ifdef LEXLIB_EXPERIMENTAL
+
+// gets the aabb as world vertex data.
+// the verts and indices can be optional, the indices are always the same.
+// the format is x,y,z.
+LEXLIB_EXTERN void lexlibAABBVertexData(const LexlibAABB* aabb, float verts[24], unsigned int indices[24]);
+
+#endif
+// ..misc.. //
+
+#endif
\ No newline at end of file
diff --git a/src/aabb.c b/src/aabb.c
new file mode 100644
index 0000000..e4baecb
--- /dev/null
+++ b/src/aabb.c
@@ -0,0 +1,106 @@
+// Copyright 2023 alexevier
+// licensed under the MIT or Apache 2.0 (at your option)
+
+#include
+#define false 0
+#define true 1
+
+// creation //
+
+LEXLIB_EXTERN LexlibAABB lexlibAABBNewUni3(float x, float y, float z, float size){
+ return (LexlibAABB){
+ {x, size},
+ {y, size},
+ {z, size}
+ };
+}
+
+// ..creation.. //
+
+
+
+// intersects //
+
+uint8_t lexlibAABBIntersect(const LexlibAABB* a, const LexlibAABB* b){
+ LexlibAABB A = {
+ {a->x[0], a->x[0] + a->x[1]},
+ {a->y[0], a->y[0] + a->y[1]},
+ {a->z[0], a->z[0] + a->z[1]},
+ };
+ LexlibAABB B = {
+ {b->x[0], b->x[0] + b->x[1]},
+ {b->y[0], b->y[0] + b->y[1]},
+ {b->z[0], b->z[0] + b->z[1]},
+ };
+
+ if(A.x[1] > B.x[0])
+ return true;
+
+ return false;
+}
+
+// ..intersects.. //
+
+
+
+// misc //
+
+void lexlibAABBVertexData(const LexlibAABB* aabb, float verts[24], unsigned int indices[24]){
+ if(verts){
+ // bottom
+ verts[0 ] = aabb->x[0];
+ verts[1 ] = aabb->y[0];
+ verts[2 ] = aabb->z[0];
+ verts[3 ] = aabb->x[0] + aabb->x[1];
+ verts[4 ] = aabb->y[0];
+ verts[5 ] = aabb->z[0];
+ verts[6 ] = aabb->x[0];
+ verts[7 ] = aabb->y[0];
+ verts[8 ] = aabb->z[0] + aabb->z[1];
+ verts[9 ] = aabb->x[0] + aabb->x[1];
+ verts[10] = aabb->y[0];
+ verts[11] = aabb->z[0] + aabb->z[1];
+ // top
+ verts[12] = aabb->x[0];
+ verts[13] = aabb->y[0] + aabb->y[1];
+ verts[14] = aabb->z[0];
+ verts[15] = aabb->x[0] + aabb->x[1];
+ verts[16] = aabb->y[0] + aabb->y[1];
+ verts[17] = aabb->z[0];
+ verts[18] = aabb->x[0];
+ verts[19] = aabb->y[0] + aabb->y[1];
+ verts[20] = aabb->z[0] + aabb->z[1];
+ verts[21] = aabb->x[0] + aabb->x[1];
+ verts[22] = aabb->y[0] + aabb->y[1];
+ verts[23] = aabb->z[0] + aabb->z[1];
+ }
+
+ if(indices){
+ indices[0 ] = 0;
+ indices[1 ] = 1;
+ indices[2 ] = 0;
+ indices[3 ] = 2;
+ indices[4 ] = 1;
+ indices[5 ] = 3;
+ indices[6 ] = 2;
+ indices[7 ] = 3;
+ indices[8 ] = 4;
+ indices[9 ] = 5;
+ indices[10] = 4;
+ indices[11] = 6;
+ indices[12] = 5;
+ indices[13] = 7;
+ indices[14] = 6;
+ indices[15] = 7;
+ indices[16] = 0;
+ indices[17] = 4;
+ indices[18] = 1;
+ indices[19] = 5;
+ indices[20] = 2;
+ indices[21] = 6;
+ indices[22] = 3;
+ indices[23] = 7;
+ }
+}
+
+// ..misc.. //
\ No newline at end of file
--
GitLab
From 83e373b6f70b1871621d2dc0d637322e945d7043 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 01:52:02 -0400
Subject: [PATCH 02/64] set version number to 1.5.0
---
CMakeLists.txt | 2 +-
linux.sh | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 25b2048..a2f9921 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.26.0)
-project("lexlib" VERSION 1.4.0)
+project("lexlib" VERSION 1.5.0)
# NOTE s
# don't forget to change the version number in linux.sh too.
diff --git a/linux.sh b/linux.sh
index 278078f..24a36f0 100755
--- a/linux.sh
+++ b/linux.sh
@@ -6,7 +6,7 @@ mingw32dir=/usr/i686-w64-mingw32
mingw64dir=/usr/x86_64-w64-mingw32
# lexlib vars, do not touch.
-version="1.4.0"
+version="1.5.0"
function message () {
echo -e "[\e[1;38;5;243mlinux.sh\e[0m]: $@\e[0m"
--
GitLab
From c93e16aedb1dbc2fb1e25a2efd96e0a40ad59fb5 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 01:53:29 -0400
Subject: [PATCH 03/64] fixed miscopied src/aabb.c
---
CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a2f9921..7e40916 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,7 +7,7 @@ project("lexlib" VERSION 1.5.0)
# lexlib itself and src
add_library(${PROJECT_NAME} STATIC)
target_sources(${PROJECT_NAME} PRIVATE
- src/color/aabb.c
+ src/aabb.c
src/color/color.c
src/color/colorflt.c
src/file.c
--
GitLab
From 1089c7af797a64831e37f3d68cbc9bdd638dadef Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 02:50:53 -0400
Subject: [PATCH 04/64] added the short license notice to src color
---
src/color/color.c | 3 +++
src/color/colorflt.c | 3 +++
2 files changed, 6 insertions(+)
diff --git a/src/color/color.c b/src/color/color.c
index 63157b4..8cd2648 100644
--- a/src/color/color.c
+++ b/src/color/color.c
@@ -1,3 +1,6 @@
+// Copyright 2023 alexevier
+// licensed under the MIT or Apache 2.0 (at your option)
+
#include
#include
#include
diff --git a/src/color/colorflt.c b/src/color/colorflt.c
index 6248fb7..28f9187 100644
--- a/src/color/colorflt.c
+++ b/src/color/colorflt.c
@@ -1,3 +1,6 @@
+// Copyright 2023 alexevier
+// licensed under the MIT or Apache 2.0 (at your option)
+
#include
LexlibColorFlt lexlibColorFltBlend(const LexlibColorFlt dst, const LexlibColorFlt src, uint8_t mode){
--
GitLab
From 192b390d7da6ec992db2007418f673bc1cb6bdb5 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 14:01:11 -0400
Subject: [PATCH 05/64] macro to check for endianness
---
include/lexlib/common.h | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/include/lexlib/common.h b/include/lexlib/common.h
index c6dd7f8..2927c87 100644
--- a/include/lexlib/common.h
+++ b/include/lexlib/common.h
@@ -5,7 +5,8 @@
#define lexlib_common_h
/* this header is not documented since its not
-suposed to be used externally of lexlib */
+suposed to be used externally of lexlib
+and any changes may break api */
#include"defines.h"
@@ -25,6 +26,20 @@ suposed to be used externally of lexlib */
# define LEXLIB_DEPRECATED
#endif
+#ifdef __BYTE_ORDER__
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define LEXLIB_LITTLE_ENDIAN LEXLIB_FALSE
+# define LEXLIB_BIG_ENDIAN LEXLIB_TRUE
+# else /* if its not big endian or can't be detected fallback to little endian. */
+# define LEXLIB_LITTLE_ENDIAN LEXLIB_TRUE
+# define LEXLIB_BIG_ENDIAN LEXLIB_FALSE
+# endif
+#else
+# warning lexlib could not detected endianness, __BYTE_ORDER__ not defined, fallback to little
+# define LEXLIB_LITTLE_ENDIAN LEXLIB_TRUE
+# define LEXLIB_BIG_ENDIAN LEXLIB_FALSE
+#endif
+
#define LEXLIB_BUFFER_SIZE 256
#endif
\ No newline at end of file
--
GitLab
From d08f818a3ecc458c62caf560d9bc32731c167339 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 15:06:06 -0400
Subject: [PATCH 06/64] color16 blending
---
CMakeLists.txt | 1 +
include/lexlib/color.h | 1 +
src/color/color16.c | 60 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 62 insertions(+)
create mode 100644 src/color/color16.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7e40916..6720ba0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,7 @@ add_library(${PROJECT_NAME} STATIC)
target_sources(${PROJECT_NAME} PRIVATE
src/aabb.c
src/color/color.c
+ src/color/color16.c
src/color/colorflt.c
src/file.c
src/image.c
diff --git a/include/lexlib/color.h b/include/lexlib/color.h
index 08e864e..dfae622 100644
--- a/include/lexlib/color.h
+++ b/include/lexlib/color.h
@@ -77,6 +77,7 @@ typedef struct LexlibColor16 LexlibColor16;
// performs a color blend depending on the mode
// if mode is invalid the default (LEXLIB_ADD) will be done.
LEXLIB_EXTERN LexlibColor lexlibColorBlend(const LexlibColor dst, const LexlibColor src, uint8_t mode);
+LEXLIB_EXTERN LexlibColor16 lexlibColor16Blend(const LexlibColor16 dst, const LexlibColor16 src, uint8_t mode);
LEXLIB_EXTERN LexlibColorFlt lexlibColorFltBlend(const LexlibColorFlt dst, const LexlibColorFlt src, uint8_t mode);
diff --git a/src/color/color16.c b/src/color/color16.c
new file mode 100644
index 0000000..b63fbe9
--- /dev/null
+++ b/src/color/color16.c
@@ -0,0 +1,60 @@
+// Copyright 2023 alexevier
+// licensed under the MIT or Apache 2.0 (at your option)
+
+#include
+#include
+#include
+#include
+
+LexlibColor16 lexlibColor16Blend(const LexlibColor16 dst, const LexlibColor16 src, uint8_t mode){
+ LexlibColor16 color;
+
+ switch(mode){
+ case LEXLIB_NONE:
+ return src;
+ case LEXLIB_ADD:{
+ float alpha = (float)src.a / .0f;
+ color.r = lexlibClampi(dst.r + rintf(src.r * alpha), 0, 65535);
+ color.g = lexlibClampi(dst.g + rintf(src.g * alpha), 0, 65535);
+ color.b = lexlibClampi(dst.b + rintf(src.b * alpha), 0, 65535);
+ color.a = dst.a;
+ return color;
+ }
+ case LEXLIB_SUB:{
+ float alpha = (float)src.a / 65535.0f;
+ color.r = dst.r - (src.r * alpha);
+ color.g = dst.g - (src.g * alpha);
+ color.b = dst.b - (src.b * alpha);
+ color.a = dst.a;
+ return color;
+ }
+ case LEXLIB_MUL:{
+ LexlibColor16 d = lexlibColor16Premultiply(dst);
+ LexlibColorFlt dstf = lexlibColor16ToFlt(d);
+ float alpha = (float)src.a / 65535.0f;
+ float alphainv = 1.0f - alpha;
+ color.r = lexlibClampi(rintf((src.r * dstf.r) + (dst.r * alphainv)), 0, 65535);
+ color.g = lexlibClampi(rintf((src.g * dstf.g) + (dst.g * alphainv)), 0, 65535);
+ color.b = lexlibClampi(rintf((src.b * dstf.b) + (dst.b * alphainv)), 0, 65535);
+ color.a = lexlibClampi(rintf(((alpha * dstf.a) + (dstf.a * alphainv))) * 65535.0f, 0, 65535);
+ return color;
+ }
+ case LEXLIB_MOD:
+ color.r = rintf(src.r * (dst.r / 65535.0f));
+ color.g = rintf(src.g * (dst.g / 65535.0f));
+ color.b = rintf(src.b * (dst.b / 65535.0f));
+ color.a = dst.a;
+ return color;
+ case LEXLIB_BLEND:{
+ float alpha = (float)src.a / 65535.0f;
+ float alphainv = 1.0f - alpha;
+ color.r = rintf((src.r * alpha) + (dst.r * alphainv));
+ color.g = rintf((src.g * alpha) + (dst.g * alphainv));
+ color.b = rintf((src.b * alpha) + (dst.b * alphainv));
+ color.a = (alpha + (((float)dst.a / 65535.0f) * alphainv)) * 65535.0f;
+ return color;
+ }
+ default:
+ return lexlibColor16Blend(dst, src, LEXLIB_ADD);
+ }
+}
\ No newline at end of file
--
GitLab
From 7bc913c9d8dccde1bb63dcd8b6024109e919d0f3 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 15:07:37 -0400
Subject: [PATCH 07/64] fixed a little error in color16 blending
---
src/color/color16.c | 2 +-
src/color/colorflt.c | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/color/color16.c b/src/color/color16.c
index b63fbe9..f3bc57c 100644
--- a/src/color/color16.c
+++ b/src/color/color16.c
@@ -13,7 +13,7 @@ LexlibColor16 lexlibColor16Blend(const LexlibColor16 dst, const LexlibColor16 sr
case LEXLIB_NONE:
return src;
case LEXLIB_ADD:{
- float alpha = (float)src.a / .0f;
+ float alpha = (float)src.a / 65535.0f;
color.r = lexlibClampi(dst.r + rintf(src.r * alpha), 0, 65535);
color.g = lexlibClampi(dst.g + rintf(src.g * alpha), 0, 65535);
color.b = lexlibClampi(dst.b + rintf(src.b * alpha), 0, 65535);
diff --git a/src/color/colorflt.c b/src/color/colorflt.c
index 28f9187..b03eefa 100644
--- a/src/color/colorflt.c
+++ b/src/color/colorflt.c
@@ -2,6 +2,7 @@
// licensed under the MIT or Apache 2.0 (at your option)
#include
+#include
LexlibColorFlt lexlibColorFltBlend(const LexlibColorFlt dst, const LexlibColorFlt src, uint8_t mode){
LexlibColorFlt color;
--
GitLab
From 8cce6887cab915cc616c9172a4e07c636ccb475f Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 16:42:01 -0400
Subject: [PATCH 08/64] finished imagePixelSet()
---
CHANGELOG.md | 4 ++
include/lexlib/image.h | 5 ++
src/image.c | 119 +++++++++++++++++++++++++++++++++++++++--
3 files changed, 123 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index af324a7..edd2c60 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.5.0 (under development)
++ function lexlibColor16Blend().
++ function lexlibImagePixelSet().
+
## 1.4.0
+ function lexlibStrCopy().
+ removed path.h from default includes.
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index d9057ab..0524afd 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -8,6 +8,11 @@
#include
#include"color.h"
+/* NOTE s
+ images with more bitdepth than 8 are bigendian.
+*/
+
+
struct LexlibImage {
uint8_t* data;
uint32_t width;
diff --git a/src/image.c b/src/image.c
index a36314d..3c37aca 100644
--- a/src/image.c
+++ b/src/image.c
@@ -175,12 +175,121 @@ uint8_t lexlibImagePixelSet(const LexlibImage* image, uint32_t x, uint32_t y, Le
size_t rowsize = image->width * pixelsize;
size_t offset = (y * rowsize) + (x * pixelsize);
- image->data[offset+0] = color.r;
- image->data[offset+1] = color.g;
- image->data[offset+2] = color.b;
- image->data[offset+3] = color.a;
+ if(image->depth == 8){
+ if(image->channels == 1){
+ image->data[offset] = lexlibColorGray(color);
+ return LEXLIB_OK;
+ }
+ if(image->channels == 3){
+ LexlibColor pixel = *((LexlibColor*)image->data+offset);
+ pixel.a = -1;
+ pixel = lexlibColorPremultiply(lexlibColorBlend(pixel, color, blendmode));
+ image->data[offset+0] = pixel.r;
+ image->data[offset+1] = pixel.g;
+ image->data[offset+2] = pixel.b;
+ return LEXLIB_OK;
+ }
+ if(image->channels == 4){
+ *(LexlibColor*)(image->data+offset) = lexlibColorBlend(*(LexlibColor*)(image->data+offset), color, blendmode);
+ return LEXLIB_OK;
+ }
+ return LEXLIB_INVALID_VALUE;
+ }
- return LEXLIB_OK;
+ if(image->depth == 16){
+#if LEXLIB_BIG_ENDIAN
+ if(image->channels == 1){
+ uint16_t col = lexlibColor16Gray(lexlibColorTo16(color));
+ image->data[offset+0] = ((uint8_t*)&col)[0];
+ image->data[offset+1] = ((uint8_t*)&col)[1];
+ return LEXLIB_OK;
+ }
+ if(image->channels == 3){
+ LexlibColor16 color16 = lexlibColorTo16(color);
+ LexlibColor16 pixel16 = *((LexlibColor16*)image->data+offset);
+ pixel16.a = -1;
+ pixel16 = lexlibColor16Premultiply(lexlibColor16Blend(pixel16, color16, blendmode));
+ image->data[offset+0] = ((uint8_t*)&pixel16)[0];
+ image->data[offset+1] = ((uint8_t*)&pixel16)[1];
+ image->data[offset+2] = ((uint8_t*)&pixel16)[2];
+ image->data[offset+3] = ((uint8_t*)&pixel16)[3];
+ image->data[offset+4] = ((uint8_t*)&pixel16)[4];
+ image->data[offset+5] = ((uint8_t*)&pixel16)[5];
+ return LEXLIB_OK;
+ }
+
+ if(image->channels == 4){
+ *(LexlibColor16*)(image->data+offset) = lexlibColor16Blend(*(LexlibColor16*)(image->data+offset), lexlibColorTo16(color), blendmode);
+ return LEXLIB_OK;
+ }
+#else /* little endian */
+ if(image->channels == 1){
+ uint16_t col = lexlibColor16Gray(lexlibColorTo16(color));
+ image->data[offset+0] = ((uint8_t*)&col)[1];
+ image->data[offset+1] = ((uint8_t*)&col)[0];
+ return LEXLIB_OK;
+ }
+
+ if(image->channels == 3){
+ LexlibColor16 color16 = lexlibColorTo16(color);
+ LexlibColor16 pixel16;
+ uint8_t* color16raw = (uint8_t*)&color16;
+ uint8_t* pixel16raw = (uint8_t*)&pixel16;
+
+ pixel16raw[0] = image->data[offset+1];
+ pixel16raw[1] = image->data[offset+0];
+ pixel16raw[2] = image->data[offset+3];
+ pixel16raw[3] = image->data[offset+2];
+ pixel16raw[4] = image->data[offset+5];
+ pixel16raw[5] = image->data[offset+4];
+ pixel16.a = -1;
+
+ color16 = lexlibColor16Blend(pixel16, color16, blendmode);
+ color16 = lexlibColor16Premultiply(color16);
+
+ image->data[offset+0] = color16raw[1];
+ image->data[offset+1] = color16raw[0];
+ image->data[offset+2] = color16raw[3];
+ image->data[offset+3] = color16raw[2];
+ image->data[offset+4] = color16raw[5];
+ image->data[offset+5] = color16raw[4];
+
+ return LEXLIB_OK;
+ }
+
+ if(image->channels == 4){
+ LexlibColor16 color16 = lexlibColorTo16(color);
+ LexlibColor16 pixel16;
+ uint8_t* color16raw = (uint8_t*)&color16;
+ uint8_t* pixel16raw = (uint8_t*)&pixel16;
+
+ pixel16raw[0] = image->data[offset+1];
+ pixel16raw[1] = image->data[offset+0];
+ pixel16raw[2] = image->data[offset+3];
+ pixel16raw[3] = image->data[offset+2];
+ pixel16raw[4] = image->data[offset+5];
+ pixel16raw[5] = image->data[offset+4];
+ pixel16raw[6] = image->data[offset+7];
+ pixel16raw[7] = image->data[offset+6];
+
+ color16 = lexlibColor16Blend(pixel16, color16, blendmode);
+
+ image->data[offset+0] = color16raw[1];
+ image->data[offset+1] = color16raw[0];
+ image->data[offset+2] = color16raw[3];
+ image->data[offset+3] = color16raw[2];
+ image->data[offset+4] = color16raw[5];
+ image->data[offset+5] = color16raw[4];
+ image->data[offset+6] = color16raw[7];
+ image->data[offset+7] = color16raw[6];
+
+ return LEXLIB_OK;
+ }
+#endif
+ return LEXLIB_INVALID_VALUE;
+ }
+
+ return LEXLIB_ERROR;
}
LexlibImage lexlibImageLoad(const char* filename){
--
GitLab
From 26094243ad13502298fc010cd12986afa357f8a4 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 16:56:11 -0400
Subject: [PATCH 09/64] moved image png functions to its own src file; related
changes
---
CMakeLists.txt | 1 +
include/lexlib/image.h | 3 +
src/image.c | 163 +---------------------------------------
src/image/png.c | 166 +++++++++++++++++++++++++++++++++++++++++
test/colorblend.c | 3 +-
5 files changed, 173 insertions(+), 163 deletions(-)
create mode 100644 src/image/png.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6720ba0..d65c666 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,6 +13,7 @@ target_sources(${PROJECT_NAME} PRIVATE
src/color/colorflt.c
src/file.c
src/image.c
+ src/image/png.c
src/io.c
src/lexlib.c
src/linkedList.c
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index 0524afd..0379a9f 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -34,6 +34,9 @@ typedef struct LexlibImage LexlibImage;
#define LEXLIB_FLIP_X 0x01
#define LEXLIB_FLIP_Y 0x02
+// "constants"
+#define LEXLIB_IMAGE_ZERO ((LexlibImage){NULL, 0, 0, 0, 0})
+
// creates a new LexlibImage and allocates its memory.
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_OUT_OF_MEMORY)
LEXLIB_EXTERN LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uint8_t depth);
diff --git a/src/image.c b/src/image.c
index 3c37aca..e17fb2b 100644
--- a/src/image.c
+++ b/src/image.c
@@ -8,8 +8,6 @@
#include
#include
-#define imageZero {NULL, 0, 0, 0, 0}
-
LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uint8_t depth){
LexlibImage image = {NULL, width, height, 0, depth};
@@ -293,7 +291,7 @@ uint8_t lexlibImagePixelSet(const LexlibImage* image, uint32_t x, uint32_t y, Le
}
LexlibImage lexlibImageLoad(const char* filename){
- LexlibImage image = imageZero;
+ LexlibImage image = LEXLIB_IMAGE_ZERO;
char* offset = strrchr(filename, '.');
if(offset){
@@ -315,163 +313,4 @@ uint8_t lexlibImageSave(const LexlibImage* image, const char* filename){
}
return LEXLIB_INVALID_FILENAME;
-}
-
-LexlibImage lexlibImageLoadPng(const char* filename){
- LexlibImage image = imageZero;
-
- FILE* file = fopen(filename, "rb");
- if(!file){
- image.data = NULL;
- image.depth = LEXLIB_CANT_OPEN;
- return image;
- }
-
- {// check if its a png
- uint8_t head[8];
- fread(head, 1, 8, file);
- bool ispng = !png_sig_cmp(head, 0, 8);
- if(!ispng){
- fclose(file);
- image.data = NULL;
- image.depth = LEXLIB_INVALID_OPERATION;
- return image;
- }
- }
-
- // allocate libpng structs
- png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if(!pngPtr){
- fclose(file);
- image.data = NULL;
- image.depth = LEXLIB_OUT_OF_MEMORY;
- return image;
- }
- png_infop infoPtr = png_create_info_struct(pngPtr);
- if(!infoPtr){
- fclose(file);
- png_destroy_read_struct(&pngPtr, NULL, NULL);
- image.data = NULL;
- image.depth = LEXLIB_OUT_OF_MEMORY;
- return image;
- }
- png_infop endInfo = png_create_info_struct(pngPtr);
- if(!endInfo){
- fclose(file);
- png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
- image.data = NULL;
- image.depth = LEXLIB_OUT_OF_MEMORY;
- return image;
- }
-
- // initial read
- png_init_io(pngPtr, file);
- png_set_sig_bytes(pngPtr, 8);
- png_read_png(pngPtr, infoPtr, 0, NULL);
-
- // read info
- image.width = png_get_image_width(pngPtr, infoPtr);
- image.height = png_get_image_height(pngPtr, infoPtr);
- image.depth = png_get_bit_depth(pngPtr, infoPtr);
- image.channels = png_get_channels(pngPtr, infoPtr);;
- image = lexlibImageNew(image.width, image.height, image.channels, image.depth);
-
- // check for errors
- if(image.data == NULL){
- switch(image.depth){
- case LEXLIB_OUT_OF_MEMORY:
- break;
- default:
- image.depth = LEXLIB_ERROR;
- break;
- }
- fclose(file);
- png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
- return image;
- }
-
- // read data
- png_byte** rowPointers = png_get_rows(pngPtr, infoPtr);
- size_t rowSize = image.width * image.channels * (image.depth / 8);
- size_t offset = 0;
- for(size_t y = 0; y < image.height; y++){
- memcpy(image.data+offset, rowPointers[y], rowSize * sizeof(uint8_t));
- offset += rowSize;
- }
-
- // cleanup and return
- png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
- fclose(file);
- return image;
-}
-
-uint8_t lexlibImageSavePng(const LexlibImage* image, const char* filename){
- // image checks
- if(image->data == NULL)
- return LEXLIB_INVALID_VALUE;
- if(image->width == 0)
- return LEXLIB_INVALID_VALUE;
- if(image->height == 0)
- return LEXLIB_INVALID_VALUE;
- if(image->channels == 0)
- return LEXLIB_INVALID_VALUE;
- if(image->depth == 0)
- return LEXLIB_INVALID_VALUE;
- if((image->depth % 8) != 0)
- return LEXLIB_INVALID_VALUE;
-
- // create file
- FILE* file = fopen(filename, "wb");
- if(!file)
- return LEXLIB_CANT_WRITE;
-
- // allocate libpng structs
- png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if(!pngPtr)
- return LEXLIB_OUT_OF_MEMORY;
- png_infop infoPtr = png_create_info_struct(pngPtr);
- if(!infoPtr){
- png_destroy_write_struct(&pngPtr, NULL);
- return LEXLIB_OUT_OF_MEMORY;
- }
-
- // get color type
- int colorType = 0;
- switch(image->channels){
- case 1:
- colorType = PNG_COLOR_TYPE_GRAY;
- break;
- case 3:
- colorType = PNG_COLOR_TYPE_RGB;
- break;
- case 4:
- colorType = PNG_COLOR_TYPE_RGB_ALPHA;
- break;
- default:
- colorType = PNG_COLOR_TYPE_GRAY;
- }
-
- // set png info
- png_set_IHDR(pngPtr, infoPtr, image->width, image->height, image->depth, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
- png_set_compression_level(pngPtr, 9);
-
- // write png
- png_init_io(pngPtr, file);
- png_write_info(pngPtr, infoPtr);
- png_write_flush(pngPtr);
-
- // write data
- size_t rowSize = image->width * image->channels * (image->depth / 8);
- uint32_t offset = 0;
- for(uint32_t y = 0; y < image->height; y++){
- png_write_row(pngPtr, image->data+offset);
- offset += rowSize;
- }
-
- png_write_end(pngPtr, infoPtr);
-
- // cleanup
- png_destroy_write_struct(&pngPtr, &infoPtr);
- fclose(file);
- return LEXLIB_OK;
}
\ No newline at end of file
diff --git a/src/image/png.c b/src/image/png.c
new file mode 100644
index 0000000..9d13c8e
--- /dev/null
+++ b/src/image/png.c
@@ -0,0 +1,166 @@
+// Copyright 2023 alexevier
+// licensed under the MIT or Apache 2.0 (at your option)
+
+#include
+#include
+#include
+#include
+
+LexlibImage lexlibImageLoadPng(const char* filename){
+ LexlibImage image = LEXLIB_IMAGE_ZERO;
+
+ FILE* file = fopen(filename, "rb");
+ if(!file){
+ image.data = NULL;
+ image.depth = LEXLIB_CANT_OPEN;
+ return image;
+ }
+
+ {// check if its a png
+ uint8_t head[8];
+ fread(head, 1, 8, file);
+ bool ispng = !png_sig_cmp(head, 0, 8);
+ if(!ispng){
+ fclose(file);
+ image.data = NULL;
+ image.depth = LEXLIB_INVALID_OPERATION;
+ return image;
+ }
+ }
+
+ // allocate libpng structs
+ png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if(!pngPtr){
+ fclose(file);
+ image.data = NULL;
+ image.depth = LEXLIB_OUT_OF_MEMORY;
+ return image;
+ }
+ png_infop infoPtr = png_create_info_struct(pngPtr);
+ if(!infoPtr){
+ fclose(file);
+ png_destroy_read_struct(&pngPtr, NULL, NULL);
+ image.data = NULL;
+ image.depth = LEXLIB_OUT_OF_MEMORY;
+ return image;
+ }
+ png_infop endInfo = png_create_info_struct(pngPtr);
+ if(!endInfo){
+ fclose(file);
+ png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
+ image.data = NULL;
+ image.depth = LEXLIB_OUT_OF_MEMORY;
+ return image;
+ }
+
+ // initial read
+ png_init_io(pngPtr, file);
+ png_set_sig_bytes(pngPtr, 8);
+ png_read_png(pngPtr, infoPtr, 0, NULL);
+
+ // read info
+ image.width = png_get_image_width(pngPtr, infoPtr);
+ image.height = png_get_image_height(pngPtr, infoPtr);
+ image.depth = png_get_bit_depth(pngPtr, infoPtr);
+ image.channels = png_get_channels(pngPtr, infoPtr);;
+ image = lexlibImageNew(image.width, image.height, image.channels, image.depth);
+
+ // check for errors
+ if(image.data == NULL){
+ switch(image.depth){
+ case LEXLIB_OUT_OF_MEMORY:
+ break;
+ default:
+ image.depth = LEXLIB_ERROR;
+ break;
+ }
+ fclose(file);
+ png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
+ return image;
+ }
+
+ // read data
+ png_byte** rowPointers = png_get_rows(pngPtr, infoPtr);
+ size_t rowSize = image.width * image.channels * (image.depth / 8);
+ size_t offset = 0;
+ for(size_t y = 0; y < image.height; y++){
+ memcpy(image.data+offset, rowPointers[y], rowSize * sizeof(uint8_t));
+ offset += rowSize;
+ }
+
+ // cleanup and return
+ png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
+ fclose(file);
+ return image;
+}
+
+uint8_t lexlibImageSavePng(const LexlibImage* image, const char* filename){
+ // image checks
+ if(image->data == NULL)
+ return LEXLIB_INVALID_VALUE;
+ if(image->width == 0)
+ return LEXLIB_INVALID_VALUE;
+ if(image->height == 0)
+ return LEXLIB_INVALID_VALUE;
+ if(image->channels == 0)
+ return LEXLIB_INVALID_VALUE;
+ if(image->depth == 0)
+ return LEXLIB_INVALID_VALUE;
+ if((image->depth % 8) != 0)
+ return LEXLIB_INVALID_VALUE;
+
+ // create file
+ FILE* file = fopen(filename, "wb");
+ if(!file)
+ return LEXLIB_CANT_WRITE;
+
+ // allocate libpng structs
+ png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if(!pngPtr)
+ return LEXLIB_OUT_OF_MEMORY;
+ png_infop infoPtr = png_create_info_struct(pngPtr);
+ if(!infoPtr){
+ png_destroy_write_struct(&pngPtr, NULL);
+ return LEXLIB_OUT_OF_MEMORY;
+ }
+
+ // get color type
+ int colorType = 0;
+ switch(image->channels){
+ case 1:
+ colorType = PNG_COLOR_TYPE_GRAY;
+ break;
+ case 3:
+ colorType = PNG_COLOR_TYPE_RGB;
+ break;
+ case 4:
+ colorType = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ default:
+ colorType = PNG_COLOR_TYPE_GRAY;
+ }
+
+ // set png info
+ png_set_IHDR(pngPtr, infoPtr, image->width, image->height, image->depth, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ png_set_compression_level(pngPtr, 9);
+
+ // write png
+ png_init_io(pngPtr, file);
+ png_write_info(pngPtr, infoPtr);
+ png_write_flush(pngPtr);
+
+ // write data
+ size_t rowSize = image->width * image->channels * (image->depth / 8);
+ uint32_t offset = 0;
+ for(uint32_t y = 0; y < image->height; y++){
+ png_write_row(pngPtr, image->data+offset);
+ offset += rowSize;
+ }
+
+ png_write_end(pngPtr, infoPtr);
+
+ // cleanup
+ png_destroy_write_struct(&pngPtr, &infoPtr);
+ fclose(file);
+ return LEXLIB_OK;
+}
\ No newline at end of file
diff --git a/test/colorblend.c b/test/colorblend.c
index f75c9c0..4d59fc9 100644
--- a/test/colorblend.c
+++ b/test/colorblend.c
@@ -9,7 +9,7 @@ void testColorBlend(void){
const char* errmsg = NULL;
#ifdef TEST_PNG
- LexlibImage image = lexlibImageNew(41, 3, LEXLIB_RGBA, 8);
+ LexlibImage image = lexlibImageNew(41, 3, LEXLIB_RGB, 16);
LexlibColor color1 = {0xE5, 0xA4, 0x7C, 0xFF};
LexlibColor color2 = {0x00, 0x00, 0x00, 0xCC};
LexlibColor colorR = {0xFF, 0x00, 0x00, 178};
@@ -24,6 +24,7 @@ void testColorBlend(void){
// reference
// add
lexlibImagePixelSet(&image, col++, row, (LexlibColor){0xB2, 0x00, 0x00, 0xFF}, LEXLIB_NONE);
+ lexlibImagePixelSet(&image, col-1, row, (LexlibColor){0x00, 0xFF, 0x00, 178}, LEXLIB_BLEND);
lexlibImagePixelSet(&image, col++, row, (LexlibColor){0x00, 0xB2, 0x00, 0xFF}, LEXLIB_NONE);
lexlibImagePixelSet(&image, col++, row, (LexlibColor){0x00, 0x00, 0xB2, 0xFF}, LEXLIB_NONE);
lexlibImagePixelSet(&image, col++, row, (LexlibColor){0xB2, 0xB2, 0x00, 0xFF}, LEXLIB_NONE);
--
GitLab
From 91a1d64a15ce71b80df535631c963b41a3ea8dc8 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 17:20:52 -0400
Subject: [PATCH 10/64] added .bpp element to image
---
include/lexlib/image.h | 5 +++--
src/image.c | 10 +++++-----
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index 0379a9f..3720635 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -18,7 +18,8 @@ struct LexlibImage {
uint32_t width;
uint32_t height;
uint8_t channels;
- uint8_t depth;
+ uint8_t depth; /* bits per color */
+ uint8_t bpp; /* bits per pixel */
};
#ifndef __cplusplus
@@ -35,7 +36,7 @@ typedef struct LexlibImage LexlibImage;
#define LEXLIB_FLIP_Y 0x02
// "constants"
-#define LEXLIB_IMAGE_ZERO ((LexlibImage){NULL, 0, 0, 0, 0})
+#define LEXLIB_IMAGE_ZERO ((LexlibImage){NULL, 0, 0, 0, 0, 0})
// creates a new LexlibImage and allocates its memory.
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_OUT_OF_MEMORY)
diff --git a/src/image.c b/src/image.c
index e17fb2b..a16d7c3 100644
--- a/src/image.c
+++ b/src/image.c
@@ -9,7 +9,7 @@
#include
LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uint8_t depth){
- LexlibImage image = {NULL, width, height, 0, depth};
+ LexlibImage image = {NULL, width, height, 0, depth, 0};
// corrections
if(image.depth == 0)
@@ -41,10 +41,10 @@ LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uin
break;
}
- // size of the data
- size_t size = image.depth / 8;
- size *= (image.width * image.height) * image.channels;
- image.data = calloc(size, sizeof(uint8_t));
+ image.bpp = image.channels * image.depth;
+
+ // allocate data
+ image.data = calloc((image.width * image.height) * (image.bpp / 8), sizeof(uint8_t));
if(!image.data){
image.data = NULL;
image.depth = LEXLIB_OUT_OF_MEMORY;
--
GitLab
From 3b7130b5a18ba122924cef61933351957d30c09e Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 17:39:39 -0400
Subject: [PATCH 11/64] 2 new defines and one deprecated deprecated
"LEXLIB_INVALID_FILENAME" in favor of LEXLIB_INVALID_FILE_NAME
---
include/lexlib/defines.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/lexlib/defines.h b/include/lexlib/defines.h
index a98f5e8..f9fab0e 100644
--- a/include/lexlib/defines.h
+++ b/include/lexlib/defines.h
@@ -17,6 +17,8 @@
#define LEXLIB_CANT_OPEN 0x83
#define LEXLIB_CANT_WRITE 0x84
#define LEXLIB_PARTIAL_WRITE 0x85
-#define LEXLIB_INVALID_FILENAME 0x86
+#define LEXLIB_INVALID_FILENAME 0x86 /* DEPRECATED, use LEXLIB_INVALID_FILE_NAME instead */
+#define LEXLIB_INVALID_FILE_NAME 0x86
+#define LEXLIB_INVALID_FILE_TYPE 0x87
#endif
\ No newline at end of file
--
GitLab
From 51ee95531c14062d39effb7cbe1812ef03428221 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 22:33:57 -0400
Subject: [PATCH 12/64] lexlibFileBytes()
---
CHANGELOG.md | 1 +
include/lexlib/file.h | 14 ++++++++++++++
src/file.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index edd2c60..56e9ed2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
## 1.5.0 (under development)
+ function lexlibColor16Blend().
+ function lexlibImagePixelSet().
++ function lexlibFileBytes():
## 1.4.0
+ function lexlibStrCopy().
diff --git a/include/lexlib/file.h b/include/lexlib/file.h
index f6555d7..ba0b0c2 100644
--- a/include/lexlib/file.h
+++ b/include/lexlib/file.h
@@ -5,6 +5,16 @@
#define lexlib_file_h
#include"common.h"
+#include
+#include
+
+struct LexlibBytes {
+ uint8_t* data;
+ size_t count;
+};
+
+typedef struct LexlibBytes LexlibBytes;
+
/// reads a file into a null terminated heap allocated string.
/// returns a valid string on success, NULL on error.
LEXLIB_EXTERN char* lexlibFileToString(const char* filename);
@@ -12,5 +22,9 @@ LEXLIB_EXTERN char* lexlibFileToString(const char* filename);
/// writes a null terminated string into a file.
/// returns LEXLIB_OK on success, LEXLIB_CANT_WRITE, LEXLIB_PARTIAL_WRITE on error.
LEXLIB_EXTERN unsigned int lexlibStringToFile(const char* string, const char* filename);
+
+// reads a file as bytes
+// on error bytes.data will be NULL and the error code is placed in bytes.count (LEXLIB_CANT_OPEN, LEXLIB_ERROR, LEXLIB_OUT_OF_MEMORY, LEXLIB_PARTIAL_READ).
+LEXLIB_EXTERN LexlibBytes lexlibFileBytes(const char* filename);
#endif
\ No newline at end of file
diff --git a/src/file.c b/src/file.c
index 0848e47..c11f94f 100644
--- a/src/file.c
+++ b/src/file.c
@@ -50,4 +50,45 @@ unsigned int lexlibStringToFile(const char* string, const char* filename){
fclose(file);
return LEXLIB_OK;
-}
\ No newline at end of file
+}
+
+LexlibBytes lexlibFileBytes(const char* filename){
+ LexlibBytes bytes = {NULL, 0};
+
+ FILE* file = fopen(filename, "rb");
+ if(!file){
+ bytes.count = LEXLIB_CANT_OPEN;
+ return bytes;
+ }
+
+ if(fseek(file, 0, SEEK_END) != 0){
+ bytes.count = LEXLIB_ERROR;
+ fclose(file);
+ return bytes;
+ }
+ bytes.count = ftell(file);
+
+ if(fseek(file, 0, SEEK_SET) != 0){
+ bytes.count = LEXLIB_ERROR;
+ fclose(file);
+ return bytes;
+ };
+
+ bytes.data = malloc(bytes.count);
+ if(!bytes.data){
+ bytes.count = LEXLIB_OUT_OF_MEMORY;
+ fclose(file);
+ return bytes;
+ }
+
+ if(fread(bytes.data, 1, bytes.count, file) != bytes.count){
+ free(bytes.data);
+ fclose(file);
+ bytes.data = NULL;
+ bytes.count = LEXLIB_PARTIAL_READ;
+ return bytes;
+ }
+
+ fclose(file);
+ return bytes;
+}
--
GitLab
From a3937bf8b2ff1c47732b2927ee7e9a02fdaf4116 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Thu, 11 May 2023 22:36:41 -0400
Subject: [PATCH 13/64] initial support for loading bmp files
---
.gitignore | 1 +
CMakeLists.txt | 1 +
include/lexlib/defines.h | 2 +
include/lexlib/image.h | 4 ++
include/lexlibinternal/bmp.h | 108 +++++++++++++++++++++++++++++++++
resources/plasma16.bmp | Bin 0 -> 582 bytes
resources/plasma24.bmp | Bin 0 -> 822 bytes
resources/plasma32.bmp | Bin 0 -> 1094 bytes
src/image/bmp.c | 113 +++++++++++++++++++++++++++++++++++
test/test.c | 21 ++++++-
10 files changed, 249 insertions(+), 1 deletion(-)
create mode 100644 include/lexlibinternal/bmp.h
create mode 100644 resources/plasma16.bmp
create mode 100644 resources/plasma24.bmp
create mode 100644 resources/plasma32.bmp
create mode 100644 src/image/bmp.c
diff --git a/.gitignore b/.gitignore
index e83bc2c..c22f3de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
build
packages
resources/colorblendtest.png
+resources/out
resources/textFileWrite.txt
resources/pixelDucksOut.png
resources/archPackage/pkg
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d65c666..a5af99d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,6 +13,7 @@ target_sources(${PROJECT_NAME} PRIVATE
src/color/colorflt.c
src/file.c
src/image.c
+ src/image/bmp.c
src/image/png.c
src/io.c
src/lexlib.c
diff --git a/include/lexlib/defines.h b/include/lexlib/defines.h
index f9fab0e..9d0e0f0 100644
--- a/include/lexlib/defines.h
+++ b/include/lexlib/defines.h
@@ -20,5 +20,7 @@
#define LEXLIB_INVALID_FILENAME 0x86 /* DEPRECATED, use LEXLIB_INVALID_FILE_NAME instead */
#define LEXLIB_INVALID_FILE_NAME 0x86
#define LEXLIB_INVALID_FILE_TYPE 0x87
+#define LEXLIB_INVALID_FILE_DATA 0x88
+#define LEXLIB_PARTIAL_READ 0x89
#endif
\ No newline at end of file
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index 3720635..b0a90cd 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -73,6 +73,10 @@ LEXLIB_EXTERN LexlibImage lexlibImageLoad(const char* filename);
// returns LEXLIB_OK on success, nonzero on error. (LEXLIB_INVALID_FILENAME, ... *errors sujected to the actual saver*)
LEXLIB_EXTERN uint8_t lexlibImageSave(const LexlibImage* image, const char* filename);
+// loads a bmp into LexlibImage
+// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_CANT_OPEN, LEXLIB_INVALID_OPERATION, LEXLIB_OUT_OF_MEMORY, LEXLIB_ERROR).
+LEXLIB_EXTERN LexlibImage lexlibImageLoadBmp(const char* filename);
+
// loads a png into LexlibImage
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_CANT_OPEN, LEXLIB_INVALID_OPERATION, LEXLIB_OUT_OF_MEMORY, LEXLIB_ERROR).
LEXLIB_EXTERN LexlibImage lexlibImageLoadPng(const char* filename);
diff --git a/include/lexlibinternal/bmp.h b/include/lexlibinternal/bmp.h
new file mode 100644
index 0000000..02332e1
--- /dev/null
+++ b/include/lexlibinternal/bmp.h
@@ -0,0 +1,108 @@
+#ifndef lexlib_internal_bmpheaders_h
+#define lexlib_internal_bmpheaders_h
+
+#include
+
+// "constants" //
+#define BMP_RGB 0
+#define BMP_RLE8 1
+#define BMP_RLE4 2
+#define BMP_BITFIELDS 3
+#define BMP_JPEG 4
+#define BMP_PNG 5
+#define BMP_ALPHABITFIELDS 6
+#define BMP_CMYK 11
+#define BMP_CMYKRLE8 12
+#define BMP_CMYKRLE4 13
+
+// structs //
+
+#pragma pack(push, 1)
+typedef struct BmpFileHeader {
+ uint16_t type;
+ uint32_t size;
+ uint16_t reserved1;
+ uint16_t reserved2;
+ uint32_t start;
+} BmpFileHeader;
+#pragma pack(pop)
+
+// windows 2.0 or later
+typedef struct BmpCoreHeader {
+ uint32_t size;
+ uint16_t width;
+ uint16_t height;
+ uint16_t planes;
+ uint16_t bitdepth; /* bits per pixel */
+} BmpCoreHeader;
+
+// windows nt, 3.1x or later
+typedef struct BmpInfoHeader {
+ uint32_t size;
+ int32_t width;
+ int32_t height;
+ uint16_t planes;
+ uint16_t bitdepth;
+ uint32_t compression;
+ uint32_t imagesize;
+ int32_t xresm;
+ int32_t yresm;
+ uint32_t colorpalette;
+ uint32_t colorimportant;
+} BmpInfoHeader;
+
+// header 2 and 3 are not documented
+
+// windows nt 4.0, 95
+typedef struct BmpInfoHeader4 {
+ uint32_t size;
+ int32_t width;
+ int32_t height;
+ uint16_t planes;
+ uint16_t bitdepth;
+ uint32_t compression;
+ uint32_t imagesize;
+ int32_t xresm;
+ int32_t yresm;
+ uint32_t colorpalette;
+ uint32_t colorimportant;
+ uint32_t redmask;
+ uint32_t greenmask;
+ uint32_t bluemask;
+ uint32_t alphamask;
+ uint32_t cstype;
+ int32_t endpoint[3][3];// ??
+ uint32_t redgamma;
+ uint32_t greengamma;
+ uint32_t bluegamma;
+} BmpInfoHeader4;
+
+// windows nt 5.0, 98
+typedef struct BmpInfoHeader5 {
+ uint32_t size;
+ int32_t width;
+ int32_t height;
+ uint16_t planes;
+ uint16_t bitdepth;
+ uint32_t compression;
+ uint32_t imagesize;
+ int32_t xresm;
+ int32_t yresm;
+ uint32_t colorpalette;
+ uint32_t colorimportant;
+ uint32_t redmask;
+ uint32_t greenmask;
+ uint32_t bluemask;
+ uint32_t alphamask;
+ uint32_t cstype;
+ int32_t endpoint[3][3];// ??
+ uint32_t redgamma;
+ uint32_t greengamma;
+ uint32_t bluegamma;
+ uint32_t intent;
+ uint32_t profiledata;
+ uint32_t profilesize;
+ uint32_t reserved;
+} BmpInfoHeader5;
+
+#endif
\ No newline at end of file
diff --git a/resources/plasma16.bmp b/resources/plasma16.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..f47a579a85e5ad87dad67ea87fdfa7a861570335
GIT binary patch
literal 582
zcmZ?rbz@=x12+Z+1`7rT1_3B$WDsCr2FWlnFevLmFo+ArKNuJuurn~ogE~g?$YLR#D&?_
z(KW$!a?qxri$Max`oX@zJ;AGkPX=>@sE4?Qw1g}UIT*qaDwHgkY>@1ioSWQ}+?~8C
z`9$*bWVRI66qOXGl*E*VlnKTC#eK!S#cPUJ7q2Q_S$w?sSn<)~BgK!49~D0=W+>rn
z;cek*;cj`={IdB)^YiB8&BvOLHXmtT+`OoHVRJ)s&y?;dSyQ~GXinjn!an8MKfHGPgWmU-Mrd)HPh-ts~T51u3}jAZ11wYse4uTKH1Z<$7K)mp2fS9
zb~Eihw5xHK;;sif8+N9gQ#p6|Z1P#4(DV{obGT|h{$w&8^
z?kU|{bl36j!#j<481F2+t$6$3Eyr6AZYJDhxY=+c;r)Ym3GW`fO?b=jw&4xKn}*j6
SuNz)5ylQyK@Ur0r!wUd{XYgqN
literal 0
HcmV?d00001
diff --git a/resources/plasma24.bmp b/resources/plasma24.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..a788b4fff2154420f165bcae8a214b286f1e351e
GIT binary patch
literal 822
zcmZ?rHDhJ~12YB&1`P%V1_3B$WRL)hGcYqSDCT`BXC4RV2g#o3KxMHAp#u<
z0u==UIW+oVj3DkY8rfM8eD1`Y-$=TDjEzb8Z;^z6e=1dN*V-88aPTC
z7z!E^CQOK#Fd?L8LO{m^kCq7z4HIk{CYaPrFsPWIQ8GcHV1i7+1d*Hx0vQuHQYJ7Y
zObA%8z-P_^j~NRbCM>Y&Szytzz@TA)PR#<1iUkS<3uJN@NMtM!NLauVvw$OF0Ykt7
zhYcHS)@-m?vcY7|27@UZbb2;uv}{nR*`QFdL8f4XM8*b@gbe}_8+ZaXaCmHBaM)mQ
z;DEu713DWHXe>FPGUtH8gaZm42V@!!NR%89$vGg9a6lm908hXH4wnNgHU}6C4k%o>
zpm5@X%$^G}8!kvJxgas)f=JH=k%kKbB^LxTF7U)$;0d_E;c|h);sT4#1qOu+0uLSt
zTzMdH;(@@92Rv&Y@XUF@GvNVG!vl_z2OKF6I3gZ!csyXSdBCFcfJNZ}D2;yj!0_M$
w!-WqF2R<-t_`tB>1H*(53=JO`3O+C-d|(Lpz~JzK!Qcaf!UqO{4-5<+02U!Hd;kCd
literal 0
HcmV?d00001
diff --git a/resources/plasma32.bmp b/resources/plasma32.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..52f2755b2aded28d3b38533d0c4372028f263c16
GIT binary patch
literal 1094
zcmZ?rbz@-w12+Z+1`7rT1_3B$WKdvW2Fb86FevLmFo+Am{}~t{2+aM!z`*c8fPvwH
z0t3SV0|tf-4h#$n0vH%3Brq^E6fiIpG%zqEOkiLLSir#Guz`WW-~a=I!UYBffd>o>
z3?D#x1sJZ#2rwMc5MbD1A;7T0MSx*OhyX)Jf&fEBfdE5JjQ~STj{t+u3;_n46#@(f
zTLc&sjtDRaTo3?hX1JiBz;HxEfnkS<0>cUi1%^333Jg6F3JeV?3Je7W3JfVV3Jf6~
z3Je}o6c{WPC@|=(QDBhSp}-(;L;>vR0|o{RTPzG1RyY_i%<(Z`m=I#X(2!ujP?BN5
zkWpa35L08o5YS@4;4r~}!DNO3gT?{_2AMSm3<6sWz#iV<;J~oL#erdtj|0Pm5C?{q
z7zc)m6bFW!90!Jk5(kEm3I_&{1_uV44hIH<2@VV@GaMKs7C12QtZ)Da)`EZlh8ZCN
z3_TG63=IhZ3>7H>3^^GA3<(7R3=t&(3_cYB3=Rze3>GZ`3_2YF3
z00;Dhgan3;gan3$lmv#7j0A?9oCJo1f&_+$f&_+uk^}~qiUbCmngj-eh6DzUh6DzM
zmIMZojsymto&<0tH53#uR1_326ciLNWE2!IB$N~|M3fXT1e6poc$5?{*i;lSm{b%n
z=u{Lis8kd%$kY@th}0A?@YEE5Be0h~AzCQM+6nJ|GNq-O#{K*t0IkCq7x
z4h<6+Y#JsonAA*QFsPWopiwe`L7`v*gG|8$29cZz3<4Pw7&uZUfD=~0f&~mda~3do
z%viwSFku0MP0s=bi;e{h1`P`sbZQnbXjCj*;)
zz=_gf!v+SMH5(W#mTX`!nX`exV9Evtot_O08Z8?bRBARbC{%1+RCzzN#mzySt>9S0b6HXLBkSaN_tWzGQxg$V~36gmzt$TS>akSIC8
zAd+){K_KA(gFwUq2A+Te3>+>87+7o$fHQ-_g$oP{CoV9^?76@ov*7}R#F7gP5;HC^
zi1b`w5NWu;AW(9FK_KG-15eBa2A+Tm3>+>O7&t60FtF%c0B0nD2M-tot~_86IPri%
zV8;Uno;42`c;-A{;F<7%fv4dC14qdN29A^m3>*;;7&ts0FtFG>U|`XCz`&yL0Fntm
zfHL6+28IhC7#I$GU|`trfq`Mc2L^@-9~c-KJ}@v8d|+Tm_`tvr@PUEB;R6GM!3PEg
Og%1o20-&7#fdK$tmNK>g
literal 0
HcmV?d00001
diff --git a/src/image/bmp.c b/src/image/bmp.c
new file mode 100644
index 0000000..c647df3
--- /dev/null
+++ b/src/image/bmp.c
@@ -0,0 +1,113 @@
+// Copyright 2023 alexevier
+// licensed under the MIT or Apache 2.0 (at your option)
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+/*
+
+> pixel formats
+ 8bpp: index of table 256.
+ 16bpp: ?
+ 24bpp: b,g,r.
+ 32bpp: ?
+*/
+
+LexlibImage lexlibImageLoadBmp(const char* filename){
+ LexlibImage image = LEXLIB_IMAGE_ZERO;
+ LexlibBytes bmp = lexlibFileBytes(filename);
+ if(!bmp.data){
+ printf("bmp: no data.\n");
+ image.depth = bmp.count;
+ return image;
+ }
+ printf("bmp.count: %zu\n", bmp.count);
+
+ printf("BmpFileHeader size: %zu\n", sizeof(BmpFileHeader));
+ printf("BmpCoreHeader size: %zu\n", sizeof(BmpCoreHeader));
+ printf("BmpInfoHeader size: %zu\n", sizeof(BmpInfoHeader));
+ printf("BmpInfoHeader4 size: %zu\n", sizeof(BmpInfoHeader4));
+ printf("BmpInfoHeader5 size: %zu\n", sizeof(BmpInfoHeader5));
+ printf("\n");
+
+ BmpFileHeader* fileheader = (BmpFileHeader*)bmp.data;
+ BmpCoreHeader* coreheader = (BmpCoreHeader*)(bmp.data+14);
+
+ printf("fileheader.type: 0x%X\n", fileheader->type);
+ printf("fileheader.size: %d\n", fileheader->size);
+ printf("fileheader.res1: %d\n", fileheader->reserved1);
+ printf("fileheader.res2: %d\n", fileheader->reserved2);
+ printf("fileheader.stat: %d\n", fileheader->start);
+ printf("\n");
+
+ printf("coreheader might be wrong.\n");
+ printf("coreheader.size : %u\n", coreheader->size);
+ printf("coreheader.width : %d\n", coreheader->width);
+ printf("coreheader.height : %d\n", coreheader->height);
+ printf("coreheader.planes : %d\n", coreheader->planes);
+ printf("coreheader.bitdep : %d\n", coreheader->bitdepth);
+ printf("\n");
+
+ /* check if file is bmp */
+ if(fileheader->type != 0x4D42){
+ printf("bmp: no\n");
+ image.depth = LEXLIB_INVALID_FILE_TYPE;
+ goto bmploadend;
+ }
+
+ // info header
+ if(coreheader->size == 40){
+ BmpInfoHeader* infoheader = (BmpInfoHeader*)coreheader;
+ printf("infoheader.size : %u\n", infoheader->size);
+ printf("infoheader.width : %d\n", infoheader->width);
+ printf("infoheader.height : %d\n", infoheader->height);
+ printf("infoheader.planes : %u\n", infoheader->planes);
+ printf("infoheader.bitdep : %u\n", infoheader->bitdepth);
+ printf("infoheader.compre : %u\n", infoheader->compression);
+ printf("infoheader.imgsiz : %u\n", infoheader->imagesize);
+ printf("infoheader.xresm : %u\n", infoheader->xresm);
+ printf("infoheader.yresm : %u\n", infoheader->yresm);
+ printf("infoheader.clrpa : %u\n", infoheader->colorpalette);
+ printf("infoheader.clrim : %u\n", infoheader->colorimportant);
+
+ uint8_t profile = LEXLIB_RGB;
+ switch(infoheader->bitdepth){
+ case 8:
+ profile = LEXLIB_GRAY;
+ break;
+ case 24:
+ profile = LEXLIB_RGB;
+ break;
+ case 32:
+ profile = LEXLIB_RGBA;
+ break;
+ default:
+ break;
+ }
+
+ image = lexlibImageNew(infoheader->width, infoheader->height, profile, infoheader->bitdepth / 8);
+ size_t bmpoffset = fileheader->start;
+ size_t imgoffset = 0;
+ while(imgoffset < infoheader->imagesize){
+ image.data[imgoffset+0] = bmp.data[bmpoffset+2];
+ image.data[imgoffset+1] = bmp.data[bmpoffset+1];
+ image.data[imgoffset+2] = bmp.data[bmpoffset+0];
+ bmpoffset+=image.channels;
+ imgoffset+=image.channels;
+ }
+ }
+
+ LEXLIB_UNREACHABLE
+
+ bmploadend:
+ if(bmp.data)
+ free(bmp.data);
+ return image;
+}
\ No newline at end of file
diff --git a/test/test.c b/test/test.c
index 405951c..e9eaaba 100644
--- a/test/test.c
+++ b/test/test.c
@@ -3,6 +3,7 @@
#include
#include
+#include
int main(void){
#ifdef __unix__
@@ -27,7 +28,7 @@ int main(void){
testImagePng();
testColorBlend();
testColorGray();
- testColorFlt();
+ // testColorFlt();
// end
unsigned int total = testCountFailed + testCountSuccess;
@@ -41,6 +42,24 @@ int main(void){
}
printf("all tests succeed.\n");
+ {// temp bmp test
+ mkdir("resources/out", 0777);
+ LexlibImage image16 = lexlibImageLoadBmp("resources/plasma16.bmp");
+ if(image16.channels == 0) printf("bmp16 ewwor :(\n");
+ lexlibImageFlip(&image16, LEXLIB_FLIP_Y);
+ lexlibImageSavePng(&image16, "resources/out/plasma16.png");
+
+ LexlibImage image24 = lexlibImageLoadBmp("resources/plasma24.bmp");
+ if(image24.channels == 0) printf("bmp24 ewwor :(\n");
+ lexlibImageFlip(&image24, LEXLIB_FLIP_Y);
+ lexlibImageSavePng(&image24, "resources/out/plasma24.png");
+
+ LexlibImage image32 = lexlibImageLoadBmp("resources/plasma32.bmp");
+ if(image24.channels == 0) printf("bmp32 ewwor :(\n");
+ lexlibImageFlip(&image32, LEXLIB_FLIP_Y);
+ lexlibImageSavePng(&image24, "resources/out/plasma32.png");
+ }
+
return 0;
}
--
GitLab
From 9221d4cca0ee221d98607eb7bc7ecc25558bf31d Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 01:17:07 -0400
Subject: [PATCH 14/64] bmp info header v3
---
include/lexlibinternal/bmp.h | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/include/lexlibinternal/bmp.h b/include/lexlibinternal/bmp.h
index 02332e1..dbeee2c 100644
--- a/include/lexlibinternal/bmp.h
+++ b/include/lexlibinternal/bmp.h
@@ -51,7 +51,26 @@ typedef struct BmpInfoHeader {
uint32_t colorimportant;
} BmpInfoHeader;
-// header 2 and 3 are not documented
+// header 2 is not documented
+
+// https://web.archive.org/web/20150127132443/https://forums.adobe.com/message/3272950#3272950
+typedef struct BmpInfoHeader3 {
+ uint32_t size;
+ int32_t width;
+ int32_t height;
+ uint16_t planes;
+ uint16_t bitdepth;
+ uint32_t compression;
+ uint32_t imagesize;
+ int32_t xresm;
+ int32_t yresm;
+ uint32_t colorpalette;
+ uint32_t colorimportant;
+ uint32_t redbitmask;
+ uint32_t greenbitmask;
+ uint32_t bluebitmask;
+ uint32_t alphabitmask;
+} BmpInfoHeader3;
// windows nt 4.0, 95
typedef struct BmpInfoHeader4 {
--
GitLab
From 4b8e29f4731765fb31dc88ac4297345cf2e75a33 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 02:43:04 -0400
Subject: [PATCH 15/64] working on bmp support
---
include/lexlib/image.h | 10 +++--
src/image.c | 7 ++--
src/image/bmp.c | 90 +++++++++++++++++++++++++++++++++++++++++-
test/test.c | 10 ++++-
4 files changed, 105 insertions(+), 12 deletions(-)
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index b0a90cd..eadb25a 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -20,6 +20,7 @@ struct LexlibImage {
uint8_t channels;
uint8_t depth; /* bits per color */
uint8_t bpp; /* bits per pixel */
+ uint8_t profile;
};
#ifndef __cplusplus
@@ -27,16 +28,17 @@ typedef struct LexlibImage LexlibImage;
#endif
// profiles
-#define LEXLIB_GRAY 0x01
-#define LEXLIB_RGB 0x03
-#define LEXLIB_RGBA 0x04
+#define LEXLIB_GRAY 0x01 /* Gray scale */
+#define LEXLIB_BW 0x02 /* Black White */
+#define LEXLIB_RGB 0x03 /* Red Green Blue */
+#define LEXLIB_RGBA 0x04 /* Red Green Blue Alpha */
// flags
#define LEXLIB_FLIP_X 0x01
#define LEXLIB_FLIP_Y 0x02
// "constants"
-#define LEXLIB_IMAGE_ZERO ((LexlibImage){NULL, 0, 0, 0, 0, 0})
+#define LEXLIB_IMAGE_ZERO ((LexlibImage){NULL, 0, 0, 0, 0, 0, 0})
// creates a new LexlibImage and allocates its memory.
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_OUT_OF_MEMORY)
diff --git a/src/image.c b/src/image.c
index a16d7c3..b02256b 100644
--- a/src/image.c
+++ b/src/image.c
@@ -9,7 +9,7 @@
#include
LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uint8_t depth){
- LexlibImage image = {NULL, width, height, 0, depth, 0};
+ LexlibImage image = {NULL, width, height, 0, depth, 0, profile};
// corrections
if(image.depth == 0)
@@ -24,9 +24,7 @@ LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uin
image.height = 16;
// set profile settings.
- if(profile == 0)
- profile = LEXLIB_RGB;
- switch(profile){
+ switch(image.profile){
case LEXLIB_GRAY:
image.channels = 1;
break;
@@ -37,6 +35,7 @@ LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uin
image.channels = 4;
break;
default:
+ image.profile = LEXLIB_RGB;
image.channels = 3;
break;
}
diff --git a/src/image/bmp.c b/src/image/bmp.c
index c647df3..edb2c9b 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -33,6 +33,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("BmpFileHeader size: %zu\n", sizeof(BmpFileHeader));
printf("BmpCoreHeader size: %zu\n", sizeof(BmpCoreHeader));
printf("BmpInfoHeader size: %zu\n", sizeof(BmpInfoHeader));
+ printf("BmpInfoHeader3 size: %zu\n", sizeof(BmpInfoHeader3));
printf("BmpInfoHeader4 size: %zu\n", sizeof(BmpInfoHeader4));
printf("BmpInfoHeader5 size: %zu\n", sizeof(BmpInfoHeader5));
printf("\n");
@@ -81,20 +82,25 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
switch(infoheader->bitdepth){
case 8:
profile = LEXLIB_GRAY;
+ image.depth = 8;
break;
case 24:
profile = LEXLIB_RGB;
+ image.depth = 8;
break;
case 32:
profile = LEXLIB_RGBA;
+ image.depth = 8;
break;
default:
break;
}
- image = lexlibImageNew(infoheader->width, infoheader->height, profile, infoheader->bitdepth / 8);
+ image = lexlibImageNew(infoheader->width, infoheader->height, profile, image.depth);
size_t bmpoffset = fileheader->start;
size_t imgoffset = 0;
+
+ if(image.profile == LEXLIB_RGB)
while(imgoffset < infoheader->imagesize){
image.data[imgoffset+0] = bmp.data[bmpoffset+2];
image.data[imgoffset+1] = bmp.data[bmpoffset+1];
@@ -102,9 +108,89 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
bmpoffset+=image.channels;
imgoffset+=image.channels;
}
+
+ if(image.profile == LEXLIB_RGBA)
+ while(imgoffset < infoheader->imagesize){
+ image.data[imgoffset+0] = bmp.data[bmpoffset+3];
+ image.data[imgoffset+1] = bmp.data[bmpoffset+2];
+ image.data[imgoffset+2] = bmp.data[bmpoffset+1];
+ image.data[imgoffset+3] = bmp.data[bmpoffset+0];
+ bmpoffset+=image.channels;
+ imgoffset+=image.channels;
+ }
+
+ }
+
+ if(coreheader->size == 56){
+ BmpInfoHeader3* infoheader3 = (BmpInfoHeader3*)coreheader;
+ printf("infoheader3.size : %u\n", infoheader3->size);
+ printf("infoheader3.width : %d\n", infoheader3->width);
+ printf("infoheader3.height : %d\n", infoheader3->height);
+ printf("infoheader3.planes : %u\n", infoheader3->planes);
+ printf("infoheader3.bitdep : %u\n", infoheader3->bitdepth);
+ printf("infoheader3.compre : %u\n", infoheader3->compression);
+ printf("infoheader3.imgsiz : %u\n", infoheader3->imagesize);
+ printf("infoheader3.xresm : %u\n", infoheader3->xresm);
+ printf("infoheader3.yresm : %u\n", infoheader3->yresm);
+ printf("infoheader3.clrpa : %u\n", infoheader3->colorpalette);
+ printf("infoheader3.clrim : %u\n", infoheader3->colorimportant);
+ printf("infoheader3.redbitmask : 0x%.8X\n", infoheader3->redbitmask);
+ printf("infoheader3.greenbitmask : 0x%.8X\n", infoheader3->greenbitmask);
+ printf("infoheader3.bluebitmask : 0x%.8X\n", infoheader3->bluebitmask);
+ printf("infoheader3.alphabitmask : 0x%.8X\n", infoheader3->alphabitmask);
+
+ uint8_t profile = LEXLIB_RGB;
+ uint8_t bmpoffsetextra = 0;
+ switch(infoheader3->bitdepth){
+ case 8:
+ profile = LEXLIB_GRAY;
+ image.depth = 8;
+ break;
+ case 24:
+ profile = LEXLIB_RGB;
+ image.depth = 8;
+ break;
+ case 32:
+ image.depth = 8;
+ if(infoheader3->alphabitmask){
+ profile = LEXLIB_RGBA;
+ } else {
+ profile = LEXLIB_RGB;
+ // infoheader3->imagesize /= 3;
+ infoheader3->imagesize = (infoheader3->width * infoheader3->height) * (24 / 8);
+ printf("infoheader3.imgsiz : %u\n", infoheader3->imagesize);
+ bmpoffsetextra = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ image = lexlibImageNew(infoheader3->width, infoheader3->height, profile, image.depth);
+ size_t bmpoffset = fileheader->start;
+ size_t imgoffset = 0;
+
+ if(image.profile == LEXLIB_RGB)
+ while(imgoffset < infoheader3->imagesize){
+ image.data[imgoffset+0] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->redbitmask) >> 16;
+ image.data[imgoffset+1] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->greenbitmask) >> 8;
+ image.data[imgoffset+2] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->bluebitmask);
+ bmpoffset+=image.channels+bmpoffsetextra;
+ imgoffset+=image.channels;
+ }
+
+ if(image.profile == LEXLIB_RGBA)
+ while(imgoffset < infoheader3->imagesize){
+ image.data[imgoffset+0] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->redbitmask) >> 16;
+ image.data[imgoffset+1] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->greenbitmask) >> 8;
+ image.data[imgoffset+2] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->bluebitmask);
+ image.data[imgoffset+3] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->alphabitmask) >> 24;
+ bmpoffset+=image.channels;
+ imgoffset+=image.channels;
+ }
}
- LEXLIB_UNREACHABLE
+ // LEXLIB_UNREACHABLE
bmploadend:
if(bmp.data)
diff --git a/test/test.c b/test/test.c
index e9eaaba..4846b44 100644
--- a/test/test.c
+++ b/test/test.c
@@ -44,20 +44,26 @@ int main(void){
{// temp bmp test
mkdir("resources/out", 0777);
+ printf("\n[plasma16.bmp]\n");
LexlibImage image16 = lexlibImageLoadBmp("resources/plasma16.bmp");
if(image16.channels == 0) printf("bmp16 ewwor :(\n");
lexlibImageFlip(&image16, LEXLIB_FLIP_Y);
lexlibImageSavePng(&image16, "resources/out/plasma16.png");
+ lexlibImageDelete(&image16);
+ printf("\n[plasma24.bmp]\n");
LexlibImage image24 = lexlibImageLoadBmp("resources/plasma24.bmp");
if(image24.channels == 0) printf("bmp24 ewwor :(\n");
lexlibImageFlip(&image24, LEXLIB_FLIP_Y);
lexlibImageSavePng(&image24, "resources/out/plasma24.png");
+ lexlibImageDelete(&image24);
+ printf("\n[plasma32.bmp]\n");
LexlibImage image32 = lexlibImageLoadBmp("resources/plasma32.bmp");
- if(image24.channels == 0) printf("bmp32 ewwor :(\n");
+ if(image32.channels == 0) printf("bmp32 ewwor :(\n");
lexlibImageFlip(&image32, LEXLIB_FLIP_Y);
- lexlibImageSavePng(&image24, "resources/out/plasma32.png");
+ lexlibImageSavePng(&image32, "resources/out/plasma32.png");
+ lexlibImageDelete(&image32);
}
return 0;
--
GitLab
From e601aa8b912a79dc19ff633c9ba05c2f31717e39 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 04:01:12 -0400
Subject: [PATCH 16/64] documentation in bmp source
---
src/image/bmp.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 41 insertions(+), 5 deletions(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index edb2c9b..5e79483 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -12,14 +12,50 @@
#include
/*
-
+> BMP
+ data is stored as little endian.
+
+> BMP structure
+ File Header | contains information about the file itsef
+ Info Header | contains Info about the bitmap
+ Extra bit masks | defines pixel format | optional
+ Color Table | defines colors used by the bitmap | semi-optional (not if bpp is less than 8)
+ Gap1 | alignment | optional
+ Pixel Array | actual pixel data
+ Gap2 | alignment | optional
+ ICC color profile | defines color profile | optional
+
+> BMP headers
+ all bmp files start with "BM" (0x4D42 in hex 16bits) which
+ is part of a file header (BmpFileHeader).
+
+ information headers.
+ L S
+ ◯ ◯ BmpCoreHeader | 1..24 bpp
+ ◇ ◇ ?? | ?..?? bpp | not sure about which one it is
+ ● ◯ BmpInfoHeader | 1..32 bpp
+ ◇ ◇ BmpInfoHeader2 | ?..?? bpp | not documented | no struct exist
+ ● ◯ BmpInfoHeader3 | ?..?? bpp | not officially documented
+ ◯ ◯ BmpInfoHeader4 | 0..32 bpp
+ ◯ ◯ BmpInfoHeader5 | 0..32 bpp
+
+> Color Table
+ usually the order is bgr0.
+ 4-byte per entry for rgba format.
+ 3-byte per entry for rgb format
+
> pixel formats
- 8bpp: index of table 256.
- 16bpp: ?
- 24bpp: b,g,r.
- 32bpp: ?
+ left-most pixel in the most-significant bit of the first byte.
+ ◯ 1bpp : 2 colors | table
+ ◯ 2bpp : 4 colors | table
+ ◯ 4bpp : 16 colors | table
+ ◯ 8bpp : 256 colors | table
+ ◯ 16bpp: 65536 colors | ?
+ ● 24bpp: 16777216 colors | b,g,r.
+ ● 32bpp: 4294967296 colors | a,b,g,r.
*/
+// TODO probably needs big endian transforms
LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
LexlibBytes bmp = lexlibFileBytes(filename);
--
GitLab
From 807c1bc0bf741f1503ea87f48df5b1c369317eff Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 13:38:43 -0400
Subject: [PATCH 17/64] added element image.datasize
---
include/lexlib/image.h | 3 ++-
src/image.c | 14 ++++++++++++--
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index eadb25a..f558310 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -15,6 +15,7 @@
struct LexlibImage {
uint8_t* data;
+ size_t datasize;
uint32_t width;
uint32_t height;
uint8_t channels;
@@ -38,7 +39,7 @@ typedef struct LexlibImage LexlibImage;
#define LEXLIB_FLIP_Y 0x02
// "constants"
-#define LEXLIB_IMAGE_ZERO ((LexlibImage){NULL, 0, 0, 0, 0, 0, 0})
+#define LEXLIB_IMAGE_ZERO ((LexlibImage){NULL, 0, 0, 0, 0, 0, 0, 0})
// creates a new LexlibImage and allocates its memory.
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_OUT_OF_MEMORY)
diff --git a/src/image.c b/src/image.c
index b02256b..c91aaaf 100644
--- a/src/image.c
+++ b/src/image.c
@@ -9,7 +9,16 @@
#include
LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uint8_t depth){
- LexlibImage image = {NULL, width, height, 0, depth, 0, profile};
+ LexlibImage image = {
+ .data = NULL,
+ .datasize = 0,
+ .width = width,
+ .height = height,
+ .channels = 0,
+ .depth = depth,
+ .bpp = 0,
+ .profile = profile
+ };
// corrections
if(image.depth == 0)
@@ -40,10 +49,11 @@ LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uin
break;
}
+ image.datasize = (image.width * image.height) * (image.bpp / 8);
image.bpp = image.channels * image.depth;
// allocate data
- image.data = calloc((image.width * image.height) * (image.bpp / 8), sizeof(uint8_t));
+ image.data = calloc(image.datasize, sizeof(uint8_t));
if(!image.data){
image.data = NULL;
image.depth = LEXLIB_OUT_OF_MEMORY;
--
GitLab
From 20c6cf73a3b178f7d75f33d7c56eeb33d7de4109 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 15:09:22 -0400
Subject: [PATCH 18/64] fixed image.datasize calculation
---
src/image.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/image.c b/src/image.c
index c91aaaf..df7f216 100644
--- a/src/image.c
+++ b/src/image.c
@@ -49,8 +49,8 @@ LexlibImage lexlibImageNew(uint32_t width, uint32_t height, uint8_t profile, uin
break;
}
- image.datasize = (image.width * image.height) * (image.bpp / 8);
image.bpp = image.channels * image.depth;
+ image.datasize = (image.width * image.height) * (image.bpp / 8);
// allocate data
image.data = calloc(image.datasize, sizeof(uint8_t));
--
GitLab
From 7f51c6b8678294e23a09e783684743273c6e5f6e Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 15:19:43 -0400
Subject: [PATCH 19/64] better bmp rgba32 support
---
resources/macintosh.bmp | Bin 0 -> 822 bytes
resources/macintosh_alpha70.bmp | Bin 0 -> 1094 bytes
src/image/bmp.c | 68 ++++++++++++++++++--------------
test/test.c | 9 ++++-
4 files changed, 47 insertions(+), 30 deletions(-)
create mode 100644 resources/macintosh.bmp
create mode 100644 resources/macintosh_alpha70.bmp
diff --git a/resources/macintosh.bmp b/resources/macintosh.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4360108dfc205bba092a8c9d596236a40f212289
GIT binary patch
literal 822
zcmZ?rHDhJ~12YB&1`P%V1_3B$WRL)hGcYqSDCzp?TEG~@p>jsKr9
z1}S1l`){1~KP~P5%(VY!(m;9`X8tz@nR&+e%$c+^XJ(!Of&XXDFo1NNNdwt=<_yTx
zGYky>jT!!@G5nv&@ITG?%uM4mXN*BkVMse;oOUKH?aa(HkP-jW&M?e8V?6Ur+RQUE
zXM#-p4>AGV{!TkY^Ye&KNVCNn6rDMoiWG&
zhM5cuU^^MWu0~bCz`($b#{h^l12;Ffl9G~(i%V!|XnA>gM@Pr1RjYRI-hKD(-FNTa
Hp&0-G;;&+k
literal 0
HcmV?d00001
diff --git a/resources/macintosh_alpha70.bmp b/resources/macintosh_alpha70.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..348142c192a671bab9b4b0054b20fb8cb75b8bbe
GIT binary patch
literal 1094
zcmZ?rbz@-w12+Z+1`7rT1_3B$WKdvW2Fb86FevLmFo+Am{}~t{2*mxLHuL}HnKS=y
zJ~Q+G=KnMQZ)Q02f3xwK|C`g!{NFtD%>T`2&ivo}|IGi*4FCUcHva#AbK3v^n`i$2
zzxmAn|C|4VXomlr|1Sq
zwEvrDrv2Z1Chh;`|7rg>GtB(I*%)l!na##$&TLLQb7u3*GiNrRIdf+7|1)PcGyFfZ
z+4%pN&1wJ7Y@Yf5%;q!y&usqx|IB6vhX0$58UAlhWB9*$CWtmZvw5cRnayX6&usp0
zd}cF4+L_J9X=gU4rJdP4GwsagGihfw|4%!!nPKLc&Bim&Y)+ebX7kLMXEvXid1mu}
z5PfFm=Kp7AZf5vDbF=aPnVZx8&)huo|IE#2{?FX}|NqR*3=C&B8#A2QoW^iw^Gt>_
zo6j(u+5Dg3%w`7TGn~`JcA=|Npej3=A_j
z8#Bz@oW?M7^Gt@Bo6j)J-29(m=4J-tnVXG`XKqe2p1FCZ@yyLBkXnYQ`N%(Tt_XQpjtIFq*7_)Oa7v@>a&XP!yheCABr=Kp8X
zHZ%NB+iVQBFKx3iL)zvvhP2Hy8PYbNVMyEjpCN5CgK^qsW8<{VX~t=rXBww%K4YA=
z`M+`6W`?x1&BkeIo72+LHqQjnGmSUToN2uI%uM6W|7RL+W;kQK+4zj{=Cm`$n`fRe
z-hAea@#g<$j5jmU^WS*$e-O=Jy!k(a@n!~NcaBPD^9hJTr}9^O-b;&HvLFHZ#m*
z*lawLVRPC{hRri)GHgCGlVS7!nIQ9&HZw4|Y-V5x-ORvHzL|lcV>1K8s?7`xyEij1
z+}+H;@NTm)1HhTROC8SXM{W_Sm(n|m_@1H)!+
zZtl%WN=lnuTwFGXhK6n~FE8KR(b2Ja)v8sSckkZ4`R?7jo8P^Ax0#!PVY3ng!)6x-
PhRvZ244cat7&Zd{ceWYU
literal 0
HcmV?d00001
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 5e79483..d7fe000 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -55,7 +55,7 @@
● 32bpp: 4294967296 colors | a,b,g,r.
*/
-// TODO probably needs big endian transforms
+// TODO probably needs big endian to little transforms on big endian machines
LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
LexlibBytes bmp = lexlibFileBytes(filename);
@@ -84,14 +84,6 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("fileheader.stat: %d\n", fileheader->start);
printf("\n");
- printf("coreheader might be wrong.\n");
- printf("coreheader.size : %u\n", coreheader->size);
- printf("coreheader.width : %d\n", coreheader->width);
- printf("coreheader.height : %d\n", coreheader->height);
- printf("coreheader.planes : %d\n", coreheader->planes);
- printf("coreheader.bitdep : %d\n", coreheader->bitdepth);
- printf("\n");
-
/* check if file is bmp */
if(fileheader->type != 0x4D42){
printf("bmp: no\n");
@@ -174,48 +166,66 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("infoheader3.greenbitmask : 0x%.8X\n", infoheader3->greenbitmask);
printf("infoheader3.bluebitmask : 0x%.8X\n", infoheader3->bluebitmask);
printf("infoheader3.alphabitmask : 0x%.8X\n", infoheader3->alphabitmask);
+ printf("\n");
- uint8_t profile = LEXLIB_RGB;
- uint8_t bmpoffsetextra = 0;
- switch(infoheader3->bitdepth){
+ image.width = infoheader3->width;
+ image.height = infoheader3->height;
+ switch(infoheader3->bitdepth){ /* image.profile & depth */
case 8:
- profile = LEXLIB_GRAY;
+ image.profile = LEXLIB_GRAY;
image.depth = 8;
break;
case 24:
- profile = LEXLIB_RGB;
+ image.profile = LEXLIB_RGB;
image.depth = 8;
break;
case 32:
image.depth = 8;
- if(infoheader3->alphabitmask){
- profile = LEXLIB_RGBA;
- } else {
- profile = LEXLIB_RGB;
- // infoheader3->imagesize /= 3;
- infoheader3->imagesize = (infoheader3->width * infoheader3->height) * (24 / 8);
- printf("infoheader3.imgsiz : %u\n", infoheader3->imagesize);
- bmpoffsetextra = 1;
- }
+ image.profile = LEXLIB_RGBA;
break;
default:
break;
}
- image = lexlibImageNew(infoheader3->width, infoheader3->height, profile, image.depth);
+ image = lexlibImageNew(image.width, image.height, image.profile, image.depth);
+
size_t bmpoffset = fileheader->start;
size_t imgoffset = 0;
+ uint64_t pixelcount = image.width * image.height;
+ uint8_t profile = image.profile;
- if(image.profile == LEXLIB_RGB)
- while(imgoffset < infoheader3->imagesize){
+ if(profile == LEXLIB_RGBA){
+ if(infoheader3->alphabitmask){
+ profile = LEXLIB_RGBA;
+ } else {
+ profile = LEXLIB_RGB;
+ }
+ }
+
+ printf("profile: %u\n", profile);
+ printf("pixelco: %zu\n", pixelcount);
+ printf("\n");
+
+ printf("image.datasize: %zu\n", image.datasize);
+ printf("image.width : %u\n", image.width);
+ printf("image.height : %u\n", image.height);
+ printf("image.channels: %u\n", image.channels);
+ printf("image.depth : %u\n", image.depth);
+ printf("image.bpp : %u\n", image.bpp);
+ printf("image.profile : %u\n", image.profile);
+ printf("\n");
+
+ if(profile == LEXLIB_RGB)
+ for(uint64_t i = 0; i < pixelcount; i++){
image.data[imgoffset+0] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->redbitmask) >> 16;
image.data[imgoffset+1] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->greenbitmask) >> 8;
image.data[imgoffset+2] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->bluebitmask);
- bmpoffset+=image.channels+bmpoffsetextra;
- imgoffset+=image.channels;
+ if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
+ bmpoffset += image.channels;
+ imgoffset += image.channels;
}
- if(image.profile == LEXLIB_RGBA)
+ if(profile == LEXLIB_RGBA)
while(imgoffset < infoheader3->imagesize){
image.data[imgoffset+0] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->redbitmask) >> 16;
image.data[imgoffset+1] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->greenbitmask) >> 8;
diff --git a/test/test.c b/test/test.c
index 4846b44..a472430 100644
--- a/test/test.c
+++ b/test/test.c
@@ -64,8 +64,15 @@ int main(void){
lexlibImageFlip(&image32, LEXLIB_FLIP_Y);
lexlibImageSavePng(&image32, "resources/out/plasma32.png");
lexlibImageDelete(&image32);
- }
+ printf("\n[macintosh_a70.bmp]\n");
+ image32 = lexlibImageLoadBmp("resources/macintosh_alpha70.bmp");
+ if(image32.channels == 0) printf("mac_a32 ewwor :(\n");
+ lexlibImageFlip(&image32, LEXLIB_FLIP_Y);
+ lexlibImageSavePng(&image32, "resources/out/macintosh_alpha70.png");
+ lexlibImageDelete(&image32);
+ }
+ printf("s: %zu\n",sizeof(LexlibImage));
return 0;
}
--
GitLab
From c1edb584cc1d6bbe16bf0de13a4c0292acc8fb60 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 19:04:58 -0400
Subject: [PATCH 20/64] bmp bit masks and shifts detection
---
include/lexlib/image.h | 24 ++++++++
src/image/bmp.c | 121 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 139 insertions(+), 6 deletions(-)
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index f558310..e7cf228 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -10,6 +10,25 @@
/* NOTE s
images with more bitdepth than 8 are bigendian.
+
+> Image file formats
+ L S M
+ ● ◯ ◆ bmp
+ ◯ ◯ ◯ gif
+ ◯ ◯ ◯ jpg
+ ● ● ◯ png | libpng and zlib required
+ ◯ ◯ ◯ webp
+
+> Color profiles
+ lexlib images work directly only with certain color profiles in the R.G.B.A order.
+ any loading or saving with a profile the image doesn't work directly results in a conversion.
+ ● GRAY
+ ◯ BW (black white)
+ ● RGB
+ ● RGBA
+ ● RGB24
+ ▽ RGB555
+ ▽ RGB565
*/
@@ -34,6 +53,11 @@ typedef struct LexlibImage LexlibImage;
#define LEXLIB_RGB 0x03 /* Red Green Blue */
#define LEXLIB_RGBA 0x04 /* Red Green Blue Alpha */
+#define LEXLIB_RGB24 0x03 /* R.G.B.A.X: 8.8.8.0.0 */
+#define LEXLIB_RGB555 0x05 /* R.G.B.A.X: 5.5.5.0.1 */
+#define LEXLIB_RGB565 0x06 /* R.G.B.A.X: 5.6.5.0.0 */
+
+
// flags
#define LEXLIB_FLIP_X 0x01
#define LEXLIB_FLIP_Y 0x02
diff --git a/src/image/bmp.c b/src/image/bmp.c
index d7fe000..61020f0 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -7,6 +7,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -55,6 +57,25 @@
● 32bpp: 4294967296 colors | a,b,g,r.
*/
+// get an individual bit
+LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index);
+
+// to store bitmasks and shifts
+typedef struct ColorBitMask {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+ uint8_t alpha;
+ uint32_t redbit;
+ uint32_t greenbit;
+ uint32_t bluebit;
+ uint32_t alphabit;
+ uint8_t redshift;
+ uint8_t greenshift;
+ uint8_t blueshift;
+ uint8_t alphashift;
+} ColorBitMask;
+
// TODO probably needs big endian to little transforms on big endian machines
LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
@@ -168,6 +189,52 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("infoheader3.alphabitmask : 0x%.8X\n", infoheader3->alphabitmask);
printf("\n");
+ size_t bmpoffset = fileheader->start;
+ size_t imgoffset = 0;
+ uint64_t pixelcount = 0;
+ uint8_t profile = 0;
+ ColorBitMask colormask = {
+ .red = 0,
+ .green = 0,
+ .blue = 0,
+ .alpha = 0,
+ .redbit = infoheader3->redbitmask,
+ .greenbit = infoheader3->greenbitmask,
+ .bluebit = infoheader3->bluebitmask,
+ .alphabit = infoheader3->alphabitmask,
+ .redshift = 0,
+ .greenshift = 0,
+ .blueshift = 0,
+ .alphashift = 0,
+ };
+
+ for(uint8_t i = 0; i < 32; i++){
+ colormask.red += bitGet(colormask.redbit, i);
+ colormask.green += bitGet(colormask.greenbit, i);
+ colormask.blue += bitGet(colormask.bluebit, i);
+ colormask.alpha += bitGet(colormask.alphabit, i);
+ }
+
+ // get bit shifts
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colormask.redbit, i) == 0)
+ colormask.redshift++;
+ else
+ break;
+ }
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colormask.greenbit, i) == 0)
+ colormask.greenshift++;
+ else
+ break;
+ }
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colormask.bluebit, i) == 0)
+ colormask.blueshift++;
+ else
+ break;
+ }
+
image.width = infoheader3->width;
image.height = infoheader3->height;
switch(infoheader3->bitdepth){ /* image.profile & depth */
@@ -175,9 +242,19 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.profile = LEXLIB_GRAY;
image.depth = 8;
break;
+ case 16:
+ image.depth = 8;
+ if(infoheader3->alphabitmask){
+ image.profile = LEXLIB_RGBA;
+ profile = LEXLIB_RGB555;
+ } else {
+ image.profile = LEXLIB_RGB;
+ profile = LEXLIB_RGB555;
+ }
+ break;
case 24:
- image.profile = LEXLIB_RGB;
image.depth = 8;
+ image.profile = LEXLIB_RGB;
break;
case 32:
image.depth = 8;
@@ -189,10 +266,9 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image = lexlibImageNew(image.width, image.height, image.profile, image.depth);
- size_t bmpoffset = fileheader->start;
- size_t imgoffset = 0;
- uint64_t pixelcount = image.width * image.height;
- uint8_t profile = image.profile;
+ pixelcount = image.width * image.height;
+ if(!profile)
+ profile = image.profile;
if(profile == LEXLIB_RGBA){
if(infoheader3->alphabitmask){
@@ -204,6 +280,13 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("profile: %u\n", profile);
printf("pixelco: %zu\n", pixelcount);
+ printf("colormask.red: %u\n", colormask.red);
+ printf("colormask.green: %u\n", colormask.green);
+ printf("colormask.blue: %u\n", colormask.blue);
+ printf("colormask.alpha: %u\n", colormask.alpha);
+ printf("colormask.redshift : %u\n", colormask.redshift);
+ printf("colormask.greenshift: %u\n", colormask.greenshift);
+ printf("colormask.blueshift : %u\n", colormask.blueshift);
printf("\n");
printf("image.datasize: %zu\n", image.datasize);
@@ -215,6 +298,25 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("image.profile : %u\n", image.profile);
printf("\n");
+ unsigned yes = 0;
+ for(unsigned i = 0; i < 32; i++){
+ yes += bitGet(infoheader3->bluebitmask, i);
+ }
+ printf("yes: %d\n", yes);
+
+ if(profile == LEXLIB_RGB555)
+ for(uint64_t i = 0; i < pixelcount; i++){
+ uint16_t bmppixel = *((uint16_t*)(bmp.data+bmpoffset));
+
+ image.data[imgoffset+0] = rintf(( ((bmppixel & colormask.redbit) >> colormask.redshift) / 31.0f) * 255.0f);
+ image.data[imgoffset+1] = rintf(( ((bmppixel & colormask.greenbit) >> colormask.greenshift) / 63.0f) * 255.0f);
+ image.data[imgoffset+2] = rintf(( ((bmppixel & colormask.bluebit) >> colormask.blueshift) / 31.0f) * 255.0f);
+
+ bmpoffset += 2;
+ imgoffset += image.channels;
+ }
+
+
if(profile == LEXLIB_RGB)
for(uint64_t i = 0; i < pixelcount; i++){
image.data[imgoffset+0] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->redbitmask) >> 16;
@@ -242,4 +344,11 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
if(bmp.data)
free(bmp.data);
return image;
-}
\ No newline at end of file
+}
+
+
+#define UNSIGNED_BIT_WIDTH (CHAR_BIT * sizeof(unsigned))
+LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index){
+ index %= UNSIGNED_BIT_WIDTH;
+ return (x >> index) & 1;
+}
--
GitLab
From 61dc3065389669f1f761f74b03525dd54cb4bfba Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 19:59:22 -0400
Subject: [PATCH 21/64] bmp 16bit RGB555 and RGB565 support
---
include/lexlib/defines.h | 1 +
resources/macintosh_8bpp.bmp | Bin 0 -> 1334 bytes
src/image/bmp.c | 99 ++++++++++++++++++-----------------
test/test.c | 9 +++-
4 files changed, 60 insertions(+), 49 deletions(-)
create mode 100644 resources/macintosh_8bpp.bmp
diff --git a/include/lexlib/defines.h b/include/lexlib/defines.h
index 9d0e0f0..be6a49e 100644
--- a/include/lexlib/defines.h
+++ b/include/lexlib/defines.h
@@ -22,5 +22,6 @@
#define LEXLIB_INVALID_FILE_TYPE 0x87
#define LEXLIB_INVALID_FILE_DATA 0x88
#define LEXLIB_PARTIAL_READ 0x89
+#define LEXLIB_UNSUPORTED 0x8A
#endif
\ No newline at end of file
diff --git a/resources/macintosh_8bpp.bmp b/resources/macintosh_8bpp.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..e2f88c6f29e89bb8e4339ef3db0bb3c0d6681240
GIT binary patch
literal 1334
zcmZ?rHDhG}12Yx|1`P%V1_3B$WZ(dcGcYnRDCC1H%~x28RD2JB%3^jExx>(u^4xW*Rdv
zoH1r#_zzWRoW{VAmd3y^GmU}aOd12jf2d~TnG6hRGZ`3W&SYRXGn0YgKh!|uGYkxA
zXBZe}o?&1(bB2N8KhzTA{|pRi{}~u&{%2q~^Php?Kh$Dl24jXa24jYq48{y+7>pVI
zGe8_;Y;4SsW^Bwb)7Y5djIlApf2aeE(~KF?(u^5qrWrGwNi$~n4|TNhOk;+$nZ^t=
zXBsn{nQ6@MALW*Vn4oH0&g_zw*j_zw+0<1=XtX=lPGn3&zG%}6<&typZKa*kR|CtPD{?BCi4~<|@EP+A>@8mOvo`a?O8GiZ=ewU~K%KAAg
zpW#0=Q5w(u&yY6rKf}zK{~6BA{Lk!9$0S96fgY#K}{q&zwDXe#6F1o40J;wtdIWUAy<}
z-M4?i!bOXhEM2yI#mZHy*Q{N)e!|2_lc!9bHhsp-S+nQNoj1Rsv8lPGwXMCQv#YzO
zx39mTu&B7Cw5+_MvZ}hKwyr)QF)2AEH7z|OGb=kMH!nXRFeo@AG%P$KGAcSIHZI=5
z(aAZ()y>_*)63h(*U#U;(8$=t)Xdz%(#qP#*3Mo*QAt@vRZU$(Q%hS%S5IF+P)Jxr
fR7_k#Qc7AzR!*LQk%^gwm5rT)lZ%^&myaI+hZ*81
literal 0
HcmV?d00001
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 61020f0..161f65f 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -87,14 +87,6 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
}
printf("bmp.count: %zu\n", bmp.count);
- printf("BmpFileHeader size: %zu\n", sizeof(BmpFileHeader));
- printf("BmpCoreHeader size: %zu\n", sizeof(BmpCoreHeader));
- printf("BmpInfoHeader size: %zu\n", sizeof(BmpInfoHeader));
- printf("BmpInfoHeader3 size: %zu\n", sizeof(BmpInfoHeader3));
- printf("BmpInfoHeader4 size: %zu\n", sizeof(BmpInfoHeader4));
- printf("BmpInfoHeader5 size: %zu\n", sizeof(BmpInfoHeader5));
- printf("\n");
-
BmpFileHeader* fileheader = (BmpFileHeader*)bmp.data;
BmpCoreHeader* coreheader = (BmpCoreHeader*)(bmp.data+14);
@@ -207,7 +199,14 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
.blueshift = 0,
.alphashift = 0,
};
+ LexlibColorFlt colormax = {
+ .r = 255.0f,
+ .g = 255.0f,
+ .b = 255.0f,
+ .a = 255.0f,
+ };
+ // get R.G.B.A
for(uint8_t i = 0; i < 32; i++){
colormask.red += bitGet(colormask.redbit, i);
colormask.green += bitGet(colormask.greenbit, i);
@@ -235,41 +234,48 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
break;
}
- image.width = infoheader3->width;
- image.height = infoheader3->height;
- switch(infoheader3->bitdepth){ /* image.profile & depth */
- case 8:
- image.profile = LEXLIB_GRAY;
- image.depth = 8;
- break;
- case 16:
- image.depth = 8;
- if(infoheader3->alphabitmask){
- image.profile = LEXLIB_RGBA;
- profile = LEXLIB_RGB555;
- } else {
- image.profile = LEXLIB_RGB;
- profile = LEXLIB_RGB555;
- }
- break;
- case 24:
- image.depth = 8;
- image.profile = LEXLIB_RGB;
- break;
- case 32:
- image.depth = 8;
+ // set the color profile
+ if(infoheader3->bitdepth == 8){
+ image.profile = LEXLIB_GRAY;
+ image.depth = 8;
+ profile = LEXLIB_GRAY;
+ }
+ if(infoheader3->bitdepth == 16){
+ image.depth = 8;
+ if(colormask.alpha)
image.profile = LEXLIB_RGBA;
- break;
- default:
- break;
+ if(colormask.green == 5){
+ profile = LEXLIB_RGB555;
+ colormax.r = 31.0f;
+ colormax.g = 31.0f;
+ colormax.b = 31.0f;
+ colormax.a = 0.0f;
+ }
+ if(colormask.green == 6){
+ profile = LEXLIB_RGB565;
+ colormax.r = 31.0f;
+ colormax.g = 63.0f;
+ colormax.b = 31.0f;
+ colormax.a = 0.0f;
+ }
+ }
+ if(infoheader3->bitdepth == 24){
+ image.depth = 8;
+ image.profile = LEXLIB_RGB;
+ profile = LEXLIB_RGB;
+ }
+ if(infoheader3->bitdepth == 32){
+ image.depth = 8;
+ image.profile = LEXLIB_RGBA;
+ profile = LEXLIB_RGBA;
}
- image = lexlibImageNew(image.width, image.height, image.profile, image.depth);
-
+ image = lexlibImageNew(infoheader3->width, infoheader3->height, image.profile, image.depth);
pixelcount = image.width * image.height;
+
+ // check for the correct bmp profile
if(!profile)
profile = image.profile;
-
if(profile == LEXLIB_RGBA){
if(infoheader3->alphabitmask){
profile = LEXLIB_RGBA;
@@ -298,24 +304,19 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("image.profile : %u\n", image.profile);
printf("\n");
- unsigned yes = 0;
- for(unsigned i = 0; i < 32; i++){
- yes += bitGet(infoheader3->bluebitmask, i);
- }
- printf("yes: %d\n", yes);
-
- if(profile == LEXLIB_RGB555)
+ if(profile == LEXLIB_RGB555 || profile == LEXLIB_RGB565)
for(uint64_t i = 0; i < pixelcount; i++){
uint16_t bmppixel = *((uint16_t*)(bmp.data+bmpoffset));
- image.data[imgoffset+0] = rintf(( ((bmppixel & colormask.redbit) >> colormask.redshift) / 31.0f) * 255.0f);
- image.data[imgoffset+1] = rintf(( ((bmppixel & colormask.greenbit) >> colormask.greenshift) / 63.0f) * 255.0f);
- image.data[imgoffset+2] = rintf(( ((bmppixel & colormask.bluebit) >> colormask.blueshift) / 31.0f) * 255.0f);
+ image.data[imgoffset+0] = rintf(( ((bmppixel & colormask.redbit) >> colormask.redshift) / colormax.r) * 255.0f);
+ image.data[imgoffset+1] = rintf(( ((bmppixel & colormask.greenbit) >> colormask.greenshift) / colormax.g) * 255.0f);
+ image.data[imgoffset+2] = rintf(( ((bmppixel & colormask.bluebit) >> colormask.blueshift) / colormax.b) * 255.0f);
+ if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
bmpoffset += 2;
imgoffset += image.channels;
}
-
+
if(profile == LEXLIB_RGB)
for(uint64_t i = 0; i < pixelcount; i++){
@@ -323,6 +324,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.data[imgoffset+1] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->greenbitmask) >> 8;
image.data[imgoffset+2] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->bluebitmask);
if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
+
bmpoffset += image.channels;
imgoffset += image.channels;
}
@@ -333,6 +335,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.data[imgoffset+1] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->greenbitmask) >> 8;
image.data[imgoffset+2] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->bluebitmask);
image.data[imgoffset+3] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->alphabitmask) >> 24;
+
bmpoffset+=image.channels;
imgoffset+=image.channels;
}
diff --git a/test/test.c b/test/test.c
index a472430..25a1010 100644
--- a/test/test.c
+++ b/test/test.c
@@ -71,8 +71,15 @@ int main(void){
lexlibImageFlip(&image32, LEXLIB_FLIP_Y);
lexlibImageSavePng(&image32, "resources/out/macintosh_alpha70.png");
lexlibImageDelete(&image32);
+
+ printf("\n[macintosh_8bpp.bmp]\n");
+ LexlibImage image8 = lexlibImageLoadBmp("resources/macintosh_8bpp.bmp");
+ if(image8.channels == 0) printf("mac_bpp8 ewwor :(\n");
+ lexlibImageFlip(&image8, LEXLIB_FLIP_Y);
+ lexlibImageSavePng(&image8, "resources/out/macintosh_8bpp.png");
+ lexlibImageDelete(&image8);
}
- printf("s: %zu\n",sizeof(LexlibImage));
+ // printf("s: %zu\n",sizeof(LexlibImage));
return 0;
}
--
GitLab
From ba86c5ea332f01b7dd2a33ce6c1172c46ae711b6 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 22:57:05 -0400
Subject: [PATCH 22/64] added credits for plasma.bmp and macintosh.bmp
---
CREDITS | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/CREDITS b/CREDITS
index 642947d..b6d42f3 100644
--- a/CREDITS
+++ b/CREDITS
@@ -17,6 +17,14 @@ Credits for the libraries/resources/tools used by lexlib.
[notes]: lexlib does not provide any code from libpng thus it needs to be linked separately.
[used]: for optionally supporting the png image format.
+> macintosh.bmp (resource)
+[description]: The default System palette stored in the ROM BIOS of various classic Macintosh computer systems.
+[source]: https://lospec.com/palette-list/macintosh-8-bit-system-palette
+[notes]: the colors in the file were taken from the color palette in lospec published by vga256.
+
+> plasma.bmp (resource)
+[source]: the default "plasma" GIMP color palette.
+
> zlib (lib)
[license]: https://www.zlib.net/zlib_license.html
[copyright]: (C) 1995-2022 Jean-loup Gailly and Mark Adler
--
GitLab
From 522cb67b5010a0c5de213b3039134c5b7822a260 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 23:44:31 -0400
Subject: [PATCH 23/64] added comments to bmp headers
---
include/lexlibinternal/bmp.h | 107 +++++++++++++++++++++++++++++++----
1 file changed, 96 insertions(+), 11 deletions(-)
diff --git a/include/lexlibinternal/bmp.h b/include/lexlibinternal/bmp.h
index dbeee2c..7b238e2 100644
--- a/include/lexlibinternal/bmp.h
+++ b/include/lexlibinternal/bmp.h
@@ -1,3 +1,7 @@
+// 2023 alexevier
+// This is free and unencumbered software released into the public domain.
+// free to copy, modify, publish, use, compile, sell, or distribute for any purpose, commercial or non-commercial.
+
#ifndef lexlib_internal_bmpheaders_h
#define lexlib_internal_bmpheaders_h
@@ -19,35 +23,57 @@
#pragma pack(push, 1)
typedef struct BmpFileHeader {
+ // file type, should be "BM"
uint16_t type;
+ // size in bytes of the file
uint32_t size;
+ // set'd by generating program, generally 0
uint16_t reserved1;
uint16_t reserved2;
+ // offset in bytes where the bitmap data starts
uint32_t start;
+ // used for reading the size of the info header; this element is not official in the spec
+ uint32_t infoHeaderSize;
} BmpFileHeader;
#pragma pack(pop)
// windows 2.0 or later
typedef struct BmpCoreHeader {
+ // size of the header
uint32_t size;
+ // bitmap width in pixels
uint16_t width;
+ // bitmap height in pixels
uint16_t height;
+ // number of color planes (must be 1)
uint16_t planes;
- uint16_t bitdepth; /* bits per pixel */
+ // number of bits per pixel
+ uint16_t bitdepth;
} BmpCoreHeader;
// windows nt, 3.1x or later
typedef struct BmpInfoHeader {
+ // size of the header
uint32_t size;
+ // bitmap width in pixels
int32_t width;
+ // bitmap height in pixels
int32_t height;
+ // number of color planes (must be 1)
uint16_t planes;
+ // number of bits per pixel
uint16_t bitdepth;
+ // compression method
uint32_t compression;
+ // raw size of the bitmap data
uint32_t imagesize;
+ // horizontal resolution, in pixels per meter
int32_t xresm;
+ // vertical resolution, in pixels per meter
int32_t yresm;
+ // number of color indices in the color table
uint32_t colorpalette;
+ // number of color indices that are considered important, if zero all are important
uint32_t colorimportant;
} BmpInfoHeader;
@@ -55,72 +81,131 @@ typedef struct BmpInfoHeader {
// https://web.archive.org/web/20150127132443/https://forums.adobe.com/message/3272950#3272950
typedef struct BmpInfoHeader3 {
+ // size of the header
uint32_t size;
+ // bitmap width in pixels
int32_t width;
+ // bitmap height in pixels
int32_t height;
+ // number of color planes (must be 1)
uint16_t planes;
+ // number of bits per pixel
uint16_t bitdepth;
+ // compression method
uint32_t compression;
+ // raw size of the bitmap data
uint32_t imagesize;
+ // horizontal resolution, in pixels per meter
int32_t xresm;
+ // vertical resolution, in pixels per meter
int32_t yresm;
+ // number of color indices in the color table
uint32_t colorpalette;
+ // number of color indices that are considered important, if zero all are important
uint32_t colorimportant;
+ // red color per pixel bit mask
uint32_t redbitmask;
+ // green color per pixel bit mask
uint32_t greenbitmask;
+ // blue color per pixel bit mask
uint32_t bluebitmask;
+ // alpha color per pixel bit mask
uint32_t alphabitmask;
} BmpInfoHeader3;
// windows nt 4.0, 95
typedef struct BmpInfoHeader4 {
+ // size of the header
uint32_t size;
+ // bitmap width in pixels
int32_t width;
+ // bitmap height in pixels
int32_t height;
+ // number of color planes (must be 1)
uint16_t planes;
+ // number of bits per pixel
uint16_t bitdepth;
+ // compression method
uint32_t compression;
+ // raw size of the bitmap data
uint32_t imagesize;
+ // horizontal resolution, in pixels per meter
int32_t xresm;
+ // vertical resolution, in pixels per meter
int32_t yresm;
+ // number of color indices in the color table
uint32_t colorpalette;
+ // number of color indices that are considered important, if zero all are important.
uint32_t colorimportant;
- uint32_t redmask;
- uint32_t greenmask;
- uint32_t bluemask;
- uint32_t alphamask;
+ // red color per pixel bit mask
+ uint32_t redbitmask;
+ // green color per pixel bit mask
+ uint32_t greenbitmask;
+ // blue color per pixel bit mask
+ uint32_t bluebitmask;
+ // alpha color per pixel bit mask
+ uint32_t alphabitmask;
+ // color space
uint32_t cstype;
- int32_t endpoint[3][3];// ??
+ // specifies the x, y, and z coordinates of the three colors that correspond to the red, green, and blue endpoints
+ int32_t endpoint[3][3]; /* this type is wrong */
+ // Tone response curve for red
uint32_t redgamma;
+ // Tone response curve for green
uint32_t greengamma;
+ // Tone response curve for blue
uint32_t bluegamma;
} BmpInfoHeader4;
// windows nt 5.0, 98
typedef struct BmpInfoHeader5 {
+ // size of the header
uint32_t size;
+ // bitmap width in pixels
int32_t width;
+ // bitmap height in pixels
int32_t height;
+ // number of color planes (must be 1)
uint16_t planes;
+ // number of bits per pixel
uint16_t bitdepth;
+ // compression method
uint32_t compression;
+ // raw size of the bitmap data
uint32_t imagesize;
+ // horizontal resolution, in pixels per meter
int32_t xresm;
+ // vertical resolution, in pixels per meter
int32_t yresm;
+ // number of color indices in the color table
uint32_t colorpalette;
+ // number of color indices that are considered important, if zero all are important
uint32_t colorimportant;
- uint32_t redmask;
- uint32_t greenmask;
- uint32_t bluemask;
- uint32_t alphamask;
+ // red color per pixel bit mask
+ uint32_t redbitmask;
+ // green color per pixel bit mask
+ uint32_t greenbitmask;
+ // blue color per pixel bit mask
+ uint32_t bluebitmask;
+ // alpha color per pixel bit mask
+ uint32_t alphabitmask;
+ // color space
uint32_t cstype;
- int32_t endpoint[3][3];// ??
+ // specifies the x, y, and z coordinates of the three colors that correspond to the red, green, and blue endpoints
+ int32_t endpoint[3][3]; /* this type is wrong */
+ // Tone response curve for red.
uint32_t redgamma;
+ // Tone response curve for green
uint32_t greengamma;
+ // Tone response curve for blue
uint32_t bluegamma;
+ // Rendering intent for bitmap
uint32_t intent;
+ // offset in bytes from the beginning of the header to the start of profile data
uint32_t profiledata;
+ // size of the embedded profile data
uint32_t profilesize;
+ // value should be set to zero
uint32_t reserved;
} BmpInfoHeader5;
--
GitLab
From 312b910f9765df439370f74a0aa9670cdac08360 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Fri, 12 May 2023 23:45:21 -0400
Subject: [PATCH 24/64] using BmpFileHeader.infoHeaderSize
---
src/image/bmp.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 161f65f..c5cd029 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -88,13 +88,13 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("bmp.count: %zu\n", bmp.count);
BmpFileHeader* fileheader = (BmpFileHeader*)bmp.data;
- BmpCoreHeader* coreheader = (BmpCoreHeader*)(bmp.data+14);
printf("fileheader.type: 0x%X\n", fileheader->type);
printf("fileheader.size: %d\n", fileheader->size);
printf("fileheader.res1: %d\n", fileheader->reserved1);
printf("fileheader.res2: %d\n", fileheader->reserved2);
printf("fileheader.stat: %d\n", fileheader->start);
+ printf("fileheader.ihds: %d\n", fileheader->infoHeaderSize);
printf("\n");
/* check if file is bmp */
@@ -105,8 +105,8 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
}
// info header
- if(coreheader->size == 40){
- BmpInfoHeader* infoheader = (BmpInfoHeader*)coreheader;
+ if(fileheader->infoHeaderSize == 40){
+ BmpInfoHeader* infoheader = (BmpInfoHeader*)(bmp.data+14);
printf("infoheader.size : %u\n", infoheader->size);
printf("infoheader.width : %d\n", infoheader->width);
printf("infoheader.height : %d\n", infoheader->height);
@@ -162,8 +162,8 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
}
- if(coreheader->size == 56){
- BmpInfoHeader3* infoheader3 = (BmpInfoHeader3*)coreheader;
+ if(fileheader->infoHeaderSize == 56){
+ BmpInfoHeader3* infoheader3 = (BmpInfoHeader3*)(bmp.data+14);
printf("infoheader3.size : %u\n", infoheader3->size);
printf("infoheader3.width : %d\n", infoheader3->width);
printf("infoheader3.height : %d\n", infoheader3->height);
@@ -244,6 +244,8 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.depth = 8;
if(colormask.alpha)
image.profile = LEXLIB_RGBA;
+ else
+ image.profile = LEXLIB_RGB;
if(colormask.green == 5){
profile = LEXLIB_RGB555;
colormax.r = 31.0f;
--
GitLab
From ddc1ed3960371b5b723ff02ceaf25866343f2b81 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sat, 13 May 2023 00:55:29 -0400
Subject: [PATCH 25/64] new LICENSE file
---
LICENSE | 19 +++++++++++++++++++
LICENSE-UNLICENSE.txt | 24 ++++++++++++++++++++++++
2 files changed, 43 insertions(+)
create mode 100644 LICENSE
create mode 100644 LICENSE-UNLICENSE.txt
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d6cdc71
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+LexLib is dual licensed under the MIT and Apache 2.0
+some parts are released under the Unlicense (aka. Public Domain)
+
+for the full licenses check the LICENSE-*** files.
+
+> In short
+You are free to use, modify, redistribute, sublicense for any purpose, commercial or non-commercial free of charge.
+Copyright holders are not liable for any claim, damage or other.
+
+to not clobber source files with a awfully long license notice, short ones are used.
+
+> Short MIT and Apache 2.0 license notice
+Copyright [year*] [Copyright Holder*] []
+licensed under the MIT or Apache 2.0 (at your option)
+
+> Short Unlicense license notice
+[year] [writer]
+This is free and unencumbered software released into the public domain.
+free to copy, modify, publish, use, compile, sell, or distribute for any purpose, commercial or non-commercial.
\ No newline at end of file
diff --git a/LICENSE-UNLICENSE.txt b/LICENSE-UNLICENSE.txt
new file mode 100644
index 0000000..3c577b0
--- /dev/null
+++ b/LICENSE-UNLICENSE.txt
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
\ No newline at end of file
--
GitLab
From 67a0142b9b177e252ada9e75ca27c9d3c6a7cf3f Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sat, 13 May 2023 22:51:11 -0400
Subject: [PATCH 26/64] checks for bmp compression support
---
include/lexlibinternal/bmp.h | 2 +-
src/image/bmp.c | 61 ++++++++++++++++++++++++++++++------
2 files changed, 53 insertions(+), 10 deletions(-)
diff --git a/include/lexlibinternal/bmp.h b/include/lexlibinternal/bmp.h
index 7b238e2..59fb673 100644
--- a/include/lexlibinternal/bmp.h
+++ b/include/lexlibinternal/bmp.h
@@ -32,7 +32,7 @@ typedef struct BmpFileHeader {
uint16_t reserved2;
// offset in bytes where the bitmap data starts
uint32_t start;
- // used for reading the size of the info header; this element is not official in the spec
+ // used for reading the size of the info header; WARNING this element is not official in the spec
uint32_t infoHeaderSize;
} BmpFileHeader;
#pragma pack(pop)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index c5cd029..04d2374 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -19,7 +19,7 @@
> BMP structure
File Header | contains information about the file itsef
- Info Header | contains Info about the bitmap
+ Info Header | contains Info about the bitmap | 7 different versions
Extra bit masks | defines pixel format | optional
Color Table | defines colors used by the bitmap | semi-optional (not if bpp is less than 8)
Gap1 | alignment | optional
@@ -41,6 +41,18 @@
◯ ◯ BmpInfoHeader4 | 0..32 bpp
◯ ◯ BmpInfoHeader5 | 0..32 bpp
+> Compression
+ ● RGB | none | most common
+ ◯ RLE8 | RLE 8bit | only with 8-bit/pixel
+ ◯ RLE4 | RLE 4bit | only with 4-bit/pixel
+ ● BITFIELDS | RGB/A bit field masks
+ ◯ JPEG | ?
+ ◯ PNG | ?
+ ◯ ALPHABITFIELDS | RGBA bit field masks
+ ◯ CMYK | none
+ ◯ CMYKRLE8 | RLE-8 | only windows metafile
+ ◯ CMYKRLE4 | RLE-4 | only windows metafile
+
> Color Table
usually the order is bgr0.
4-byte per entry for rgba format.
@@ -55,6 +67,7 @@
◯ 16bpp: 65536 colors | ?
● 24bpp: 16777216 colors | b,g,r.
● 32bpp: 4294967296 colors | a,b,g,r.
+
*/
// get an individual bit
@@ -99,12 +112,12 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
/* check if file is bmp */
if(fileheader->type != 0x4D42){
- printf("bmp: no\n");
image.depth = LEXLIB_INVALID_FILE_TYPE;
- goto bmploadend;
+ free(bmp.data);
+ return image;
}
- // info header
+ /* info header */
if(fileheader->infoHeaderSize == 40){
BmpInfoHeader* infoheader = (BmpInfoHeader*)(bmp.data+14);
printf("infoheader.size : %u\n", infoheader->size);
@@ -119,6 +132,18 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("infoheader.clrpa : %u\n", infoheader->colorpalette);
printf("infoheader.clrim : %u\n", infoheader->colorimportant);
+ // check if compression is supported
+ switch(infoheader->compression){
+ case BMP_RGB:
+ break;
+ default: // unsuported
+ free(bmp.data);
+ lexlibImageDelete(&image);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
+ break;
+ }
+
uint8_t profile = LEXLIB_RGB;
switch(infoheader->bitdepth){
case 8:
@@ -160,8 +185,11 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
imgoffset+=image.channels;
}
- }
+ free(bmp.data);
+ return image;
+ }/* ..info header.. */
+ /* info header v3 */
if(fileheader->infoHeaderSize == 56){
BmpInfoHeader3* infoheader3 = (BmpInfoHeader3*)(bmp.data+14);
printf("infoheader3.size : %u\n", infoheader3->size);
@@ -181,6 +209,19 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("infoheader3.alphabitmask : 0x%.8X\n", infoheader3->alphabitmask);
printf("\n");
+ // check if compression is supported
+ switch(infoheader3->compression){
+ case BMP_RGB:
+ case BMP_BITFIELDS:
+ break;
+ default: // unsuported
+ free(bmp.data);
+ lexlibImageDelete(&image);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
+ break;
+ }
+
size_t bmpoffset = fileheader->start;
size_t imgoffset = 0;
uint64_t pixelcount = 0;
@@ -341,13 +382,15 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
bmpoffset+=image.channels;
imgoffset+=image.channels;
}
- }
-
- // LEXLIB_UNREACHABLE
+
+ free(bmp.data);
+ return image;
+ }/* ..info header v3.. */
- bmploadend:
+ LEXLIB_UNREACHABLE
if(bmp.data)
free(bmp.data);
+
return image;
}
--
GitLab
From 2b327b605067e797c0d036e4710eb24025e3822d Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sun, 14 May 2023 02:51:24 -0400
Subject: [PATCH 27/64] gnu attrib macro: LEXLIB_FALLTHROUGH
---
include/lexlib/common.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/lexlib/common.h b/include/lexlib/common.h
index 2927c87..686a525 100644
--- a/include/lexlib/common.h
+++ b/include/lexlib/common.h
@@ -21,9 +21,11 @@ and any changes may break api */
#ifdef __GNUC__
# define LEXLIB_INLINE static inline __attribute__((always_inline))
# define LEXLIB_DEPRECATED __attribute__((deprecated))
+# define LEXLIB_FALLTHROUGH __attribute__((fallthrough))
#else
# define LEXLIB_INLINE static inline
# define LEXLIB_DEPRECATED
+# define LEXLIB_FALLTHROUGH
#endif
#ifdef __BYTE_ORDER__
--
GitLab
From 97ff4bda7b0ec70daf5decdbe3f4b5e312b88435 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sun, 14 May 2023 03:02:15 -0400
Subject: [PATCH 28/64] lexlibPowu()
---
CHANGELOG.md | 7 ++++---
documentation/math.html | 23 +++++++++++++++++++++++
include/lexlib/math.h | 9 +++++++++
3 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56e9ed2..e1e3fc1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,8 @@
## 1.5.0 (under development)
-+ function lexlibColor16Blend().
-+ function lexlibImagePixelSet().
-+ function lexlibFileBytes():
++ lexlibColor16Blend().
++ lexlibImagePixelSet().
++ lexlibFileBytes():
++ lexlibPowu();
## 1.4.0
+ function lexlibStrCopy().
diff --git a/documentation/math.html b/documentation/math.html
index 0dcf3ab..f7ef727 100644
--- a/documentation/math.html
+++ b/documentation/math.html
@@ -19,6 +19,7 @@
lexlibDegToRadf()
lexlibRadToDeg()
lexlibRadToDegf()
+ lexlibPowu()
lexlibVec#New()
lexlibVec#NewZero()
lexlibVec#Clone()
@@ -250,6 +251,28 @@
+
+
+ lexlibPowu()
+
+ calculates base to the power of exp. (baseexp)
+
+ Function
+
+ unsigned int lexlibPowu(unsigned int base, unsigned int exp);
+
+
+ Argument
+
unsigned int base : base.
+ unsigned int exp : exponent.
+
+
+ Return
+
+ unsigned int : result of baseexp.
+
+
+
lexlibVec#New()
diff --git a/include/lexlib/math.h b/include/lexlib/math.h
index a3c4c28..5318884 100644
--- a/include/lexlib/math.h
+++ b/include/lexlib/math.h
@@ -149,6 +149,15 @@ LEXLIB_INLINE unsigned int lexlibClampu(unsigned int num, unsigned int min, unsi
return (num > max) ? max : (num < min) ? min : num;
}
+LEXLIB_INLINE unsigned int lexlibPowu(unsigned int base, unsigned int exp){
+ unsigned int result = 1;
+ while(exp != 0){
+ result *= base;
+ --exp;
+ }
+ return result;
+}
+
// ..misc.. //
--
GitLab
From 9717a7e27749f7772e7117796f05ef92f99484ae Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sun, 14 May 2023 03:54:08 -0400
Subject: [PATCH 29/64] bmp info header bpp16 support
---
src/image/bmp.c | 188 ++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 160 insertions(+), 28 deletions(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 04d2374..2e34bc2 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -42,16 +42,17 @@
◯ ◯ BmpInfoHeader5 | 0..32 bpp
> Compression
- ● RGB | none | most common
- ◯ RLE8 | RLE 8bit | only with 8-bit/pixel
- ◯ RLE4 | RLE 4bit | only with 4-bit/pixel
- ● BITFIELDS | RGB/A bit field masks
- ◯ JPEG | ?
- ◯ PNG | ?
- ◯ ALPHABITFIELDS | RGBA bit field masks
- ◯ CMYK | none
- ◯ CMYKRLE8 | RLE-8 | only windows metafile
- ◯ CMYKRLE4 | RLE-4 | only windows metafile
+ C I 2 3 4 5
+ ◯ ● ◯ ◯ ◯ ◯ RGB | none | most common
+ ◯ ◯ ◯ ◯ ◯ ◯ RLE8 | RLE 8bit | only with 8-bit/pixel
+ ◯ ◯ ◯ ◯ ◯ ◯ RLE4 | RLE 4bit | only with 4-bit/pixel
+ ◯ ● ◯ ◯ ◯ ◯ BITFIELDS | RGB bit field masks
+ ◯ ◯ ◯ ◯ ◯ ◯ JPEG | ?
+ ◯ ◯ ◯ ◯ ◯ ◯ PNG | ?
+ ◯ ● ◯ ◯ ◯ ◯ ALPHABITFIELDS | RGBA bit field masks
+ ◯ ◯ ◯ ◯ ◯ ◯ CMYK | none
+ ◯ ◯ ◯ ◯ ◯ ◯ CMYKRLE8 | RLE-8 | only windows metafile
+ ◯ ◯ ◯ ◯ ◯ ◯ CMYKRLE4 | RLE-4 | only windows metafile
> Color Table
usually the order is bgr0.
@@ -60,13 +61,14 @@
> pixel formats
left-most pixel in the most-significant bit of the first byte.
- ◯ 1bpp : 2 colors | table
- ◯ 2bpp : 4 colors | table
- ◯ 4bpp : 16 colors | table
- ◯ 8bpp : 256 colors | table
- ◯ 16bpp: 65536 colors | ?
- ● 24bpp: 16777216 colors | b,g,r.
- ● 32bpp: 4294967296 colors | a,b,g,r.
+ C I 2 3 4 5
+ ◯ ◯ ◯ ◯ ◯ ◯ 1bpp : 2 colors | table
+ ◯ ◯ ◯ ◯ ◯ ◯ 2bpp : 4 colors | table
+ ◯ ◯ ◯ ◯ ◯ ◯ 4bpp : 16 colors | table
+ ◯ ◯ ◯ ◯ ◯ ◯ 8bpp : 256 colors | table
+ ◯ ● ◯ ◯ ◯ ◯ 16bpp: 65536 colors | 555, 565, bitmask.
+ ◯ ● ◯ ◯ ◯ ◯ 24bpp: 16777216 colors | b,g,r.
+ ◯ ● ◯ ◯ ◯ ◯ 32bpp: 4294967296 colors | a,b,g,r.
*/
@@ -89,6 +91,9 @@ typedef struct ColorBitMask {
uint8_t alphashift;
} ColorBitMask;
+#define LEXLIB_RGB_BITFIELDS 0x0A
+#define LEXLIB_RGB_ALPHABITFIELDS 0x0B
+
// TODO probably needs big endian to little transforms on big endian machines
LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
@@ -132,10 +137,68 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("infoheader.clrpa : %u\n", infoheader->colorpalette);
printf("infoheader.clrim : %u\n", infoheader->colorimportant);
- // check if compression is supported
+ ColorBitMask colorMask = {0};
+ LexlibColorFlt colorMax = {0};
+ uint8_t profile = 0;
+ uint64_t pixelcount = 0;
+
+ // check for compression
switch(infoheader->compression){
case BMP_RGB:
break;
+ case BMP_ALPHABITFIELDS:
+ /* the alpha bitfield is added on top on the rgb bitfields */
+ colorMask.alphabit = (*(uint32_t*)(bmp.data+66));
+ for(uint8_t i = 0; i < 32; i++){
+ colorMask.alpha += bitGet(colorMask.alphabit, i);
+ }
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colorMask.alphabit, i) == 0)
+ colorMask.alphashift++;
+ else
+ break;
+ }
+ colorMax.a = lexlibPowu(2, colorMask.alpha) - 1;
+ profile = LEXLIB_RGB_ALPHABITFIELDS;
+ LEXLIB_FALLTHROUGH;
+ case BMP_BITFIELDS:
+ /* rgb bitfields*/
+ // get bit masks
+ colorMask.redbit = (*(uint32_t*)(bmp.data+54));
+ colorMask.greenbit = (*(uint32_t*)(bmp.data+58));
+ colorMask.bluebit = (*(uint32_t*)(bmp.data+62));
+ // get R.G.B
+ for(uint8_t i = 0; i < 32; i++){
+ colorMask.red += bitGet(colorMask.redbit, i);
+ colorMask.green += bitGet(colorMask.greenbit, i);
+ colorMask.blue += bitGet(colorMask.bluebit, i);
+ }
+ // get bit shifts
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colorMask.redbit, i) == 0)
+ colorMask.redshift++;
+ else
+ break;
+ }
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colorMask.greenbit, i) == 0)
+ colorMask.greenshift++;
+ else
+ break;
+ }
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colorMask.bluebit, i) == 0)
+ colorMask.blueshift++;
+ else
+ break;
+ }
+ // calculate max color value
+ colorMax.r = lexlibPowu(2, colorMask.red) - 1;
+ colorMax.g = lexlibPowu(2, colorMask.green) - 1;
+ colorMax.b = lexlibPowu(2, colorMask.blue) - 1;
+ if(!profile)
+ profile = LEXLIB_RGB_BITFIELDS;
+ break;
default: // unsuported
free(bmp.data);
lexlibImageDelete(&image);
@@ -144,29 +207,99 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
break;
}
- uint8_t profile = LEXLIB_RGB;
+ // check for color profile
switch(infoheader->bitdepth){
case 8:
- profile = LEXLIB_GRAY;
- image.depth = 8;
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
break;
+ case 16:
+ if(infoheader->compression == BMP_RGB){
+ profile = LEXLIB_RGB555;
+ image.profile = LEXLIB_RGB;
+ colorMax.r = 31.0f;
+ colorMax.g = 31.0f;
+ colorMax.b = 31.0f;
+ break;
+ }
+ if(infoheader->compression == BMP_BITFIELDS){
+ image.depth = 8;
+ if(colorMask.alpha)
+ image.profile = LEXLIB_RGBA;
+ else
+ image.profile = LEXLIB_RGB;
+ break;
+ }
+ free(bmp.data);
+ image.depth = LEXLIB_INVALID_FILE_DATA;
+ return image;
case 24:
- profile = LEXLIB_RGB;
image.depth = 8;
+ image.profile = LEXLIB_RGB;
+ if(!profile)
+ profile = LEXLIB_RGB;
break;
case 32:
- profile = LEXLIB_RGBA;
image.depth = 8;
+ image.profile = LEXLIB_RGBA;
+ if(!profile)
+ profile = LEXLIB_RGBA;
break;
default:
- break;
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
}
- image = lexlibImageNew(infoheader->width, infoheader->height, profile, image.depth);
+ printf("profile: %u\n", profile);
+ printf("pixelco: %zu\n", pixelcount);
+ printf("colormax.r: %f\n", colorMax.r);
+ printf("colormax.g: %f\n", colorMax.g);
+ printf("colormax.b: %f\n", colorMax.b);
+ printf("colormax.a: %f\n", colorMax.a);
+ printf("colormask.red: %u\n", colorMask.red);
+ printf("colormask.green: %u\n", colorMask.green);
+ printf("colormask.blue: %u\n", colorMask.blue);
+ printf("colormask.alpha: %u\n", colorMask.alpha);
+ printf("colormask.redshift : %u\n", colorMask.redshift);
+ printf("colormask.greenshift: %u\n", colorMask.greenshift);
+ printf("colormask.blueshift : %u\n", colorMask.blueshift);
+ printf("colormask.alphashift : %u\n", colorMask.alphashift);
+ printf("\n");
+
+ image = lexlibImageNew(infoheader->width, infoheader->height, image.profile, image.depth);
+ pixelcount = image.width * image.height;
size_t bmpoffset = fileheader->start;
size_t imgoffset = 0;
- if(image.profile == LEXLIB_RGB)
+ if(profile == LEXLIB_RGB_BITFIELDS)
+ for(uint64_t i = 0; i < pixelcount; i++){
+ uint16_t bmppixel = *((uint32_t*)(bmp.data+bmpoffset));
+
+ image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.redbit) >> colorMask.redshift) / colorMax.r) * 255.0f);
+ image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.greenbit) >> colorMask.greenshift) / colorMax.g) * 255.0f);
+ image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bluebit) >> colorMask.blueshift) / colorMax.b) * 255.0f);
+ if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
+
+ bmpoffset += 2;
+ imgoffset += image.channels;
+ }
+
+ if(profile == LEXLIB_RGB_ALPHABITFIELDS)
+ for(uint64_t i = 0; i < pixelcount; i++){
+ uint16_t bmppixel = *((uint32_t*)(bmp.data+bmpoffset));
+
+ image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.redbit) >> colorMask.redshift) / colorMax.r) * 255.0f);
+ image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.greenbit) >> colorMask.greenshift) / colorMax.g) * 255.0f);
+ image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bluebit) >> colorMask.blueshift) / colorMax.b) * 255.0f);
+ image.data[imgoffset+3] = rintf(( ((bmppixel & colorMask.alpha) >> colorMask.alphashift) / colorMax.a) * 255.0f);
+
+ bmpoffset += 2;
+ imgoffset += image.channels;
+ }
+
+ if(profile == LEXLIB_RGB)
while(imgoffset < infoheader->imagesize){
image.data[imgoffset+0] = bmp.data[bmpoffset+2];
image.data[imgoffset+1] = bmp.data[bmpoffset+1];
@@ -175,7 +308,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
imgoffset+=image.channels;
}
- if(image.profile == LEXLIB_RGBA)
+ if(profile == LEXLIB_RGBA)
while(imgoffset < infoheader->imagesize){
image.data[imgoffset+0] = bmp.data[bmpoffset+3];
image.data[imgoffset+1] = bmp.data[bmpoffset+2];
@@ -360,7 +493,6 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
imgoffset += image.channels;
}
-
if(profile == LEXLIB_RGB)
for(uint64_t i = 0; i < pixelcount; i++){
image.data[imgoffset+0] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->redbitmask) >> 16;
--
GitLab
From ba2e8a0ee2ced118d604287d1e6d6c678a49f4e1 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sun, 14 May 2023 17:09:38 -0400
Subject: [PATCH 30/64] bmp header 1 and 2 refactor
---
src/image/bmp.c | 431 ++++++++++++++++++++++++------------------------
1 file changed, 213 insertions(+), 218 deletions(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 2e34bc2..406e878 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -43,13 +43,13 @@
> Compression
C I 2 3 4 5
- ◯ ● ◯ ◯ ◯ ◯ RGB | none | most common
+ ◯ ● ◯ ● ◯ ◯ RGB | none | most common
◯ ◯ ◯ ◯ ◯ ◯ RLE8 | RLE 8bit | only with 8-bit/pixel
◯ ◯ ◯ ◯ ◯ ◯ RLE4 | RLE 4bit | only with 4-bit/pixel
- ◯ ● ◯ ◯ ◯ ◯ BITFIELDS | RGB bit field masks
+ ◯ ● ◯ ● ◯ ◯ BITFIELDS | RGB bit field masks
◯ ◯ ◯ ◯ ◯ ◯ JPEG | ?
◯ ◯ ◯ ◯ ◯ ◯ PNG | ?
- ◯ ● ◯ ◯ ◯ ◯ ALPHABITFIELDS | RGBA bit field masks
+ ◯ ● ◯ ● ◯ ◯ ALPHABITFIELDS | RGBA bit field masks
◯ ◯ ◯ ◯ ◯ ◯ CMYK | none
◯ ◯ ◯ ◯ ◯ ◯ CMYKRLE8 | RLE-8 | only windows metafile
◯ ◯ ◯ ◯ ◯ ◯ CMYKRLE4 | RLE-4 | only windows metafile
@@ -66,34 +66,36 @@
◯ ◯ ◯ ◯ ◯ ◯ 2bpp : 4 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 4bpp : 16 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 8bpp : 256 colors | table
- ◯ ● ◯ ◯ ◯ ◯ 16bpp: 65536 colors | 555, 565, bitmask.
- ◯ ● ◯ ◯ ◯ ◯ 24bpp: 16777216 colors | b,g,r.
- ◯ ● ◯ ◯ ◯ ◯ 32bpp: 4294967296 colors | a,b,g,r.
+ ◯ ● ◯ ● ◯ ◯ 16bpp: 65536 colors | 555, 565, bitmask.
+ ◯ ● ◯ ● ◯ ◯ 24bpp: 16777216 colors | b,g,r.
+ ◯ ● ◯ ● ◯ ◯ 32bpp: 4294967296 colors | a,b,g,r.
*/
-// get an individual bit
-LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index);
-
// to store bitmasks and shifts
typedef struct ColorBitMask {
- uint8_t red;
- uint8_t green;
- uint8_t blue;
- uint8_t alpha;
- uint32_t redbit;
- uint32_t greenbit;
- uint32_t bluebit;
- uint32_t alphabit;
- uint8_t redshift;
- uint8_t greenshift;
- uint8_t blueshift;
- uint8_t alphashift;
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+ uint32_t rb;
+ uint32_t gb;
+ uint32_t bb;
+ uint32_t ab;
+ uint8_t rs;
+ uint8_t gs;
+ uint8_t bs;
+ uint8_t as;
} ColorBitMask;
+/* Static Functions */
+LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index);
+static ColorBitMask colorBitMaskGet(const uint32_t* data, uint8_t bitfields);
+
#define LEXLIB_RGB_BITFIELDS 0x0A
-#define LEXLIB_RGB_ALPHABITFIELDS 0x0B
+#define LEXLIB_RGBA_BITFIELDS 0x0B
+// TODO image creation error checks
// TODO probably needs big endian to little transforms on big endian machines
LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
@@ -140,64 +142,28 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
ColorBitMask colorMask = {0};
LexlibColorFlt colorMax = {0};
uint8_t profile = 0;
- uint64_t pixelcount = 0;
+ uint8_t bmpPixelSize = 0;
// check for compression
switch(infoheader->compression){
case BMP_RGB:
break;
- case BMP_ALPHABITFIELDS:
- /* the alpha bitfield is added on top on the rgb bitfields */
- colorMask.alphabit = (*(uint32_t*)(bmp.data+66));
- for(uint8_t i = 0; i < 32; i++){
- colorMask.alpha += bitGet(colorMask.alphabit, i);
- }
- for(uint8_t i = 0; i < 32; i++){
- if(bitGet(colorMask.alphabit, i) == 0)
- colorMask.alphashift++;
- else
- break;
- }
- colorMax.a = lexlibPowu(2, colorMask.alpha) - 1;
- profile = LEXLIB_RGB_ALPHABITFIELDS;
- LEXLIB_FALLTHROUGH;
case BMP_BITFIELDS:
- /* rgb bitfields*/
- // get bit masks
- colorMask.redbit = (*(uint32_t*)(bmp.data+54));
- colorMask.greenbit = (*(uint32_t*)(bmp.data+58));
- colorMask.bluebit = (*(uint32_t*)(bmp.data+62));
- // get R.G.B
- for(uint8_t i = 0; i < 32; i++){
- colorMask.red += bitGet(colorMask.redbit, i);
- colorMask.green += bitGet(colorMask.greenbit, i);
- colorMask.blue += bitGet(colorMask.bluebit, i);
- }
- // get bit shifts
- for(uint8_t i = 0; i < 32; i++){
- if(bitGet(colorMask.redbit, i) == 0)
- colorMask.redshift++;
- else
- break;
- }
- for(uint8_t i = 0; i < 32; i++){
- if(bitGet(colorMask.greenbit, i) == 0)
- colorMask.greenshift++;
- else
- break;
- }
- for(uint8_t i = 0; i < 32; i++){
- if(bitGet(colorMask.bluebit, i) == 0)
- colorMask.blueshift++;
- else
- break;
- }
+ colorMask = colorBitMaskGet((uint32_t*)(bmp.data+54), LEXLIB_RGB_BITFIELDS);
+ profile = LEXLIB_RGB_BITFIELDS;
// calculate max color value
- colorMax.r = lexlibPowu(2, colorMask.red) - 1;
- colorMax.g = lexlibPowu(2, colorMask.green) - 1;
- colorMax.b = lexlibPowu(2, colorMask.blue) - 1;
- if(!profile)
- profile = LEXLIB_RGB_BITFIELDS;
+ colorMax.r = lexlibPowu(2, colorMask.r) - 1;
+ colorMax.g = lexlibPowu(2, colorMask.g) - 1;
+ colorMax.b = lexlibPowu(2, colorMask.b) - 1;
+ break;
+ case BMP_ALPHABITFIELDS:
+ colorMask = colorBitMaskGet((uint32_t*)(bmp.data+54), LEXLIB_RGBA_BITFIELDS);
+ profile = LEXLIB_RGB_BITFIELDS;
+ // calculate max color value
+ colorMax.r = lexlibPowu(2, colorMask.r) - 1;
+ colorMax.g = lexlibPowu(2, colorMask.g) - 1;
+ colorMax.b = lexlibPowu(2, colorMask.b) - 1;
+ colorMax.a = lexlibPowu(2, colorMask.a);
break;
default: // unsuported
free(bmp.data);
@@ -215,8 +181,10 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
return image;
break;
case 16:
+ bmpPixelSize = 2;
if(infoheader->compression == BMP_RGB){
profile = LEXLIB_RGB555;
+ image.depth = 8;
image.profile = LEXLIB_RGB;
colorMax.r = 31.0f;
colorMax.g = 31.0f;
@@ -225,10 +193,12 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
}
if(infoheader->compression == BMP_BITFIELDS){
image.depth = 8;
- if(colorMask.alpha)
- image.profile = LEXLIB_RGBA;
- else
- image.profile = LEXLIB_RGB;
+ image.profile = (colorMask.a) ? LEXLIB_RGBA : LEXLIB_RGB;
+ break;
+ }
+ if(infoheader->compression == BMP_ALPHABITFIELDS){
+ image.depth = 8;
+ image.profile = LEXLIB_RGBA;
break;
}
free(bmp.data);
@@ -239,12 +209,14 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.profile = LEXLIB_RGB;
if(!profile)
profile = LEXLIB_RGB;
+ bmpPixelSize = 3;
break;
case 32:
image.depth = 8;
image.profile = LEXLIB_RGBA;
if(!profile)
profile = LEXLIB_RGBA;
+ bmpPixelSize = 4;
break;
default:
free(bmp.data);
@@ -253,68 +225,72 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
}
printf("profile: %u\n", profile);
- printf("pixelco: %zu\n", pixelcount);
printf("colormax.r: %f\n", colorMax.r);
printf("colormax.g: %f\n", colorMax.g);
printf("colormax.b: %f\n", colorMax.b);
printf("colormax.a: %f\n", colorMax.a);
- printf("colormask.red: %u\n", colorMask.red);
- printf("colormask.green: %u\n", colorMask.green);
- printf("colormask.blue: %u\n", colorMask.blue);
- printf("colormask.alpha: %u\n", colorMask.alpha);
- printf("colormask.redshift : %u\n", colorMask.redshift);
- printf("colormask.greenshift: %u\n", colorMask.greenshift);
- printf("colormask.blueshift : %u\n", colorMask.blueshift);
- printf("colormask.alphashift : %u\n", colorMask.alphashift);
+ printf("colormask.r: %u\n", colorMask.r);
+ printf("colormask.g: %u\n", colorMask.g);
+ printf("colormask.b: %u\n", colorMask.b);
+ printf("colormask.a: %u\n", colorMask.a);
+ printf("colormask.rs: %u\n", colorMask.rs);
+ printf("colormask.gs: %u\n", colorMask.gs);
+ printf("colormask.bs: %u\n", colorMask.bs);
+ printf("colormask.as: %u\n", colorMask.as);
printf("\n");
+ // create image and set offsets
image = lexlibImageNew(infoheader->width, infoheader->height, image.profile, image.depth);
- pixelcount = image.width * image.height;
+ uint64_t pixelCount = image.width * image.height;
size_t bmpoffset = fileheader->start;
size_t imgoffset = 0;
+ // load pixel data from bmp to lexlib image
if(profile == LEXLIB_RGB_BITFIELDS)
- for(uint64_t i = 0; i < pixelcount; i++){
+ for(uint64_t i = 0; i < pixelCount; i++){
uint16_t bmppixel = *((uint32_t*)(bmp.data+bmpoffset));
- image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.redbit) >> colorMask.redshift) / colorMax.r) * 255.0f);
- image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.greenbit) >> colorMask.greenshift) / colorMax.g) * 255.0f);
- image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bluebit) >> colorMask.blueshift) / colorMax.b) * 255.0f);
- if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
+ image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.rb) >> colorMask.rs) / colorMax.r) * 255.0f);
+ image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.gb) >> colorMask.gs) / colorMax.g) * 255.0f);
+ image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bb) >> colorMask.bs) / colorMax.b) * 255.0f);
+ image.data[imgoffset+3] = (image.profile == LEXLIB_RGBA) ? rintf(( ((bmppixel & colorMask.ab) >> colorMask.as) / colorMax.a) * 256.0f) - 1 : 0xFF;
- bmpoffset += 2;
+ bmpoffset += bmpPixelSize;
imgoffset += image.channels;
}
- if(profile == LEXLIB_RGB_ALPHABITFIELDS)
- for(uint64_t i = 0; i < pixelcount; i++){
- uint16_t bmppixel = *((uint32_t*)(bmp.data+bmpoffset));
+ if(profile == LEXLIB_RGB555)
+ for(uint64_t i = 0; i < pixelCount; i++){
+ uint16_t bmppixel = *((uint16_t*)(bmp.data+bmpoffset));
- image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.redbit) >> colorMask.redshift) / colorMax.r) * 255.0f);
- image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.greenbit) >> colorMask.greenshift) / colorMax.g) * 255.0f);
- image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bluebit) >> colorMask.blueshift) / colorMax.b) * 255.0f);
- image.data[imgoffset+3] = rintf(( ((bmppixel & colorMask.alpha) >> colorMask.alphashift) / colorMax.a) * 255.0f);
+ image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.rb) >> 10) / 31.0f) * 255.0f);
+ image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.gb) >> 5) / 31.0f) * 255.0f);
+ image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bb) >> 0) / 31.0f) * 255.0f);
+ if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
bmpoffset += 2;
imgoffset += image.channels;
}
if(profile == LEXLIB_RGB)
- while(imgoffset < infoheader->imagesize){
+ for(uint64_t i = 0; i < pixelCount; i++){
image.data[imgoffset+0] = bmp.data[bmpoffset+2];
image.data[imgoffset+1] = bmp.data[bmpoffset+1];
image.data[imgoffset+2] = bmp.data[bmpoffset+0];
- bmpoffset+=image.channels;
+ if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
+
+ bmpoffset+=3;
imgoffset+=image.channels;
}
if(profile == LEXLIB_RGBA)
- while(imgoffset < infoheader->imagesize){
+ for(uint64_t i = 0; i < pixelCount; i++){
image.data[imgoffset+0] = bmp.data[bmpoffset+3];
image.data[imgoffset+1] = bmp.data[bmpoffset+2];
image.data[imgoffset+2] = bmp.data[bmpoffset+1];
image.data[imgoffset+3] = bmp.data[bmpoffset+0];
- bmpoffset+=image.channels;
+
+ bmpoffset+=4;
imgoffset+=image.channels;
}
@@ -342,10 +318,24 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("infoheader3.alphabitmask : 0x%.8X\n", infoheader3->alphabitmask);
printf("\n");
- // check if compression is supported
+ ColorBitMask colorMask = {0};
+ LexlibColorFlt colorMax = {0};
+ uint8_t profile = 0;
+ uint8_t bmpPixelSize = 0;
+
+ // check for compression
switch(infoheader3->compression){
case BMP_RGB:
+ break;
case BMP_BITFIELDS:
+ case BMP_ALPHABITFIELDS:
+ colorMask = colorBitMaskGet((uint32_t*)(bmp.data+54), LEXLIB_RGBA_BITFIELDS);
+ profile = LEXLIB_RGB_BITFIELDS;
+ // calculate max color value
+ colorMax.r = lexlibPowu(2, colorMask.r) - 1;
+ colorMax.g = lexlibPowu(2, colorMask.g) - 1;
+ colorMax.b = lexlibPowu(2, colorMask.b) - 1;
+ colorMax.a = lexlibPowu(2, colorMask.a);
break;
default: // unsuported
free(bmp.data);
@@ -355,120 +345,57 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
break;
}
- size_t bmpoffset = fileheader->start;
- size_t imgoffset = 0;
- uint64_t pixelcount = 0;
- uint8_t profile = 0;
- ColorBitMask colormask = {
- .red = 0,
- .green = 0,
- .blue = 0,
- .alpha = 0,
- .redbit = infoheader3->redbitmask,
- .greenbit = infoheader3->greenbitmask,
- .bluebit = infoheader3->bluebitmask,
- .alphabit = infoheader3->alphabitmask,
- .redshift = 0,
- .greenshift = 0,
- .blueshift = 0,
- .alphashift = 0,
- };
- LexlibColorFlt colormax = {
- .r = 255.0f,
- .g = 255.0f,
- .b = 255.0f,
- .a = 255.0f,
- };
-
- // get R.G.B.A
- for(uint8_t i = 0; i < 32; i++){
- colormask.red += bitGet(colormask.redbit, i);
- colormask.green += bitGet(colormask.greenbit, i);
- colormask.blue += bitGet(colormask.bluebit, i);
- colormask.alpha += bitGet(colormask.alphabit, i);
- }
-
- // get bit shifts
- for(uint8_t i = 0; i < 32; i++){
- if(bitGet(colormask.redbit, i) == 0)
- colormask.redshift++;
- else
- break;
- }
- for(uint8_t i = 0; i < 32; i++){
- if(bitGet(colormask.greenbit, i) == 0)
- colormask.greenshift++;
- else
- break;
- }
- for(uint8_t i = 0; i < 32; i++){
- if(bitGet(colormask.bluebit, i) == 0)
- colormask.blueshift++;
- else
- break;
- }
-
// set the color profile
if(infoheader3->bitdepth == 8){
- image.profile = LEXLIB_GRAY;
- image.depth = 8;
- profile = LEXLIB_GRAY;
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
}
if(infoheader3->bitdepth == 16){
image.depth = 8;
- if(colormask.alpha)
- image.profile = LEXLIB_RGBA;
- else
- image.profile = LEXLIB_RGB;
- if(colormask.green == 5){
+ image.profile = (colorMask.a) ? LEXLIB_RGBA : LEXLIB_RGB;
+ if(!profile)
profile = LEXLIB_RGB555;
- colormax.r = 31.0f;
- colormax.g = 31.0f;
- colormax.b = 31.0f;
- colormax.a = 0.0f;
- }
- if(colormask.green == 6){
- profile = LEXLIB_RGB565;
- colormax.r = 31.0f;
- colormax.g = 63.0f;
- colormax.b = 31.0f;
- colormax.a = 0.0f;
- }
+ bmpPixelSize = 2;
}
if(infoheader3->bitdepth == 24){
image.depth = 8;
image.profile = LEXLIB_RGB;
- profile = LEXLIB_RGB;
+ if(!profile)
+ profile = LEXLIB_RGB;
+ bmpPixelSize = 3;
}
if(infoheader3->bitdepth == 32){
image.depth = 8;
image.profile = LEXLIB_RGBA;
- profile = LEXLIB_RGBA;
+ if(!profile)
+ profile = LEXLIB_RGBA;
+ bmpPixelSize = 4;
}
+ // create image and set offsets
image = lexlibImageNew(infoheader3->width, infoheader3->height, image.profile, image.depth);
- pixelcount = image.width * image.height;
-
- // check for the correct bmp profile
- if(!profile)
- profile = image.profile;
- if(profile == LEXLIB_RGBA){
- if(infoheader3->alphabitmask){
- profile = LEXLIB_RGBA;
- } else {
- profile = LEXLIB_RGB;
- }
- }
+ uint64_t pixelCount = image.width * image.height;
+ size_t bmpoffset = fileheader->start;
+ size_t imgoffset = 0;
printf("profile: %u\n", profile);
- printf("pixelco: %zu\n", pixelcount);
- printf("colormask.red: %u\n", colormask.red);
- printf("colormask.green: %u\n", colormask.green);
- printf("colormask.blue: %u\n", colormask.blue);
- printf("colormask.alpha: %u\n", colormask.alpha);
- printf("colormask.redshift : %u\n", colormask.redshift);
- printf("colormask.greenshift: %u\n", colormask.greenshift);
- printf("colormask.blueshift : %u\n", colormask.blueshift);
+ printf("colormax.r: %f\n", colorMax.r);
+ printf("colormax.g: %f\n", colorMax.g);
+ printf("colormax.b: %f\n", colorMax.b);
+ printf("colormax.a: %f\n", colorMax.a);
+ printf("colormask.r: %u\n", colorMask.r);
+ printf("colormask.g: %u\n", colorMask.g);
+ printf("colormask.b: %u\n", colorMask.b);
+ printf("colormask.a: %u\n", colorMask.a);
+ printf("colormask.rb: %u\n", colorMask.rb);
+ printf("colormask.gb: %u\n", colorMask.gb);
+ printf("colormask.bb: %u\n", colorMask.bb);
+ printf("colormask.ab: %u\n", colorMask.ab);
+ printf("colormask.rs: %u\n", colorMask.rs);
+ printf("colormask.gs: %u\n", colorMask.gs);
+ printf("colormask.bs: %u\n", colorMask.bs);
+ printf("colormask.as: %u\n", colorMask.as);
printf("\n");
printf("image.datasize: %zu\n", image.datasize);
@@ -480,38 +407,52 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
printf("image.profile : %u\n", image.profile);
printf("\n");
- if(profile == LEXLIB_RGB555 || profile == LEXLIB_RGB565)
- for(uint64_t i = 0; i < pixelcount; i++){
+ // load pixel data from bmp to lexlib image
+ if(profile == LEXLIB_RGB_BITFIELDS)
+ for(uint64_t i = 0; i < pixelCount; i++){
+ uint32_t bmppixel = *((uint32_t*)(bmp.data+bmpoffset));
+
+ image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.rb) >> colorMask.rs) / colorMax.r) * 255.0f);
+ image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.gb) >> colorMask.gs) / colorMax.g) * 255.0f);
+ image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bb) >> colorMask.bs) / colorMax.b) * 255.0f);
+ image.data[imgoffset+3] = (image.profile == LEXLIB_RGBA) ? rintf(( ((bmppixel & colorMask.ab) >> colorMask.as) / colorMax.a) * 256.0f) - 1 : 0xFF;
+
+ bmpoffset += bmpPixelSize;
+ imgoffset += image.channels;
+ }
+
+ if(profile == LEXLIB_RGB555)
+ for(uint64_t i = 0; i < pixelCount; i++){
uint16_t bmppixel = *((uint16_t*)(bmp.data+bmpoffset));
- image.data[imgoffset+0] = rintf(( ((bmppixel & colormask.redbit) >> colormask.redshift) / colormax.r) * 255.0f);
- image.data[imgoffset+1] = rintf(( ((bmppixel & colormask.greenbit) >> colormask.greenshift) / colormax.g) * 255.0f);
- image.data[imgoffset+2] = rintf(( ((bmppixel & colormask.bluebit) >> colormask.blueshift) / colormax.b) * 255.0f);
+ image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.rb) >> 10) / 31.0f) * 255.0f);
+ image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.gb) >> 5) / 31.0f) * 255.0f);
+ image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bb) >> 0) / 31.0f) * 255.0f);
if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
bmpoffset += 2;
imgoffset += image.channels;
}
-
+
if(profile == LEXLIB_RGB)
- for(uint64_t i = 0; i < pixelcount; i++){
- image.data[imgoffset+0] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->redbitmask) >> 16;
- image.data[imgoffset+1] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->greenbitmask) >> 8;
- image.data[imgoffset+2] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->bluebitmask);
+ for(uint64_t i = 0; i < pixelCount; i++){
+ image.data[imgoffset+0] = bmp.data[bmpoffset+2];
+ image.data[imgoffset+1] = bmp.data[bmpoffset+1];
+ image.data[imgoffset+2] = bmp.data[bmpoffset+0];
if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
- bmpoffset += image.channels;
- imgoffset += image.channels;
+ bmpoffset+=3;
+ imgoffset+=image.channels;
}
if(profile == LEXLIB_RGBA)
- while(imgoffset < infoheader3->imagesize){
- image.data[imgoffset+0] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->redbitmask) >> 16;
- image.data[imgoffset+1] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->greenbitmask) >> 8;
- image.data[imgoffset+2] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->bluebitmask);
- image.data[imgoffset+3] = (*((uint32_t*)(bmp.data+bmpoffset)) & infoheader3->alphabitmask) >> 24;
+ for(uint64_t i = 0; i < pixelCount; i++){
+ image.data[imgoffset+0] = bmp.data[bmpoffset+3];
+ image.data[imgoffset+1] = bmp.data[bmpoffset+2];
+ image.data[imgoffset+2] = bmp.data[bmpoffset+1];
+ image.data[imgoffset+3] = bmp.data[bmpoffset+0];
- bmpoffset+=image.channels;
+ bmpoffset+=4;
imgoffset+=image.channels;
}
@@ -527,8 +468,62 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
}
+/* Static Functions */
#define UNSIGNED_BIT_WIDTH (CHAR_BIT * sizeof(unsigned))
LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index){
index %= UNSIGNED_BIT_WIDTH;
return (x >> index) & 1;
}
+
+static ColorBitMask colorBitMaskGet(const uint32_t* data, uint8_t bitfields){
+ ColorBitMask colorMask = {0};
+
+ // get bit masks
+ if(bitfields == LEXLIB_RGB_BITFIELDS){
+ colorMask.rb = data[0];
+ colorMask.gb = data[1];
+ colorMask.bb = data[2];
+ }
+ if(bitfields == LEXLIB_RGBA_BITFIELDS){
+ colorMask.rb = data[0];
+ colorMask.gb = data[1];
+ colorMask.bb = data[2];
+ colorMask.ab = data[3];
+ }
+
+ // get R.G.B.A
+ for(uint8_t i = 0; i < 32; i++){
+ colorMask.r += bitGet(colorMask.rb, i);
+ colorMask.g += bitGet(colorMask.gb, i);
+ colorMask.b += bitGet(colorMask.bb, i);
+ colorMask.a += bitGet(colorMask.ab, i);
+ }
+
+ // get bit shifts
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colorMask.rb, i) == 0)
+ colorMask.rs++;
+ else
+ break;
+ }
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colorMask.gb, i) == 0)
+ colorMask.gs++;
+ else
+ break;
+ }
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colorMask.bb, i) == 0)
+ colorMask.bs++;
+ else
+ break;
+ }
+ for(uint8_t i = 0; i < 32; i++){
+ if(bitGet(colorMask.ab, i) == 0)
+ colorMask.as++;
+ else
+ break;
+ }
+
+ return colorMask;
+}
\ No newline at end of file
--
GitLab
From d3d23bca8773a7c40cc5e46129c264b98f09bac5 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sun, 14 May 2023 17:51:48 -0400
Subject: [PATCH 31/64] bmp 8bpp table support
---
src/image/bmp.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 406e878..58c72d4 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -65,7 +65,7 @@
◯ ◯ ◯ ◯ ◯ ◯ 1bpp : 2 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 2bpp : 4 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 4bpp : 16 colors | table
- ◯ ◯ ◯ ◯ ◯ ◯ 8bpp : 256 colors | table
+ ◯ ● ◯ ◯ ◯ ◯ 8bpp : 256 colors | table
◯ ● ◯ ● ◯ ◯ 16bpp: 65536 colors | 555, 565, bitmask.
◯ ● ◯ ● ◯ ◯ 24bpp: 16777216 colors | b,g,r.
◯ ● ◯ ● ◯ ◯ 32bpp: 4294967296 colors | a,b,g,r.
@@ -88,12 +88,19 @@ typedef struct ColorBitMask {
uint8_t as;
} ColorBitMask;
+typedef struct ColorRGB {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+} ColorRGB;
+
/* Static Functions */
LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index);
static ColorBitMask colorBitMaskGet(const uint32_t* data, uint8_t bitfields);
#define LEXLIB_RGB_BITFIELDS 0x0A
#define LEXLIB_RGBA_BITFIELDS 0x0B
+#define LEXLIB_RGB_PALETTE 0x0C
// TODO image creation error checks
// TODO probably needs big endian to little transforms on big endian machines
@@ -176,6 +183,26 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
// check for color profile
switch(infoheader->bitdepth){
case 8:
+ bmpPixelSize = 1;
+ image.depth = 8;
+ image.profile = LEXLIB_RGB;
+ if(infoheader->colorpalette){
+ profile = LEXLIB_RGB_PALETTE;
+ if(infoheader->compression){
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
+ }
+ break;
+ }
+ if(infoheader->compression == BMP_BITFIELDS){
+ image.profile = (colorMask.a) ? LEXLIB_RGBA : LEXLIB_RGB;
+ break;
+ }
+ if(infoheader->compression == BMP_ALPHABITFIELDS){
+ image.profile = LEXLIB_RGBA;
+ break;
+ }
free(bmp.data);
image.depth = LEXLIB_UNSUPORTED;
return image;
@@ -294,6 +321,19 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
imgoffset+=image.channels;
}
+ if(profile == LEXLIB_RGB_PALETTE){
+ LexlibColor8* palette = (LexlibColor8*)(bmp.data+54);
+ for(uint64_t i = 0; i < pixelCount; i++){
+
+ image.data[imgoffset+0] = palette[bmp.data[bmpoffset]].b;
+ image.data[imgoffset+1] = palette[bmp.data[bmpoffset]].g;
+ image.data[imgoffset+2] = palette[bmp.data[bmpoffset]].r;
+ if(image.profile == LEXLIB_RGBA) image.data[imgoffset+4] = palette[bmp.data[bmpoffset]].a;
+
+ bmpoffset += bmpPixelSize;
+ imgoffset += image.channels;
+ }}
+
free(bmp.data);
return image;
}/* ..info header.. */
--
GitLab
From 13116a27739ba5f286247589adc0909f07121655 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sun, 14 May 2023 17:54:30 -0400
Subject: [PATCH 32/64] bmp checks at image creation
---
src/image/bmp.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 58c72d4..0e597ec 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -102,7 +102,6 @@ static ColorBitMask colorBitMaskGet(const uint32_t* data, uint8_t bitfields);
#define LEXLIB_RGBA_BITFIELDS 0x0B
#define LEXLIB_RGB_PALETTE 0x0C
-// TODO image creation error checks
// TODO probably needs big endian to little transforms on big endian machines
LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
@@ -268,6 +267,10 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
// create image and set offsets
image = lexlibImageNew(infoheader->width, infoheader->height, image.profile, image.depth);
+ if(!image.data){
+ free(bmp.data);
+ return image;
+ }
uint64_t pixelCount = image.width * image.height;
size_t bmpoffset = fileheader->start;
size_t imgoffset = 0;
@@ -415,6 +418,10 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
// create image and set offsets
image = lexlibImageNew(infoheader3->width, infoheader3->height, image.profile, image.depth);
+ if(!image.data){
+ free(bmp.data);
+ return image;
+ }
uint64_t pixelCount = image.width * image.height;
size_t bmpoffset = fileheader->start;
size_t imgoffset = 0;
--
GitLab
From d13db3f1e5a8ff6188139aba91128e22ba971a35 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sun, 14 May 2023 17:56:28 -0400
Subject: [PATCH 33/64] removed printf's from imageLoadBmp
---
src/image/bmp.c | 84 +------------------------------------------------
1 file changed, 1 insertion(+), 83 deletions(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 0e597ec..1ad68ab 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -4,15 +4,13 @@
#include
#include
#include
+#include
#include
#include
#include
#include
#include
-#include
-#include
-
/*
> BMP
data is stored as little endian.
@@ -107,22 +105,12 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
LexlibBytes bmp = lexlibFileBytes(filename);
if(!bmp.data){
- printf("bmp: no data.\n");
image.depth = bmp.count;
return image;
}
- printf("bmp.count: %zu\n", bmp.count);
BmpFileHeader* fileheader = (BmpFileHeader*)bmp.data;
- printf("fileheader.type: 0x%X\n", fileheader->type);
- printf("fileheader.size: %d\n", fileheader->size);
- printf("fileheader.res1: %d\n", fileheader->reserved1);
- printf("fileheader.res2: %d\n", fileheader->reserved2);
- printf("fileheader.stat: %d\n", fileheader->start);
- printf("fileheader.ihds: %d\n", fileheader->infoHeaderSize);
- printf("\n");
-
/* check if file is bmp */
if(fileheader->type != 0x4D42){
image.depth = LEXLIB_INVALID_FILE_TYPE;
@@ -133,17 +121,6 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
/* info header */
if(fileheader->infoHeaderSize == 40){
BmpInfoHeader* infoheader = (BmpInfoHeader*)(bmp.data+14);
- printf("infoheader.size : %u\n", infoheader->size);
- printf("infoheader.width : %d\n", infoheader->width);
- printf("infoheader.height : %d\n", infoheader->height);
- printf("infoheader.planes : %u\n", infoheader->planes);
- printf("infoheader.bitdep : %u\n", infoheader->bitdepth);
- printf("infoheader.compre : %u\n", infoheader->compression);
- printf("infoheader.imgsiz : %u\n", infoheader->imagesize);
- printf("infoheader.xresm : %u\n", infoheader->xresm);
- printf("infoheader.yresm : %u\n", infoheader->yresm);
- printf("infoheader.clrpa : %u\n", infoheader->colorpalette);
- printf("infoheader.clrim : %u\n", infoheader->colorimportant);
ColorBitMask colorMask = {0};
LexlibColorFlt colorMax = {0};
@@ -250,21 +227,6 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
return image;
}
- printf("profile: %u\n", profile);
- printf("colormax.r: %f\n", colorMax.r);
- printf("colormax.g: %f\n", colorMax.g);
- printf("colormax.b: %f\n", colorMax.b);
- printf("colormax.a: %f\n", colorMax.a);
- printf("colormask.r: %u\n", colorMask.r);
- printf("colormask.g: %u\n", colorMask.g);
- printf("colormask.b: %u\n", colorMask.b);
- printf("colormask.a: %u\n", colorMask.a);
- printf("colormask.rs: %u\n", colorMask.rs);
- printf("colormask.gs: %u\n", colorMask.gs);
- printf("colormask.bs: %u\n", colorMask.bs);
- printf("colormask.as: %u\n", colorMask.as);
- printf("\n");
-
// create image and set offsets
image = lexlibImageNew(infoheader->width, infoheader->height, image.profile, image.depth);
if(!image.data){
@@ -344,22 +306,6 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
/* info header v3 */
if(fileheader->infoHeaderSize == 56){
BmpInfoHeader3* infoheader3 = (BmpInfoHeader3*)(bmp.data+14);
- printf("infoheader3.size : %u\n", infoheader3->size);
- printf("infoheader3.width : %d\n", infoheader3->width);
- printf("infoheader3.height : %d\n", infoheader3->height);
- printf("infoheader3.planes : %u\n", infoheader3->planes);
- printf("infoheader3.bitdep : %u\n", infoheader3->bitdepth);
- printf("infoheader3.compre : %u\n", infoheader3->compression);
- printf("infoheader3.imgsiz : %u\n", infoheader3->imagesize);
- printf("infoheader3.xresm : %u\n", infoheader3->xresm);
- printf("infoheader3.yresm : %u\n", infoheader3->yresm);
- printf("infoheader3.clrpa : %u\n", infoheader3->colorpalette);
- printf("infoheader3.clrim : %u\n", infoheader3->colorimportant);
- printf("infoheader3.redbitmask : 0x%.8X\n", infoheader3->redbitmask);
- printf("infoheader3.greenbitmask : 0x%.8X\n", infoheader3->greenbitmask);
- printf("infoheader3.bluebitmask : 0x%.8X\n", infoheader3->bluebitmask);
- printf("infoheader3.alphabitmask : 0x%.8X\n", infoheader3->alphabitmask);
- printf("\n");
ColorBitMask colorMask = {0};
LexlibColorFlt colorMax = {0};
@@ -426,34 +372,6 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
size_t bmpoffset = fileheader->start;
size_t imgoffset = 0;
- printf("profile: %u\n", profile);
- printf("colormax.r: %f\n", colorMax.r);
- printf("colormax.g: %f\n", colorMax.g);
- printf("colormax.b: %f\n", colorMax.b);
- printf("colormax.a: %f\n", colorMax.a);
- printf("colormask.r: %u\n", colorMask.r);
- printf("colormask.g: %u\n", colorMask.g);
- printf("colormask.b: %u\n", colorMask.b);
- printf("colormask.a: %u\n", colorMask.a);
- printf("colormask.rb: %u\n", colorMask.rb);
- printf("colormask.gb: %u\n", colorMask.gb);
- printf("colormask.bb: %u\n", colorMask.bb);
- printf("colormask.ab: %u\n", colorMask.ab);
- printf("colormask.rs: %u\n", colorMask.rs);
- printf("colormask.gs: %u\n", colorMask.gs);
- printf("colormask.bs: %u\n", colorMask.bs);
- printf("colormask.as: %u\n", colorMask.as);
- printf("\n");
-
- printf("image.datasize: %zu\n", image.datasize);
- printf("image.width : %u\n", image.width);
- printf("image.height : %u\n", image.height);
- printf("image.channels: %u\n", image.channels);
- printf("image.depth : %u\n", image.depth);
- printf("image.bpp : %u\n", image.bpp);
- printf("image.profile : %u\n", image.profile);
- printf("\n");
-
// load pixel data from bmp to lexlib image
if(profile == LEXLIB_RGB_BITFIELDS)
for(uint64_t i = 0; i < pixelCount; i++){
--
GitLab
From 18f7a96055d13cb513812316266fd6c00ad223c4 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Sun, 14 May 2023 23:45:01 -0400
Subject: [PATCH 34/64] moved image resources to resources/image
---
resources/{ => image}/macintosh.bmp | Bin
resources/{ => image}/macintosh_8bpp.bmp | Bin
resources/{ => image}/macintosh_alpha70.bmp | Bin
resources/{ => image}/pixelDucks.png | Bin
resources/{ => image}/plasma16.bmp | Bin
resources/{ => image}/plasma24.bmp | Bin
resources/{ => image}/plasma32.bmp | Bin
resources/image/puro.bmp | Bin 0 -> 17154 bytes
test/imagePng.c | 6 +++---
9 files changed, 3 insertions(+), 3 deletions(-)
rename resources/{ => image}/macintosh.bmp (100%)
rename resources/{ => image}/macintosh_8bpp.bmp (100%)
rename resources/{ => image}/macintosh_alpha70.bmp (100%)
rename resources/{ => image}/pixelDucks.png (100%)
rename resources/{ => image}/plasma16.bmp (100%)
rename resources/{ => image}/plasma24.bmp (100%)
rename resources/{ => image}/plasma32.bmp (100%)
create mode 100644 resources/image/puro.bmp
diff --git a/resources/macintosh.bmp b/resources/image/macintosh.bmp
similarity index 100%
rename from resources/macintosh.bmp
rename to resources/image/macintosh.bmp
diff --git a/resources/macintosh_8bpp.bmp b/resources/image/macintosh_8bpp.bmp
similarity index 100%
rename from resources/macintosh_8bpp.bmp
rename to resources/image/macintosh_8bpp.bmp
diff --git a/resources/macintosh_alpha70.bmp b/resources/image/macintosh_alpha70.bmp
similarity index 100%
rename from resources/macintosh_alpha70.bmp
rename to resources/image/macintosh_alpha70.bmp
diff --git a/resources/pixelDucks.png b/resources/image/pixelDucks.png
similarity index 100%
rename from resources/pixelDucks.png
rename to resources/image/pixelDucks.png
diff --git a/resources/plasma16.bmp b/resources/image/plasma16.bmp
similarity index 100%
rename from resources/plasma16.bmp
rename to resources/image/plasma16.bmp
diff --git a/resources/plasma24.bmp b/resources/image/plasma24.bmp
similarity index 100%
rename from resources/plasma24.bmp
rename to resources/image/plasma24.bmp
diff --git a/resources/plasma32.bmp b/resources/image/plasma32.bmp
similarity index 100%
rename from resources/plasma32.bmp
rename to resources/image/plasma32.bmp
diff --git a/resources/image/puro.bmp b/resources/image/puro.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..07317298cb2c4fbfbb3950a426887cf35fca0161
GIT binary patch
literal 17154
zcmZ?rWpZW!12YB&1`P%V25%^4WRL)hpK)SfP}YNBumA%CgNaE$@yKFu0OB2NV$whA
zN6g?F9MNcj=`cJZqw$CtIHU16I748Frd9lbiI)6E{fHJICMNy(18|VYqB(ms9?=4X
zp7DrgHAyK1P4A$MM>Kbi`VlPz(86al9?=41G(Vyx7z(+V!HXQ;eTG8jr|92Vvt6F)GSJtiwf;WYK6mVg@5g0Z55rOskPa
zNHTde9+86%!X_yIDNziu4i`z1$pqt(B-5y<7?2;e
zD@Kz=i#BILjvKsK7I(6Tm~EE*Rx9?=vGpudoOPT3DcO
zS{XcP6)nx6IU7G0O)nZ3&5vkYG{rPct7vxN_Y|5enqD+6ny1jXXo^SuNMU|N3s1C|
z!p}w1i^fHZI5aMr;?a0S3lM_Qim4ut2qp1|W-NvAh-MlU9Y#f?M*T=IKaR#DT6#kZ
z5d2&;y=YwgdeLO5n^w^bryCc|7x=kot|B$9qG_ia7r&>_WYJtT>PNHy89**tOyTFE
JxpRcXBLFk8cc%aV
literal 0
HcmV?d00001
diff --git a/test/imagePng.c b/test/imagePng.c
index c16ae36..4604d24 100644
--- a/test/imagePng.c
+++ b/test/imagePng.c
@@ -9,9 +9,9 @@ void testImagePng(void){
#ifdef TEST_PNG
testStart("png image");
- remove("resources/pixelDucksOut.png");
+ remove("resources/out/pixelDucks.png");
- LexlibImage image = lexlibImageLoadPng("resources/pixelDucks.png");
+ LexlibImage image = lexlibImageLoadPng("resources/image/pixelDucks.png");
if(!image.data){
switch(image.depth){
case LEXLIB_CANT_OPEN:
@@ -43,7 +43,7 @@ void testImagePng(void){
return;
}
- switch(lexlibImageSave(&image, "resources/pixelDucksOut.png")){
+ switch(lexlibImageSave(&image, "resources/out/pixelDucks.png")){
case 0:
break;
case LEXLIB_INVALID_VALUE:
--
GitLab
From 9961471f8a3b9d6b3ac00afaf1175e8b226d0198 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Mon, 15 May 2023 00:07:14 -0400
Subject: [PATCH 35/64] placed bmp in its own test file
---
CMakeLists.txt | 1 +
test/imageBmp.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++
test/test.c | 40 +-----------------
test/test.h | 1 +
4 files changed, 113 insertions(+), 39 deletions(-)
create mode 100644 test/imageBmp.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a5af99d..ce0dec1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,6 +72,7 @@ add_executable(test
test/path.c
test/linkedList.c
test/strPath.c
+ test/imageBmp.c
test/imagePng.c
test/colorblend.c
test/colorgray.c
diff --git a/test/imageBmp.c b/test/imageBmp.c
new file mode 100644
index 0000000..df15286
--- /dev/null
+++ b/test/imageBmp.c
@@ -0,0 +1,110 @@
+// Copyright 2023 alexevier
+// licensed under the MIT or Apache 2.0 (at your option)
+
+#include
+#include
+#include
+
+void testImageBmp(void){
+
+ {testStart("bmp plasma16");
+ LexlibImage image = lexlibImageLoadBmp("resources/image/plasma16.bmp");
+ if(!image.data)
+ switch(image.depth){
+ case LEXLIB_CANT_OPEN:
+ testEnd(0, "can't open \"resources/image/plasma16.bmp\"");
+ return;
+ case LEXLIB_INVALID_FILE_TYPE:
+ testEnd(0, "file is not a bmp");
+ return;
+ case LEXLIB_OUT_OF_MEMORY:
+ testEnd(0, "OOM");
+ return;
+ case LEXLIB_UNSUPORTED:
+ testEnd(0, "unsuported");
+ return;
+ default:
+ testEnd(0, "other error");
+ return;
+ }
+
+ lexlibImageFlip(&image, LEXLIB_FLIP_Y);
+ lexlibImageSave(&image, "resources/out/plasma16.png");
+ testEnd(1, NULL);}
+
+ {testStart("bmp plasma24");
+ LexlibImage image = lexlibImageLoadBmp("resources/image/plasma24.bmp");
+ if(!image.data)
+ switch(image.depth){
+ case LEXLIB_CANT_OPEN:
+ testEnd(0, "can't open \"resources/image/plasma24.bmp\"");
+ return;
+ case LEXLIB_INVALID_FILE_TYPE:
+ testEnd(0, "file is not a bmp");
+ return;
+ case LEXLIB_OUT_OF_MEMORY:
+ testEnd(0, "OOM");
+ return;
+ case LEXLIB_UNSUPORTED:
+ testEnd(0, "unsuported");
+ return;
+ default:
+ testEnd(0, "other error");
+ return;
+ }
+
+ lexlibImageFlip(&image, LEXLIB_FLIP_Y);
+ lexlibImageSave(&image, "resources/out/plasma24.png");
+ testEnd(1, NULL);}
+
+ {testStart("bmp plasma32");
+ LexlibImage image = lexlibImageLoadBmp("resources/image/plasma32.bmp");
+ if(!image.data)
+ switch(image.depth){
+ case LEXLIB_CANT_OPEN:
+ testEnd(0, "can't open \"resources/image/plasma32.bmp\"");
+ return;
+ case LEXLIB_INVALID_FILE_TYPE:
+ testEnd(0, "file is not a bmp");
+ return;
+ case LEXLIB_OUT_OF_MEMORY:
+ testEnd(0, "OOM");
+ return;
+ case LEXLIB_UNSUPORTED:
+ testEnd(0, "unsuported");
+ return;
+ default:
+ testEnd(0, "other error");
+ return;
+ }
+
+ lexlibImageFlip(&image, LEXLIB_FLIP_Y);
+ lexlibImageSave(&image, "resources/out/plasma32.png");
+ testEnd(1, NULL);}
+
+ {testStart("bmp puro");
+ LexlibImage image = lexlibImageLoadBmp("resources/image/puro.bmp");
+ if(!image.data)
+ switch(image.depth){
+ case LEXLIB_CANT_OPEN:
+ testEnd(0, "can't open \"resources/image/puro.bmp\"");
+ return;
+ case LEXLIB_INVALID_FILE_TYPE:
+ testEnd(0, "file is not a bmp");
+ return;
+ case LEXLIB_OUT_OF_MEMORY:
+ testEnd(0, "OOM");
+ return;
+ case LEXLIB_UNSUPORTED:
+ testEnd(0, "unsuported");
+ return;
+ default:
+ testEnd(0, "other error");
+ return;
+ }
+
+ lexlibImageFlip(&image, LEXLIB_FLIP_Y);
+ lexlibImageSave(&image, "resources/out/puro.png");
+ testEnd(1, NULL);}
+
+}
\ No newline at end of file
diff --git a/test/test.c b/test/test.c
index 25a1010..34772d0 100644
--- a/test/test.c
+++ b/test/test.c
@@ -26,6 +26,7 @@ int main(void){
testLinkedList();
testStrPath();
testImagePng();
+ testImageBmp();
testColorBlend();
testColorGray();
// testColorFlt();
@@ -41,45 +42,6 @@ int main(void){
return 1;
}
printf("all tests succeed.\n");
-
- {// temp bmp test
- mkdir("resources/out", 0777);
- printf("\n[plasma16.bmp]\n");
- LexlibImage image16 = lexlibImageLoadBmp("resources/plasma16.bmp");
- if(image16.channels == 0) printf("bmp16 ewwor :(\n");
- lexlibImageFlip(&image16, LEXLIB_FLIP_Y);
- lexlibImageSavePng(&image16, "resources/out/plasma16.png");
- lexlibImageDelete(&image16);
-
- printf("\n[plasma24.bmp]\n");
- LexlibImage image24 = lexlibImageLoadBmp("resources/plasma24.bmp");
- if(image24.channels == 0) printf("bmp24 ewwor :(\n");
- lexlibImageFlip(&image24, LEXLIB_FLIP_Y);
- lexlibImageSavePng(&image24, "resources/out/plasma24.png");
- lexlibImageDelete(&image24);
-
- printf("\n[plasma32.bmp]\n");
- LexlibImage image32 = lexlibImageLoadBmp("resources/plasma32.bmp");
- if(image32.channels == 0) printf("bmp32 ewwor :(\n");
- lexlibImageFlip(&image32, LEXLIB_FLIP_Y);
- lexlibImageSavePng(&image32, "resources/out/plasma32.png");
- lexlibImageDelete(&image32);
-
- printf("\n[macintosh_a70.bmp]\n");
- image32 = lexlibImageLoadBmp("resources/macintosh_alpha70.bmp");
- if(image32.channels == 0) printf("mac_a32 ewwor :(\n");
- lexlibImageFlip(&image32, LEXLIB_FLIP_Y);
- lexlibImageSavePng(&image32, "resources/out/macintosh_alpha70.png");
- lexlibImageDelete(&image32);
-
- printf("\n[macintosh_8bpp.bmp]\n");
- LexlibImage image8 = lexlibImageLoadBmp("resources/macintosh_8bpp.bmp");
- if(image8.channels == 0) printf("mac_bpp8 ewwor :(\n");
- lexlibImageFlip(&image8, LEXLIB_FLIP_Y);
- lexlibImageSavePng(&image8, "resources/out/macintosh_8bpp.png");
- lexlibImageDelete(&image8);
- }
- // printf("s: %zu\n",sizeof(LexlibImage));
return 0;
}
diff --git a/test/test.h b/test/test.h
index 7b915ff..db188d7 100644
--- a/test/test.h
+++ b/test/test.h
@@ -23,6 +23,7 @@ void testCompatCglm(void);
void testPath(void);
void testLinkedList(void);
void testStrPath(void);
+void testImageBmp(void);
void testImagePng(void);
void testColorBlend(void);
void testColorGray(void);
--
GitLab
From e736bd35f6c6d20d26b64a74b850ef2bff2c1372 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Mon, 15 May 2023 04:14:14 -0400
Subject: [PATCH 36/64] rewrote the bmp loader
---
include/lexlibinternal/bmp.h | 22 +-
src/image/bmp.c | 471 +++++++++++++++--------------------
test/imageBmp.c | 50 ++++
3 files changed, 265 insertions(+), 278 deletions(-)
diff --git a/include/lexlibinternal/bmp.h b/include/lexlibinternal/bmp.h
index 59fb673..6f744ca 100644
--- a/include/lexlibinternal/bmp.h
+++ b/include/lexlibinternal/bmp.h
@@ -31,9 +31,7 @@ typedef struct BmpFileHeader {
uint16_t reserved1;
uint16_t reserved2;
// offset in bytes where the bitmap data starts
- uint32_t start;
- // used for reading the size of the info header; WARNING this element is not official in the spec
- uint32_t infoHeaderSize;
+ uint32_t offset;
} BmpFileHeader;
#pragma pack(pop)
@@ -48,7 +46,7 @@ typedef struct BmpCoreHeader {
// number of color planes (must be 1)
uint16_t planes;
// number of bits per pixel
- uint16_t bitdepth;
+ uint16_t bitdepth;
} BmpCoreHeader;
// windows nt, 3.1x or later
@@ -72,9 +70,9 @@ typedef struct BmpInfoHeader {
// vertical resolution, in pixels per meter
int32_t yresm;
// number of color indices in the color table
- uint32_t colorpalette;
+ uint32_t colorPalette;
// number of color indices that are considered important, if zero all are important
- uint32_t colorimportant;
+ uint32_t colorImportant;
} BmpInfoHeader;
// header 2 is not documented
@@ -100,9 +98,9 @@ typedef struct BmpInfoHeader3 {
// vertical resolution, in pixels per meter
int32_t yresm;
// number of color indices in the color table
- uint32_t colorpalette;
+ uint32_t colorPalette;
// number of color indices that are considered important, if zero all are important
- uint32_t colorimportant;
+ uint32_t colorImportant;
// red color per pixel bit mask
uint32_t redbitmask;
// green color per pixel bit mask
@@ -134,9 +132,9 @@ typedef struct BmpInfoHeader4 {
// vertical resolution, in pixels per meter
int32_t yresm;
// number of color indices in the color table
- uint32_t colorpalette;
+ uint32_t colorPalette;
// number of color indices that are considered important, if zero all are important.
- uint32_t colorimportant;
+ uint32_t colorImportant;
// red color per pixel bit mask
uint32_t redbitmask;
// green color per pixel bit mask
@@ -178,9 +176,9 @@ typedef struct BmpInfoHeader5 {
// vertical resolution, in pixels per meter
int32_t yresm;
// number of color indices in the color table
- uint32_t colorpalette;
+ uint32_t colorPalette;
// number of color indices that are considered important, if zero all are important
- uint32_t colorimportant;
+ uint32_t colorImportant;
// red color per pixel bit mask
uint32_t redbitmask;
// green color per pixel bit mask
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 1ad68ab..02aa9e1 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -40,17 +40,16 @@
◯ ◯ BmpInfoHeader5 | 0..32 bpp
> Compression
- C I 2 3 4 5
- ◯ ● ◯ ● ◯ ◯ RGB | none | most common
- ◯ ◯ ◯ ◯ ◯ ◯ RLE8 | RLE 8bit | only with 8-bit/pixel
- ◯ ◯ ◯ ◯ ◯ ◯ RLE4 | RLE 4bit | only with 4-bit/pixel
- ◯ ● ◯ ● ◯ ◯ BITFIELDS | RGB bit field masks
- ◯ ◯ ◯ ◯ ◯ ◯ JPEG | ?
- ◯ ◯ ◯ ◯ ◯ ◯ PNG | ?
- ◯ ● ◯ ● ◯ ◯ ALPHABITFIELDS | RGBA bit field masks
- ◯ ◯ ◯ ◯ ◯ ◯ CMYK | none
- ◯ ◯ ◯ ◯ ◯ ◯ CMYKRLE8 | RLE-8 | only windows metafile
- ◯ ◯ ◯ ◯ ◯ ◯ CMYKRLE4 | RLE-4 | only windows metafile
+ ● RGB | none | most common
+ ◯ RLE8 | RLE 8bit | only with 8-bit/pixel
+ ◯ RLE4 | RLE 4bit | only with 4-bit/pixel
+ ● BITFIELDS | RGB/A bit field masks
+ ◯ JPEG | ?
+ ◯ PNG | ?
+ ● ALPHABITFIELDS | RGBA bit field masks
+ ◯ CMYK | none
+ ◯ CMYKRLE8 | RLE-8 | only windows metafile
+ ◯ CMYKRLE4 | RLE-4 | only windows metafile
> Color Table
usually the order is bgr0.
@@ -63,11 +62,13 @@
◯ ◯ ◯ ◯ ◯ ◯ 1bpp : 2 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 2bpp : 4 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 4bpp : 16 colors | table
- ◯ ● ◯ ◯ ◯ ◯ 8bpp : 256 colors | table
+ ◯ ◯ ◯ ◯ ◯ ◯ 8bpp : 256 colors | table
◯ ● ◯ ● ◯ ◯ 16bpp: 65536 colors | 555, 565, bitmask.
◯ ● ◯ ● ◯ ◯ 24bpp: 16777216 colors | b,g,r.
◯ ● ◯ ● ◯ ◯ 32bpp: 4294967296 colors | a,b,g,r.
+> pixel storage
+ The size of each row is rounded up to a multiple of 4 bytes.
*/
// to store bitmasks and shifts
@@ -100,339 +101,277 @@ static ColorBitMask colorBitMaskGet(const uint32_t* data, uint8_t bitfields);
#define LEXLIB_RGBA_BITFIELDS 0x0B
#define LEXLIB_RGB_PALETTE 0x0C
+#define COLORBITMASK_BGRA_8888 ((ColorBitMask){8, 8, 8, 8, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, 16, 8, 0, 24})
+#define COLORBITMASK_BGRA_555 ((ColorBitMask){5, 6, 5, 8, 0x0000FC00, 0x000003E0, 0x0000001F, 0x00000000, 16, 8, 0, 00})
+#define COLORBITMASK_BGRA_565 ((ColorBitMask){5, 6, 5, 8, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000, 16, 8, 0, 00})
+
// TODO probably needs big endian to little transforms on big endian machines
LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
+
+ // load file as bytes
LexlibBytes bmp = lexlibFileBytes(filename);
if(!bmp.data){
image.depth = bmp.count;
return image;
}
- BmpFileHeader* fileheader = (BmpFileHeader*)bmp.data;
+ BmpFileHeader* fileHeader = (BmpFileHeader*)(bmp.data);
+ BmpCoreHeader* coreHeader = (BmpCoreHeader*)(bmp.data + sizeof(BmpFileHeader));
- /* check if file is bmp */
- if(fileheader->type != 0x4D42){
+ // check if file is bmp
+ if(fileHeader->type != 0x4D42){
image.depth = LEXLIB_INVALID_FILE_TYPE;
free(bmp.data);
return image;
}
- /* info header */
- if(fileheader->infoHeaderSize == 40){
- BmpInfoHeader* infoheader = (BmpInfoHeader*)(bmp.data+14);
+ // check if header is valid
+ switch(coreHeader->size){
+ // supported
+ case sizeof(BmpInfoHeader):
+ case sizeof(BmpInfoHeader3):
+ break;
+ // unsuported
+ case sizeof(BmpCoreHeader):
+ case sizeof(BmpInfoHeader4):
+ case sizeof(BmpInfoHeader5):
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
+ default:
+ free(bmp.data);
+ image.depth = LEXLIB_INVALID_FILE_DATA;
+ return image;
+ }
+
+ ColorBitMask bitMask = {0};
+ LexlibColorFlt colorMax = {0};
+ uint8_t profile = 0;
+ uint8_t bmpPixelSize = 0;
+ uint8_t bmpRowStride = 0;
+ uint8_t bmpRowPadding = 0;
+
+ // InfoHeader
+ if(coreHeader->size == sizeof(BmpInfoHeader)){
+ BmpInfoHeader infoHeader;
+ memcpy(&infoHeader, coreHeader, sizeof(BmpInfoHeader));
- ColorBitMask colorMask = {0};
- LexlibColorFlt colorMax = {0};
- uint8_t profile = 0;
- uint8_t bmpPixelSize = 0;
+ image.width = infoHeader.width;
+ image.height = infoHeader.height;
+ bmpRowStride = ((((infoHeader.width * infoHeader.bitdepth) + 31) & ~31) >> 3);
+ bmpRowPadding = (bmpRowStride) - (infoHeader.width * (infoHeader.bitdepth / 8));
// check for compression
- switch(infoheader->compression){
+ switch(infoHeader.compression){
case BMP_RGB:
break;
case BMP_BITFIELDS:
- colorMask = colorBitMaskGet((uint32_t*)(bmp.data+54), LEXLIB_RGB_BITFIELDS);
- profile = LEXLIB_RGB_BITFIELDS;
+ bitMask = colorBitMaskGet((uint32_t*)(bmp.data + sizeof(BmpFileHeader) + sizeof(BmpInfoHeader)), LEXLIB_RGB_BITFIELDS);
// calculate max color value
- colorMax.r = lexlibPowu(2, colorMask.r) - 1;
- colorMax.g = lexlibPowu(2, colorMask.g) - 1;
- colorMax.b = lexlibPowu(2, colorMask.b) - 1;
+ colorMax.r = lexlibPowu(2, bitMask.r) - 1;
+ colorMax.g = lexlibPowu(2, bitMask.g) - 1;
+ colorMax.b = lexlibPowu(2, bitMask.b) - 1;
+ profile = LEXLIB_RGB_BITFIELDS;
break;
case BMP_ALPHABITFIELDS:
- colorMask = colorBitMaskGet((uint32_t*)(bmp.data+54), LEXLIB_RGBA_BITFIELDS);
- profile = LEXLIB_RGB_BITFIELDS;
+ bitMask = colorBitMaskGet((uint32_t*)(bmp.data + sizeof(BmpFileHeader) + sizeof(BmpInfoHeader)), LEXLIB_RGBA_BITFIELDS);
// calculate max color value
- colorMax.r = lexlibPowu(2, colorMask.r) - 1;
- colorMax.g = lexlibPowu(2, colorMask.g) - 1;
- colorMax.b = lexlibPowu(2, colorMask.b) - 1;
- colorMax.a = lexlibPowu(2, colorMask.a);
+ colorMax.r = lexlibPowu(2, bitMask.r) - 1;
+ colorMax.g = lexlibPowu(2, bitMask.g) - 1;
+ colorMax.b = lexlibPowu(2, bitMask.b) - 1;
+ colorMax.a = lexlibPowu(2, bitMask.a) - 1;
+ profile = LEXLIB_RGBA_BITFIELDS;
break;
default: // unsuported
free(bmp.data);
- lexlibImageDelete(&image);
image.depth = LEXLIB_UNSUPORTED;
return image;
- break;
}
- // check for color profile
- switch(infoheader->bitdepth){
- case 8:
- bmpPixelSize = 1;
+ // check for profile
+ switch(infoHeader.bitdepth){
+ case 16:
image.depth = 8;
image.profile = LEXLIB_RGB;
- if(infoheader->colorpalette){
- profile = LEXLIB_RGB_PALETTE;
- if(infoheader->compression){
- free(bmp.data);
- image.depth = LEXLIB_UNSUPORTED;
- return image;
- }
- break;
- }
- if(infoheader->compression == BMP_BITFIELDS){
- image.profile = (colorMask.a) ? LEXLIB_RGBA : LEXLIB_RGB;
- break;
- }
- if(infoheader->compression == BMP_ALPHABITFIELDS){
- image.profile = LEXLIB_RGBA;
- break;
- }
- free(bmp.data);
- image.depth = LEXLIB_UNSUPORTED;
- return image;
- break;
- case 16:
bmpPixelSize = 2;
- if(infoheader->compression == BMP_RGB){
- profile = LEXLIB_RGB555;
- image.depth = 8;
- image.profile = LEXLIB_RGB;
- colorMax.r = 31.0f;
- colorMax.g = 31.0f;
- colorMax.b = 31.0f;
- break;
- }
- if(infoheader->compression == BMP_BITFIELDS){
- image.depth = 8;
- image.profile = (colorMask.a) ? LEXLIB_RGBA : LEXLIB_RGB;
- break;
+ if(!infoHeader.compression){
+ profile = LEXLIB_RGB_BITFIELDS;
+ bitMask = COLORBITMASK_BGRA_555;
}
- if(infoheader->compression == BMP_ALPHABITFIELDS){
- image.depth = 8;
- image.profile = LEXLIB_RGBA;
- break;
- }
- free(bmp.data);
- image.depth = LEXLIB_INVALID_FILE_DATA;
- return image;
+ break;
case 24:
image.depth = 8;
image.profile = LEXLIB_RGB;
- if(!profile)
- profile = LEXLIB_RGB;
bmpPixelSize = 3;
+ if(!infoHeader.compression){
+ profile = LEXLIB_RGB;
+ }
break;
case 32:
image.depth = 8;
image.profile = LEXLIB_RGBA;
- if(!profile)
- profile = LEXLIB_RGBA;
bmpPixelSize = 4;
+ if(!infoHeader.compression){
+ profile = LEXLIB_RGBA;
+ break;
+ }
break;
- default:
+ default: // unsuported
free(bmp.data);
image.depth = LEXLIB_UNSUPORTED;
return image;
}
-
- // create image and set offsets
- image = lexlibImageNew(infoheader->width, infoheader->height, image.profile, image.depth);
- if(!image.data){
- free(bmp.data);
- return image;
- }
- uint64_t pixelCount = image.width * image.height;
- size_t bmpoffset = fileheader->start;
- size_t imgoffset = 0;
-
- // load pixel data from bmp to lexlib image
- if(profile == LEXLIB_RGB_BITFIELDS)
- for(uint64_t i = 0; i < pixelCount; i++){
- uint16_t bmppixel = *((uint32_t*)(bmp.data+bmpoffset));
-
- image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.rb) >> colorMask.rs) / colorMax.r) * 255.0f);
- image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.gb) >> colorMask.gs) / colorMax.g) * 255.0f);
- image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bb) >> colorMask.bs) / colorMax.b) * 255.0f);
- image.data[imgoffset+3] = (image.profile == LEXLIB_RGBA) ? rintf(( ((bmppixel & colorMask.ab) >> colorMask.as) / colorMax.a) * 256.0f) - 1 : 0xFF;
-
- bmpoffset += bmpPixelSize;
- imgoffset += image.channels;
- }
-
- if(profile == LEXLIB_RGB555)
- for(uint64_t i = 0; i < pixelCount; i++){
- uint16_t bmppixel = *((uint16_t*)(bmp.data+bmpoffset));
-
- image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.rb) >> 10) / 31.0f) * 255.0f);
- image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.gb) >> 5) / 31.0f) * 255.0f);
- image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bb) >> 0) / 31.0f) * 255.0f);
- if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
-
- bmpoffset += 2;
- imgoffset += image.channels;
- }
-
- if(profile == LEXLIB_RGB)
- for(uint64_t i = 0; i < pixelCount; i++){
- image.data[imgoffset+0] = bmp.data[bmpoffset+2];
- image.data[imgoffset+1] = bmp.data[bmpoffset+1];
- image.data[imgoffset+2] = bmp.data[bmpoffset+0];
- if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
-
- bmpoffset+=3;
- imgoffset+=image.channels;
- }
-
- if(profile == LEXLIB_RGBA)
- for(uint64_t i = 0; i < pixelCount; i++){
- image.data[imgoffset+0] = bmp.data[bmpoffset+3];
- image.data[imgoffset+1] = bmp.data[bmpoffset+2];
- image.data[imgoffset+2] = bmp.data[bmpoffset+1];
- image.data[imgoffset+3] = bmp.data[bmpoffset+0];
-
- bmpoffset+=4;
- imgoffset+=image.channels;
- }
-
- if(profile == LEXLIB_RGB_PALETTE){
- LexlibColor8* palette = (LexlibColor8*)(bmp.data+54);
- for(uint64_t i = 0; i < pixelCount; i++){
-
- image.data[imgoffset+0] = palette[bmp.data[bmpoffset]].b;
- image.data[imgoffset+1] = palette[bmp.data[bmpoffset]].g;
- image.data[imgoffset+2] = palette[bmp.data[bmpoffset]].r;
- if(image.profile == LEXLIB_RGBA) image.data[imgoffset+4] = palette[bmp.data[bmpoffset]].a;
-
- bmpoffset += bmpPixelSize;
- imgoffset += image.channels;
- }}
-
- free(bmp.data);
- return image;
- }/* ..info header.. */
+ }
- /* info header v3 */
- if(fileheader->infoHeaderSize == 56){
- BmpInfoHeader3* infoheader3 = (BmpInfoHeader3*)(bmp.data+14);
+ // InfoHeader v3
+ if(coreHeader->size == sizeof(BmpInfoHeader3)){
+ BmpInfoHeader3* infoHeader3 = (BmpInfoHeader3*)coreHeader;
- ColorBitMask colorMask = {0};
- LexlibColorFlt colorMax = {0};
- uint8_t profile = 0;
- uint8_t bmpPixelSize = 0;
+ image.width = infoHeader3->width;
+ image.height = infoHeader3->height;
+ bmpRowStride = ((((infoHeader3->width * infoHeader3->bitdepth) + 31) & ~31) >> 3);
+ bmpRowPadding = (bmpRowStride) - (infoHeader3->width * (infoHeader3->bitdepth / 8));
// check for compression
- switch(infoheader3->compression){
+ switch(infoHeader3->compression){
case BMP_RGB:
break;
case BMP_BITFIELDS:
case BMP_ALPHABITFIELDS:
- colorMask = colorBitMaskGet((uint32_t*)(bmp.data+54), LEXLIB_RGBA_BITFIELDS);
- profile = LEXLIB_RGB_BITFIELDS;
+ bitMask = colorBitMaskGet(&infoHeader3->redbitmask, LEXLIB_RGBA_BITFIELDS);
// calculate max color value
- colorMax.r = lexlibPowu(2, colorMask.r) - 1;
- colorMax.g = lexlibPowu(2, colorMask.g) - 1;
- colorMax.b = lexlibPowu(2, colorMask.b) - 1;
- colorMax.a = lexlibPowu(2, colorMask.a);
+ colorMax.r = lexlibPowu(2, bitMask.r) - 1;
+ colorMax.g = lexlibPowu(2, bitMask.g) - 1;
+ colorMax.b = lexlibPowu(2, bitMask.b) - 1;
+ if(bitMask.a){
+ colorMax.a = lexlibPowu(2, bitMask.a) - 1;
+ profile = LEXLIB_RGBA_BITFIELDS;
+ } else {
+ profile = LEXLIB_RGB_BITFIELDS;
+ }
break;
default: // unsuported
free(bmp.data);
- lexlibImageDelete(&image);
image.depth = LEXLIB_UNSUPORTED;
return image;
- break;
}
- // set the color profile
- if(infoheader3->bitdepth == 8){
- free(bmp.data);
- image.depth = LEXLIB_UNSUPORTED;
- return image;
- }
- if(infoheader3->bitdepth == 16){
- image.depth = 8;
- image.profile = (colorMask.a) ? LEXLIB_RGBA : LEXLIB_RGB;
- if(!profile)
- profile = LEXLIB_RGB555;
- bmpPixelSize = 2;
- }
- if(infoheader3->bitdepth == 24){
- image.depth = 8;
- image.profile = LEXLIB_RGB;
- if(!profile)
- profile = LEXLIB_RGB;
- bmpPixelSize = 3;
- }
- if(infoheader3->bitdepth == 32){
- image.depth = 8;
- image.profile = LEXLIB_RGBA;
- if(!profile)
- profile = LEXLIB_RGBA;
- bmpPixelSize = 4;
- }
-
- // create image and set offsets
- image = lexlibImageNew(infoheader3->width, infoheader3->height, image.profile, image.depth);
- if(!image.data){
- free(bmp.data);
- return image;
+ // check for profile
+ switch(infoHeader3->bitdepth){
+ case 16:
+ image.depth = 8;
+ image.profile = LEXLIB_RGB;
+ bmpPixelSize = 2;
+ if(!infoHeader3->compression){
+ profile = LEXLIB_RGB_BITFIELDS;
+ bitMask = COLORBITMASK_BGRA_555;
+ }
+ break;
+ case 24:
+ image.depth = 8;
+ image.profile = LEXLIB_RGB;
+ bmpPixelSize = 3;
+ if(!infoHeader3->compression)
+ profile = LEXLIB_RGB;
+ break;
+ case 32:
+ image.depth = 8;
+ image.profile = LEXLIB_RGBA;
+ bmpPixelSize = 4;
+ if(!infoHeader3->compression)
+ profile = LEXLIB_RGBA;
+ break;
+ default: // unsuported
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
}
- uint64_t pixelCount = image.width * image.height;
- size_t bmpoffset = fileheader->start;
- size_t imgoffset = 0;
-
- // load pixel data from bmp to lexlib image
- if(profile == LEXLIB_RGB_BITFIELDS)
- for(uint64_t i = 0; i < pixelCount; i++){
- uint32_t bmppixel = *((uint32_t*)(bmp.data+bmpoffset));
-
- image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.rb) >> colorMask.rs) / colorMax.r) * 255.0f);
- image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.gb) >> colorMask.gs) / colorMax.g) * 255.0f);
- image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bb) >> colorMask.bs) / colorMax.b) * 255.0f);
- image.data[imgoffset+3] = (image.profile == LEXLIB_RGBA) ? rintf(( ((bmppixel & colorMask.ab) >> colorMask.as) / colorMax.a) * 256.0f) - 1 : 0xFF;
+ }
+
+ // create image
+ image = lexlibImageNew(image.width, image.height, image.profile, image.depth);
+ if(!image.data){
+ free(bmp.data);
+ return image;
+ }
+
+ // set image pixels depending of the profile
+ if(profile == LEXLIB_RGB){ // perfect RGB, 8.8.8
+ uint8_t* bmpOffset = bmp.data + fileHeader->offset;
+ for(uint32_t y = 0; y < image.height; y++){
+ for(uint32_t x = 0; x < image.width; x++){
+ LexlibColor imgPixel = {
+ .r = bmpOffset[2],
+ .g = bmpOffset[1],
+ .b = bmpOffset[0],
+ .a = 0xFF
+ };
+ lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
- bmpoffset += bmpPixelSize;
- imgoffset += image.channels;
+ bmpOffset += bmpPixelSize;
}
-
- if(profile == LEXLIB_RGB555)
- for(uint64_t i = 0; i < pixelCount; i++){
- uint16_t bmppixel = *((uint16_t*)(bmp.data+bmpoffset));
-
- image.data[imgoffset+0] = rintf(( ((bmppixel & colorMask.rb) >> 10) / 31.0f) * 255.0f);
- image.data[imgoffset+1] = rintf(( ((bmppixel & colorMask.gb) >> 5) / 31.0f) * 255.0f);
- image.data[imgoffset+2] = rintf(( ((bmppixel & colorMask.bb) >> 0) / 31.0f) * 255.0f);
- if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
+ bmpOffset += bmpRowPadding;
+ }}
+
+ if(profile == LEXLIB_RGBA){ // perfect RGBA, 8.8.8.8
+ uint8_t* bmpOffset = (uint8_t*)(bmp.data + fileHeader->offset);
+ for(uint32_t y = 0; y < image.height; y++){
+ for(uint32_t x = 0; x < image.width; x++){
+ LexlibColor imgPixel = {
+ .r = bmpOffset[2],
+ .g = bmpOffset[1],
+ .b = bmpOffset[0],
+ .a = bmpOffset[4]
+ };
+ lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
- bmpoffset += 2;
- imgoffset += image.channels;
+ bmpOffset += bmpPixelSize;
}
-
- if(profile == LEXLIB_RGB)
- for(uint64_t i = 0; i < pixelCount; i++){
- image.data[imgoffset+0] = bmp.data[bmpoffset+2];
- image.data[imgoffset+1] = bmp.data[bmpoffset+1];
- image.data[imgoffset+2] = bmp.data[bmpoffset+0];
- if(image.profile == LEXLIB_RGBA){ image.data[imgoffset+3] = 0xFF; }
+ bmpOffset += bmpRowPadding;
+ }}
+
+ if(profile == LEXLIB_RGB_BITFIELDS){ // bitfields without alpha
+ uint32_t* bmpOffset = (uint32_t*)(bmp.data + fileHeader->offset);
+ for(uint32_t y = 0; y < image.height; y++){
+ for(uint32_t x = 0; x < image.width; x++){
+ uint32_t bmpPixel = *bmpOffset;
- bmpoffset+=3;
- imgoffset+=image.channels;
- }
-
- if(profile == LEXLIB_RGBA)
- for(uint64_t i = 0; i < pixelCount; i++){
- image.data[imgoffset+0] = bmp.data[bmpoffset+3];
- image.data[imgoffset+1] = bmp.data[bmpoffset+2];
- image.data[imgoffset+2] = bmp.data[bmpoffset+1];
- image.data[imgoffset+3] = bmp.data[bmpoffset+0];
+ LexlibColor imgPixel = {
+ .r = rintf((((bmpPixel & bitMask.rb) >> bitMask.rs) / colorMax.r) * 255.0f),
+ .g = rintf((((bmpPixel & bitMask.gb) >> bitMask.gs) / colorMax.g) * 255.0f),
+ .b = rintf((((bmpPixel & bitMask.bb) >> bitMask.bs) / colorMax.b) * 255.0f),
+ .a = 0xFF
+ };
+ lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
- bmpoffset+=4;
- imgoffset+=image.channels;
+ bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpPixelSize);
}
-
- free(bmp.data);
- return image;
- }/* ..info header v3.. */
+ bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpRowPadding);
+ }}
- LEXLIB_UNREACHABLE
- if(bmp.data)
- free(bmp.data);
+ if(profile == LEXLIB_RGBA_BITFIELDS){ // bitfields with alpha
+ uint32_t* bmpOffset = (uint32_t*)(bmp.data + fileHeader->offset);
+ for(uint32_t y = 0; y < image.height; y++){
+ for(uint32_t x = 0; x < image.width; x++){
+ uint32_t bmpPixel = *bmpOffset;
+ LexlibColor imgPixel = {
+ .r = rintf((((bmpPixel & bitMask.rb) >> bitMask.rs) / colorMax.r) * 255.0f),
+ .g = rintf((((bmpPixel & bitMask.gb) >> bitMask.gs) / colorMax.g) * 255.0f),
+ .b = rintf((((bmpPixel & bitMask.bb) >> bitMask.bs) / colorMax.b) * 255.0f),
+ .a = rintf((((bmpPixel & bitMask.ab) >> bitMask.as) / colorMax.a) * 255.0f),
+ };
+ lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
+
+ bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpPixelSize);
+ }
+ bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpRowPadding);
+ }}
+ free(bmp.data);
return image;
}
-
/* Static Functions */
#define UNSIGNED_BIT_WIDTH (CHAR_BIT * sizeof(unsigned))
LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index){
diff --git a/test/imageBmp.c b/test/imageBmp.c
index df15286..8c98b67 100644
--- a/test/imageBmp.c
+++ b/test/imageBmp.c
@@ -82,6 +82,56 @@ void testImageBmp(void){
lexlibImageSave(&image, "resources/out/plasma32.png");
testEnd(1, NULL);}
+ {testStart("bmp macintosh");
+ LexlibImage image = lexlibImageLoadBmp("resources/image/macintosh.bmp");
+ if(!image.data)
+ switch(image.depth){
+ case LEXLIB_CANT_OPEN:
+ testEnd(0, "can't open \"resources/image/macintosh.bmp\"");
+ return;
+ case LEXLIB_INVALID_FILE_TYPE:
+ testEnd(0, "file is not a bmp");
+ return;
+ case LEXLIB_OUT_OF_MEMORY:
+ testEnd(0, "OOM");
+ return;
+ case LEXLIB_UNSUPORTED:
+ testEnd(0, "unsuported");
+ return;
+ default:
+ testEnd(0, "other error");
+ return;
+ }
+
+ lexlibImageFlip(&image, LEXLIB_FLIP_Y);
+ lexlibImageSave(&image, "resources/out/macintosh.png");
+ testEnd(1, NULL);}
+
+ {testStart("bmp macintosh_alpha70");
+ LexlibImage image = lexlibImageLoadBmp("resources/image/macintosh_alpha70.bmp");
+ if(!image.data)
+ switch(image.depth){
+ case LEXLIB_CANT_OPEN:
+ testEnd(0, "can't open \"resources/image/macintosh_alpha70.bmp\"");
+ return;
+ case LEXLIB_INVALID_FILE_TYPE:
+ testEnd(0, "file is not a bmp");
+ return;
+ case LEXLIB_OUT_OF_MEMORY:
+ testEnd(0, "OOM");
+ return;
+ case LEXLIB_UNSUPORTED:
+ testEnd(0, "unsuported");
+ return;
+ default:
+ testEnd(0, "other error");
+ return;
+ }
+
+ lexlibImageFlip(&image, LEXLIB_FLIP_Y);
+ lexlibImageSave(&image, "resources/out/macintosh_alpha70.png");
+ testEnd(1, NULL);}
+
{testStart("bmp puro");
LexlibImage image = lexlibImageLoadBmp("resources/image/puro.bmp");
if(!image.data)
--
GitLab
From 1db8ce4572d3249ba2af1b416693523f2297aa45 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Mon, 15 May 2023 15:25:28 -0400
Subject: [PATCH 37/64] fixed segfault when setting a pixel in image
---
src/image.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/image.c b/src/image.c
index df7f216..e666add 100644
--- a/src/image.c
+++ b/src/image.c
@@ -188,8 +188,12 @@ uint8_t lexlibImagePixelSet(const LexlibImage* image, uint32_t x, uint32_t y, Le
return LEXLIB_OK;
}
if(image->channels == 3){
- LexlibColor pixel = *((LexlibColor*)image->data+offset);
- pixel.a = -1;
+ LexlibColor pixel = {
+ .r = image->data[offset+0],
+ .g = image->data[offset+1],
+ .b = image->data[offset+2],
+ .a = 0xFF,
+ };
pixel = lexlibColorPremultiply(lexlibColorBlend(pixel, color, blendmode));
image->data[offset+0] = pixel.r;
image->data[offset+1] = pixel.g;
--
GitLab
From 5a438c492a3cfd205c6af26f4ab97ab88d97ed9b Mon Sep 17 00:00:00 2001
From: alexevier
Date: Mon, 15 May 2023 15:51:35 -0400
Subject: [PATCH 38/64] bmp 8bpp support
---
src/image/bmp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++---
test/imageBmp.c | 28 +++++++++++++++++++++--
2 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 02aa9e1..558b4ab 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -62,7 +62,7 @@
◯ ◯ ◯ ◯ ◯ ◯ 1bpp : 2 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 2bpp : 4 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 4bpp : 16 colors | table
- ◯ ◯ ◯ ◯ ◯ ◯ 8bpp : 256 colors | table
+ ◯ ● ◯ ● ◯ ◯ 8bpp : 256 colors | table
◯ ● ◯ ● ◯ ◯ 16bpp: 65536 colors | 555, 565, bitmask.
◯ ● ◯ ● ◯ ◯ 24bpp: 16777216 colors | b,g,r.
◯ ● ◯ ● ◯ ◯ 32bpp: 4294967296 colors | a,b,g,r.
@@ -149,8 +149,9 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
LexlibColorFlt colorMax = {0};
uint8_t profile = 0;
uint8_t bmpPixelSize = 0;
- uint8_t bmpRowStride = 0;
- uint8_t bmpRowPadding = 0;
+ uint32_t bmpRowStride = 0;
+ uint32_t bmpRowPadding = 0;
+ uint32_t bmpHeadOffset = sizeof(BmpFileHeader);
// InfoHeader
if(coreHeader->size == sizeof(BmpInfoHeader)){
@@ -161,6 +162,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.height = infoHeader.height;
bmpRowStride = ((((infoHeader.width * infoHeader.bitdepth) + 31) & ~31) >> 3);
bmpRowPadding = (bmpRowStride) - (infoHeader.width * (infoHeader.bitdepth / 8));
+ bmpHeadOffset += sizeof(BmpInfoHeader);
// check for compression
switch(infoHeader.compression){
@@ -173,6 +175,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
colorMax.g = lexlibPowu(2, bitMask.g) - 1;
colorMax.b = lexlibPowu(2, bitMask.b) - 1;
profile = LEXLIB_RGB_BITFIELDS;
+ bmpHeadOffset += 12;
break;
case BMP_ALPHABITFIELDS:
bitMask = colorBitMaskGet((uint32_t*)(bmp.data + sizeof(BmpFileHeader) + sizeof(BmpInfoHeader)), LEXLIB_RGBA_BITFIELDS);
@@ -182,6 +185,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
colorMax.b = lexlibPowu(2, bitMask.b) - 1;
colorMax.a = lexlibPowu(2, bitMask.a) - 1;
profile = LEXLIB_RGBA_BITFIELDS;
+ bmpHeadOffset += 16;
break;
default: // unsuported
free(bmp.data);
@@ -191,6 +195,21 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
// check for profile
switch(infoHeader.bitdepth){
+ case 8:
+ image.depth = 8;
+ image.profile = LEXLIB_RGB;
+ bmpPixelSize = 1;
+ if(infoHeader.colorPalette){
+ profile = LEXLIB_RGB_PALETTE;
+ bitMask.rb = 0x000000FF;
+ }
+ if(infoHeader.compression){
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
+ }
+
+ break;
case 16:
image.depth = 8;
image.profile = LEXLIB_RGB;
@@ -232,6 +251,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.height = infoHeader3->height;
bmpRowStride = ((((infoHeader3->width * infoHeader3->bitdepth) + 31) & ~31) >> 3);
bmpRowPadding = (bmpRowStride) - (infoHeader3->width * (infoHeader3->bitdepth / 8));
+ bmpHeadOffset += sizeof(BmpInfoHeader3);
// check for compression
switch(infoHeader3->compression){
@@ -259,6 +279,20 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
// check for profile
switch(infoHeader3->bitdepth){
+ case 8:
+ image.depth = 8;
+ image.profile = LEXLIB_RGB;
+ bmpPixelSize = 1;
+ if(infoHeader3->colorPalette){
+ profile = LEXLIB_RGB_PALETTE;
+ bitMask.rb = 0x000000FF;
+ }
+ if(infoHeader3->compression){
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
+ }
+ break;
case 16:
image.depth = 8;
image.profile = LEXLIB_RGB;
@@ -368,6 +402,27 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpRowPadding);
}}
+ // here bitMask.rb is used to determine how much of bmpOffset should be used;
+ // 0x000000FF for 8 bit, 0x0000FFFF for 16 and so on.
+ if(profile == LEXLIB_RGB_PALETTE){ // color palette
+ uint32_t* bmpOffset = (uint32_t*)(bmp.data + fileHeader->offset);
+ uint32_t* palette = (uint32_t*)(bmp.data + bmpHeadOffset);
+ for(uint32_t y = 0; y < image.height; y++){
+ for(uint32_t x = 0; x < image.width; x++){
+ uint32_t bmpPixel = palette[*bmpOffset & bitMask.rb];
+ LexlibColor imgPixel = {
+ .r = bmpPixel >> 16,
+ .g = bmpPixel >> 8,
+ .b = bmpPixel >> 0,
+ .a = 0xFF,
+ };
+ lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
+
+ bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpPixelSize);
+ }
+ bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpRowPadding);
+ }}
+
free(bmp.data);
return image;
}
diff --git a/test/imageBmp.c b/test/imageBmp.c
index 8c98b67..b26fa30 100644
--- a/test/imageBmp.c
+++ b/test/imageBmp.c
@@ -132,6 +132,31 @@ void testImageBmp(void){
lexlibImageSave(&image, "resources/out/macintosh_alpha70.png");
testEnd(1, NULL);}
+ {testStart("bmp macintosh_8bpp");
+ LexlibImage image = lexlibImageLoadBmp("resources/image/macintosh_8bpp.bmp");
+ if(!image.data)
+ switch(image.depth){
+ case LEXLIB_CANT_OPEN:
+ testEnd(0, "can't open \"resources/image/macintosh_8bpp.bmp\"");
+ return;
+ case LEXLIB_INVALID_FILE_TYPE:
+ testEnd(0, "file is not a bmp");
+ return;
+ case LEXLIB_OUT_OF_MEMORY:
+ testEnd(0, "OOM");
+ return;
+ case LEXLIB_UNSUPORTED:
+ testEnd(0, "unsuported");
+ return;
+ default:
+ testEnd(0, "other error");
+ return;
+ }
+
+ lexlibImageFlip(&image, LEXLIB_FLIP_Y);
+ lexlibImageSave(&image, "resources/out/macintosh_8bpp.png");
+ testEnd(1, NULL);}
+
{testStart("bmp puro");
LexlibImage image = lexlibImageLoadBmp("resources/image/puro.bmp");
if(!image.data)
@@ -155,6 +180,5 @@ void testImageBmp(void){
lexlibImageFlip(&image, LEXLIB_FLIP_Y);
lexlibImageSave(&image, "resources/out/puro.png");
- testEnd(1, NULL);}
-
+ testEnd(1, NULL);}
}
\ No newline at end of file
--
GitLab
From 9912d4c054e172bad03e6b535acfda03c0bb77d8 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Mon, 15 May 2023 17:46:44 -0400
Subject: [PATCH 39/64] bmp 1bpp coreheader support
---
resources/image/floppy.bmp | Bin 0 -> 126 bytes
src/image/bmp.c | 63 ++++++++++++++++++++++++++++++++++---
test/imageBmp.c | 35 ++++++++++++++++++++-
3 files changed, 93 insertions(+), 5 deletions(-)
create mode 100644 resources/image/floppy.bmp
diff --git a/resources/image/floppy.bmp b/resources/image/floppy.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..1ea7b9cab0c4ed5533d65ac07b0fa5445da696b6
GIT binary patch
literal 126
zcmZ?rtz&=yI|c>@9tH*m0R{mEMg~TZ;Q#;s85kTG7#M`PA()AQfdPc!k_-$C_J1JQ
bfCoYwLTQjVNF5Bz|6pK{pMivbFfafBFX9sC
literal 0
HcmV?d00001
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 558b4ab..34316bf 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -59,7 +59,7 @@
> pixel formats
left-most pixel in the most-significant bit of the first byte.
C I 2 3 4 5
- ◯ ◯ ◯ ◯ ◯ ◯ 1bpp : 2 colors | table
+ ● ◯ ◯ ◯ ◯ ◯ 1bpp : 2 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 2bpp : 4 colors | table
◯ ◯ ◯ ◯ ◯ ◯ 4bpp : 16 colors | table
◯ ● ◯ ● ◯ ◯ 8bpp : 256 colors | table
@@ -100,6 +100,7 @@ static ColorBitMask colorBitMaskGet(const uint32_t* data, uint8_t bitfields);
#define LEXLIB_RGB_BITFIELDS 0x0A
#define LEXLIB_RGBA_BITFIELDS 0x0B
#define LEXLIB_RGB_PALETTE 0x0C
+#define LEXLIB_1BPP 0x0D
#define COLORBITMASK_BGRA_8888 ((ColorBitMask){8, 8, 8, 8, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, 16, 8, 0, 24})
#define COLORBITMASK_BGRA_555 ((ColorBitMask){5, 6, 5, 8, 0x0000FC00, 0x000003E0, 0x0000001F, 0x00000000, 16, 8, 0, 00})
@@ -129,11 +130,11 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
// check if header is valid
switch(coreHeader->size){
// supported
+ case sizeof(BmpCoreHeader):
case sizeof(BmpInfoHeader):
case sizeof(BmpInfoHeader3):
break;
// unsuported
- case sizeof(BmpCoreHeader):
case sizeof(BmpInfoHeader4):
case sizeof(BmpInfoHeader5):
free(bmp.data);
@@ -153,6 +154,29 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
uint32_t bmpRowPadding = 0;
uint32_t bmpHeadOffset = sizeof(BmpFileHeader);
+ // CoreHeader
+ if(coreHeader->size == sizeof(BmpCoreHeader)){
+ image.width = coreHeader->width;
+ image.height = coreHeader->height;
+ bmpRowStride = ((((coreHeader->width * coreHeader->bitdepth) + 31) & ~31) >> 3);
+ bmpRowPadding = (bmpRowStride) - ceil(coreHeader->width * (coreHeader->bitdepth / 8.0f));
+ bmpHeadOffset += sizeof(BmpCoreHeader);
+
+ // check for profile
+ switch(coreHeader->bitdepth){
+ case 1:
+ image.depth = 8;
+ image.profile = LEXLIB_RGB;
+ bmpPixelSize = 1;
+ profile = LEXLIB_1BPP;
+ break;
+ default: // unsuported
+ free(bmp.data);
+ image.depth = LEXLIB_UNSUPORTED;
+ return image;
+ }
+ }
+
// InfoHeader
if(coreHeader->size == sizeof(BmpInfoHeader)){
BmpInfoHeader infoHeader;
@@ -161,7 +185,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.width = infoHeader.width;
image.height = infoHeader.height;
bmpRowStride = ((((infoHeader.width * infoHeader.bitdepth) + 31) & ~31) >> 3);
- bmpRowPadding = (bmpRowStride) - (infoHeader.width * (infoHeader.bitdepth / 8));
+ bmpRowPadding = (bmpRowStride) - ceil(infoHeader.width * (infoHeader.bitdepth / 8.0f));
bmpHeadOffset += sizeof(BmpInfoHeader);
// check for compression
@@ -250,7 +274,7 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
image.width = infoHeader3->width;
image.height = infoHeader3->height;
bmpRowStride = ((((infoHeader3->width * infoHeader3->bitdepth) + 31) & ~31) >> 3);
- bmpRowPadding = (bmpRowStride) - (infoHeader3->width * (infoHeader3->bitdepth / 8));
+ bmpRowPadding = (bmpRowStride) - ceil(infoHeader3->width * (infoHeader3->bitdepth / 8.0f));
bmpHeadOffset += sizeof(BmpInfoHeader3);
// check for compression
@@ -423,6 +447,37 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpRowPadding);
}}
+ if(profile == LEXLIB_1BPP){
+ uint8_t* bmpOffset = bmp.data + fileHeader->offset;
+ uint8_t* palette = bmp.data + bmpHeadOffset;
+ // bmpRowPadding = 1;
+ for(uint32_t y = 0; y < image.height; y++){
+ for(uint32_t x = 0; x < image.width;){
+ LexlibColor imgPixel;
+ int8_t bit = 8;
+
+ do {
+ bit--;
+ if(bitGet(*bmpOffset, bit)){
+ imgPixel.r = palette[5];
+ imgPixel.g = palette[4];
+ imgPixel.b = palette[3];
+ imgPixel.a = 0xFF;
+ } else {
+ imgPixel.r = palette[2];
+ imgPixel.g = palette[1];
+ imgPixel.b = palette[0];
+ imgPixel.a = 0xFF;
+ }
+ lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
+ x++;
+ } while(bit != 0);
+
+ bmpOffset++;
+ }
+ bmpOffset += bmpRowPadding;
+ }}
+
free(bmp.data);
return image;
}
diff --git a/test/imageBmp.c b/test/imageBmp.c
index b26fa30..ea8ab57 100644
--- a/test/imageBmp.c
+++ b/test/imageBmp.c
@@ -30,6 +30,7 @@ void testImageBmp(void){
lexlibImageFlip(&image, LEXLIB_FLIP_Y);
lexlibImageSave(&image, "resources/out/plasma16.png");
+ lexlibImageDelete(&image);
testEnd(1, NULL);}
{testStart("bmp plasma24");
@@ -55,6 +56,7 @@ void testImageBmp(void){
lexlibImageFlip(&image, LEXLIB_FLIP_Y);
lexlibImageSave(&image, "resources/out/plasma24.png");
+ lexlibImageDelete(&image);
testEnd(1, NULL);}
{testStart("bmp plasma32");
@@ -80,6 +82,7 @@ void testImageBmp(void){
lexlibImageFlip(&image, LEXLIB_FLIP_Y);
lexlibImageSave(&image, "resources/out/plasma32.png");
+ lexlibImageDelete(&image);
testEnd(1, NULL);}
{testStart("bmp macintosh");
@@ -105,6 +108,7 @@ void testImageBmp(void){
lexlibImageFlip(&image, LEXLIB_FLIP_Y);
lexlibImageSave(&image, "resources/out/macintosh.png");
+ lexlibImageDelete(&image);
testEnd(1, NULL);}
{testStart("bmp macintosh_alpha70");
@@ -130,6 +134,7 @@ void testImageBmp(void){
lexlibImageFlip(&image, LEXLIB_FLIP_Y);
lexlibImageSave(&image, "resources/out/macintosh_alpha70.png");
+ lexlibImageDelete(&image);
testEnd(1, NULL);}
{testStart("bmp macintosh_8bpp");
@@ -155,6 +160,7 @@ void testImageBmp(void){
lexlibImageFlip(&image, LEXLIB_FLIP_Y);
lexlibImageSave(&image, "resources/out/macintosh_8bpp.png");
+ lexlibImageDelete(&image);
testEnd(1, NULL);}
{testStart("bmp puro");
@@ -180,5 +186,32 @@ void testImageBmp(void){
lexlibImageFlip(&image, LEXLIB_FLIP_Y);
lexlibImageSave(&image, "resources/out/puro.png");
- testEnd(1, NULL);}
+ lexlibImageDelete(&image);
+ testEnd(1, NULL);}
+
+ {testStart("bmp floppy");
+ LexlibImage image = lexlibImageLoadBmp("resources/image/floppy.bmp");
+ if(!image.data)
+ switch(image.depth){
+ case LEXLIB_CANT_OPEN:
+ testEnd(0, "can't open \"resources/image/floppy.bmp\"");
+ return;
+ case LEXLIB_INVALID_FILE_TYPE:
+ testEnd(0, "file is not a bmp");
+ return;
+ case LEXLIB_OUT_OF_MEMORY:
+ testEnd(0, "OOM");
+ return;
+ case LEXLIB_UNSUPORTED:
+ testEnd(0, "unsuported");
+ return;
+ default:
+ testEnd(0, "other error");
+ return;
+ }
+
+ lexlibImageFlip(&image, LEXLIB_FLIP_Y);
+ lexlibImageSave(&image, "resources/out/floppy.png");
+ lexlibImageDelete(&image);
+ testEnd(1, NULL);}
}
\ No newline at end of file
--
GitLab
From 9b83b17c9043f8e731d5c3aebde881c812722f00 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 01:38:58 -0400
Subject: [PATCH 40/64] imageGetPixel()
---
include/lexlib/image.h | 16 ++++++++--
src/image.c | 69 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index e7cf228..1e1d3ed 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -10,6 +10,7 @@
/* NOTE s
images with more bitdepth than 8 are bigendian.
+ its being considered if image data should be in the native machine endianess.
> Image file formats
L S M
@@ -52,16 +53,19 @@ typedef struct LexlibImage LexlibImage;
#define LEXLIB_BW 0x02 /* Black White */
#define LEXLIB_RGB 0x03 /* Red Green Blue */
#define LEXLIB_RGBA 0x04 /* Red Green Blue Alpha */
-
#define LEXLIB_RGB24 0x03 /* R.G.B.A.X: 8.8.8.0.0 */
#define LEXLIB_RGB555 0x05 /* R.G.B.A.X: 5.5.5.0.1 */
#define LEXLIB_RGB565 0x06 /* R.G.B.A.X: 5.6.5.0.0 */
-
// flags
#define LEXLIB_FLIP_X 0x01
#define LEXLIB_FLIP_Y 0x02
+// file formats
+#define LEXLIB_BMP_CORE 0x0C
+#define LEXLIB_BMP_INFO 0x28
+#define LEXLIB_BMP_INFO_V3 0x38
+
// "constants"
#define LEXLIB_IMAGE_ZERO ((LexlibImage){NULL, 0, 0, 0, 0, 0, 0, 0})
@@ -91,6 +95,11 @@ LEXLIB_EXTERN LexlibColor lexlibImagePixel(const LexlibImage* image, uint32_t x,
// returns LEXLIB_OK on success, LEXLIB_INVALID_OPERATION on error.
LEXLIB_EXTERN uint8_t lexlibImagePixelSet(const LexlibImage* image, uint32_t x, uint32_t y, LexlibColor color, uint8_t blendmode);
+// gets a pixel from a LexlibImage
+// according transformations to the returned color are performed depending of the image profile.
+// alpha is at max if the image does not have a alpha channel.
+LEXLIB_EXTERN LexlibColor lexlibImagePixelGet(const LexlibImage* image, uint32_t x, uint32_t y);
+
// loads a image into a LexlibImage.
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_INVALID_FILENAME, ... *errors sujected to the actual loader*)
LEXLIB_EXTERN LexlibImage lexlibImageLoad(const char* filename);
@@ -104,6 +113,9 @@ LEXLIB_EXTERN uint8_t lexlibImageSave(const LexlibImage* image, const char* file
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_CANT_OPEN, LEXLIB_INVALID_OPERATION, LEXLIB_OUT_OF_MEMORY, LEXLIB_ERROR).
LEXLIB_EXTERN LexlibImage lexlibImageLoadBmp(const char* filename);
+// saves a bmp to a file
+LEXLIB_EXTERN uint8_t lexlibImageSaveBmpEx(const LexlibImage* image, const char* filename, uint8_t profile, uint8_t header);
+
// loads a png into LexlibImage
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_CANT_OPEN, LEXLIB_INVALID_OPERATION, LEXLIB_OUT_OF_MEMORY, LEXLIB_ERROR).
LEXLIB_EXTERN LexlibImage lexlibImageLoadPng(const char* filename);
diff --git a/src/image.c b/src/image.c
index e666add..34f4a13 100644
--- a/src/image.c
+++ b/src/image.c
@@ -303,6 +303,75 @@ uint8_t lexlibImagePixelSet(const LexlibImage* image, uint32_t x, uint32_t y, Le
return LEXLIB_ERROR;
}
+LexlibColor lexlibImagePixelGet(const LexlibImage* image, uint32_t x, uint32_t y){
+ uint8_t pixelSize = image->bpp / 8;
+ size_t rowsize = image->width * pixelSize;
+ size_t offset = (y * rowsize) + (x * pixelSize);
+
+ if(image->depth == 8){
+ if(image->channels == 1){
+ LexlibColor pixel;
+ pixel.r = image->data[offset];
+ pixel.g = pixel.r;
+ pixel.b = pixel.r;
+ pixel.a = 0xFF;
+ return pixel;
+ }
+ if(image->channels == 3){
+ LexlibColor pixel;
+ pixel.r = image->data[offset];
+ pixel.g = image->data[offset+1];
+ pixel.b = image->data[offset+2];
+ pixel.a = 0xFF;
+ return pixel;
+ }
+ if(image->channels == 4){
+ return *(LexlibColor*)(image->data+offset);
+ }
+ }
+
+ if(image->depth == 16){
+ LexlibColor16 pixel16 = {0};
+ uint8_t* pixel16raw = (uint8_t*)&pixel16;
+ if(image->channels == 1){
+ pixel16raw[0] = image->data[offset+1];
+ pixel16raw[1] = image->data[offset+0];
+
+ pixel16.g = pixel16.r;
+ pixel16.b = pixel16.r;
+ pixel16.a = 0xFFFF;
+
+ return lexlibColor16To8(pixel16);
+ }
+ if(image->channels == 4){
+ pixel16raw[0] = image->data[offset+1];
+ pixel16raw[1] = image->data[offset+0];
+ pixel16raw[2] = image->data[offset+3];
+ pixel16raw[3] = image->data[offset+2];
+ pixel16raw[4] = image->data[offset+5];
+ pixel16raw[5] = image->data[offset+4];
+
+ pixel16.a = 0xFFFF;
+
+ return lexlibColor16To8(pixel16);
+ }
+ if(image->channels == 4){
+ pixel16raw[0] = image->data[offset+1];
+ pixel16raw[1] = image->data[offset+0];
+ pixel16raw[2] = image->data[offset+3];
+ pixel16raw[3] = image->data[offset+2];
+ pixel16raw[4] = image->data[offset+5];
+ pixel16raw[5] = image->data[offset+4];
+ pixel16raw[6] = image->data[offset+7];
+ pixel16raw[7] = image->data[offset+6];
+
+ return lexlibColor16To8(pixel16);
+ }
+ }
+
+ return LEXLIB_COLOR_MAGENTA;
+}
+
LexlibImage lexlibImageLoad(const char* filename){
LexlibImage image = LEXLIB_IMAGE_ZERO;
--
GitLab
From 9267d72913cc8bdf36635ce8631013ad877b389c Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 01:39:41 -0400
Subject: [PATCH 41/64] initial support for saving bmp files
---
src/image/bmp.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++-
test/imageBmp.c | 24 +++----
2 files changed, 183 insertions(+), 17 deletions(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 34316bf..45056e7 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -33,7 +33,7 @@
L S
◯ ◯ BmpCoreHeader | 1..24 bpp
◇ ◇ ?? | ?..?? bpp | not sure about which one it is
- ● ◯ BmpInfoHeader | 1..32 bpp
+ ● ● BmpInfoHeader | 1..32 bpp
◇ ◇ BmpInfoHeader2 | ?..?? bpp | not documented | no struct exist
● ◯ BmpInfoHeader3 | ?..?? bpp | not officially documented
◯ ◯ BmpInfoHeader4 | 0..32 bpp
@@ -93,6 +93,14 @@ typedef struct ColorRGB {
uint8_t b;
} ColorRGB;
+typedef union MasterHeader {
+ BmpCoreHeader core;
+ BmpInfoHeader info;
+ BmpInfoHeader3 info3;
+ BmpInfoHeader4 info4;
+ BmpInfoHeader5 info5;
+} MasterHeader;
+
/* Static Functions */
LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index);
static ColorBitMask colorBitMaskGet(const uint32_t* data, uint8_t bitfields);
@@ -482,6 +490,172 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
return image;
}
+uint8_t lexlibImageSaveBmpEx(const LexlibImage* image, const char* filename, uint8_t profile, uint8_t bmpheader){
+ BmpFileHeader fileHeader = {0};
+ MasterHeader header = {0};
+
+ uint8_t bitMaskCnt = 0;
+ uint32_t bitMask[4] = {0};
+ uint32_t pixelSize = 0;
+ uint32_t rowStride = 0;
+ uint32_t rowPadding = 0;
+
+ // initial file header data
+ fileHeader.type = 0x4D42;
+ fileHeader.size = sizeof(BmpFileHeader);
+ fileHeader.reserved1 = 0;
+ fileHeader.reserved2 = 0;
+
+ // arguments check
+ if(!profile)
+ profile = image->profile;
+ if(!bmpheader)
+ bmpheader = LEXLIB_BMP_INFO;
+
+ // check if header supported
+ switch(bmpheader){
+ // supported
+ case LEXLIB_BMP_INFO:
+ break;
+ default:
+ return LEXLIB_UNSUPORTED;
+ }
+
+ if(bmpheader == LEXLIB_BMP_INFO){
+ header.info.size = sizeof(BmpInfoHeader);
+ header.info.width = image->width;
+ header.info.height = image->height;
+ header.info.planes = 1;
+ header.info.xresm = 2835;
+ header.info.yresm = 2835;
+ header.info.colorPalette = 0;
+ header.info.colorImportant = 0;
+
+ // set profile
+ switch(profile){
+ case LEXLIB_RGB555:
+ header.info.bitdepth = 16;
+ header.info.compression = BMP_RGB;
+ pixelSize = 2;
+ break;
+ case LEXLIB_RGB565:
+ header.info.bitdepth = 16;
+ header.info.compression = BMP_BITFIELDS;
+ pixelSize = 2;
+ bitMaskCnt = 3;
+ bitMask[0] = 0x0000F800;
+ bitMask[1] = 0x000007E0;
+ bitMask[2] = 0x0000001F;
+ break;
+ case LEXLIB_RGB:
+ header.info.bitdepth = 24;
+ header.info.compression = BMP_RGB;
+ pixelSize = 3;
+ break;
+ case LEXLIB_RGBA:
+ header.info.bitdepth = 32;
+ header.info.compression = BMP_RGB;
+ pixelSize = 4;
+ break;
+ default:
+ return LEXLIB_UNSUPORTED;
+ }
+
+ // calculate stride and image size
+ rowStride = ((((header.info.width * header.info.bitdepth) + 31) & ~31) >> 3);
+ rowPadding = (rowStride) - ceil(header.info.width * (header.info.bitdepth / 8.0f));
+ header.info.imagesize = image->datasize + (header.info.height * rowPadding);
+ fileHeader.size += header.info.imagesize;
+ }
+
+ fileHeader.size += header.core.size;
+ fileHeader.size += bitMaskCnt * sizeof(uint32_t);
+ fileHeader.offset = sizeof(BmpFileHeader) + header.core.size + (bitMaskCnt * sizeof(uint32_t));
+
+ printf("pad %u\n", rowPadding);
+ printf("head: %u\n", fileHeader.size);
+ printf("offs: %u\n", fileHeader.offset);
+ printf("siz: %u\n", header.info.imagesize);
+
+ // create file
+ FILE* file = fopen(filename, "wb");
+ if(!file)
+ return LEXLIB_CANT_WRITE;
+
+ // set data accordingly //
+ fwrite(&fileHeader, sizeof(BmpFileHeader), 1, file);
+ fwrite(&header, header.core.size, 1, file);
+ fwrite(bitMask, sizeof(uint32_t), bitMaskCnt, file);
+
+ if(profile == LEXLIB_RGB){ // RGB
+ for(uint32_t y = 0; y < image->height; y++){
+ for(uint32_t x = 0; x < image->width; x++){
+ LexlibColor imgPixel = lexlibColorPremultiply(lexlibImagePixelGet(image, x, y));
+ LexlibColor pixel = {
+ .r = imgPixel.b,
+ .g = imgPixel.g,
+ .b = imgPixel.r,
+ .a = imgPixel.a
+ };
+ fwrite(&pixel, pixelSize, 1, file);
+ }
+ for(uint8_t pad = 0; pad < rowPadding; pad++)
+ fputc(0, file);
+ }}
+
+ if(profile == LEXLIB_RGBA){ // RGB
+ for(uint32_t y = 0; y < image->height; y++){
+ for(uint32_t x = 0; x < image->width; x++){
+ LexlibColor imgPixel = lexlibImagePixelGet(image, x, y);
+ LexlibColor pixel = {
+ .r = imgPixel.b,
+ .g = imgPixel.g,
+ .b = imgPixel.r,
+ .a = imgPixel.a
+ };
+ fwrite(&pixel, pixelSize, 1, file);
+ }
+ for(uint8_t pad = 0; pad < rowPadding; pad++)
+ fputc(0, file);
+ }}
+
+ if(profile == LEXLIB_RGB555){ // RGB555
+ for(uint32_t y = 0; y < image->height; y++){
+ for(uint32_t x = 0; x < image->width; x++){
+ LexlibColor imgPixel = lexlibColorPremultiply(lexlibImagePixelGet(image, x, y));
+ uint16_t pixel = 0x0000;
+
+ pixel |= (uint16_t)rintf((imgPixel.r / 255.0f) * 31.0f) << 10;
+ pixel |= (uint16_t)rintf((imgPixel.g / 255.0f) * 31.0f) << 5;
+ pixel |= (uint16_t)rintf((imgPixel.b / 255.0f) * 31.0f);
+
+ fwrite(&pixel, pixelSize, 1, file);
+ }
+ for(uint8_t pad = 0; pad < rowPadding; pad++)
+ fputc(0, file);
+ }}
+
+ if(profile == LEXLIB_RGB565){ // RGB565
+ for(uint32_t y = 0; y < image->height; y++){
+ for(uint32_t x = 0; x < image->width; x++){
+ LexlibColor imgPixel = lexlibColorPremultiply(lexlibImagePixelGet(image, x, y));
+ uint16_t pixel = 0x0000;
+
+ pixel |= (uint16_t)rintf((imgPixel.r / 255.0f) * 31.0f) << 11;
+ pixel |= (uint16_t)rintf((imgPixel.g / 255.0f) * 63.0f) << 5;
+ pixel |= (uint16_t)rintf((imgPixel.b / 255.0f) * 31.0f);
+
+ fwrite(&pixel, pixelSize, 1, file);
+ }
+ for(uint8_t pad = 0; pad < rowPadding; pad++)
+ fputc(0, file);
+ }}
+
+ fflush(file);
+ fclose(file);
+ return LEXLIB_OK;
+}
+
/* Static Functions */
#define UNSIGNED_BIT_WIDTH (CHAR_BIT * sizeof(unsigned))
LEXLIB_INLINE unsigned bitGet(unsigned x, unsigned index){
diff --git a/test/imageBmp.c b/test/imageBmp.c
index ea8ab57..cf01290 100644
--- a/test/imageBmp.c
+++ b/test/imageBmp.c
@@ -28,8 +28,7 @@ void testImageBmp(void){
return;
}
- lexlibImageFlip(&image, LEXLIB_FLIP_Y);
- lexlibImageSave(&image, "resources/out/plasma16.png");
+ lexlibImageSaveBmpEx(&image, "resources/out/plasma16.bmp", LEXLIB_RGB565, 0);
lexlibImageDelete(&image);
testEnd(1, NULL);}
@@ -54,8 +53,7 @@ void testImageBmp(void){
return;
}
- lexlibImageFlip(&image, LEXLIB_FLIP_Y);
- lexlibImageSave(&image, "resources/out/plasma24.png");
+ lexlibImageSaveBmpEx(&image, "resources/out/plasma24.bmp", 0, 0);
lexlibImageDelete(&image);
testEnd(1, NULL);}
@@ -80,8 +78,7 @@ void testImageBmp(void){
return;
}
- lexlibImageFlip(&image, LEXLIB_FLIP_Y);
- lexlibImageSave(&image, "resources/out/plasma32.png");
+ lexlibImageSaveBmpEx(&image, "resources/out/plasma32.bmp", 0, 0);
lexlibImageDelete(&image);
testEnd(1, NULL);}
@@ -106,8 +103,7 @@ void testImageBmp(void){
return;
}
- lexlibImageFlip(&image, LEXLIB_FLIP_Y);
- lexlibImageSave(&image, "resources/out/macintosh.png");
+ lexlibImageSaveBmpEx(&image, "resources/out/macintosh.bmp", 0, 0);
lexlibImageDelete(&image);
testEnd(1, NULL);}
@@ -132,8 +128,7 @@ void testImageBmp(void){
return;
}
- lexlibImageFlip(&image, LEXLIB_FLIP_Y);
- lexlibImageSave(&image, "resources/out/macintosh_alpha70.png");
+ lexlibImageSaveBmpEx(&image, "resources/out/macintosh_alpha70.bmp", 0, 0);
lexlibImageDelete(&image);
testEnd(1, NULL);}
@@ -158,8 +153,7 @@ void testImageBmp(void){
return;
}
- lexlibImageFlip(&image, LEXLIB_FLIP_Y);
- lexlibImageSave(&image, "resources/out/macintosh_8bpp.png");
+ lexlibImageSaveBmpEx(&image, "resources/out/macintosh_8bpp.bmp", 0, 0);
lexlibImageDelete(&image);
testEnd(1, NULL);}
@@ -184,8 +178,7 @@ void testImageBmp(void){
return;
}
- lexlibImageFlip(&image, LEXLIB_FLIP_Y);
- lexlibImageSave(&image, "resources/out/puro.png");
+ lexlibImageSaveBmpEx(&image, "resources/out/puro.bmp", 0, 0);
lexlibImageDelete(&image);
testEnd(1, NULL);}
@@ -210,8 +203,7 @@ void testImageBmp(void){
return;
}
- lexlibImageFlip(&image, LEXLIB_FLIP_Y);
- lexlibImageSave(&image, "resources/out/floppy.png");
+ lexlibImageSaveBmpEx(&image, "resources/out/floppy.bmp", 0, 0);
lexlibImageDelete(&image);
testEnd(1, NULL);}
}
\ No newline at end of file
--
GitLab
From 4317a8aa903e9b2c59e12f4ef65f8b1622d388b0 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 15:14:48 -0400
Subject: [PATCH 42/64] CMAKE_BUILD_TYPE check for debug in CMakeLists
---
CHANGELOG.md | 3 +++
CMakeLists.txt | 7 ++++++-
linux.sh | 24 ++++++++++++++++++------
3 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e1e3fc1..292b04b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,9 @@
+ lexlibImagePixelSet().
+ lexlibFileBytes():
+ lexlibPowu();
++ lexlibImageLoadBmp();
++ lexlibImagePixelGet();
++ lexlibImageSaveBmpEx();
## 1.4.0
+ function lexlibStrCopy().
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ce0dec1..8200e19 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,7 +27,12 @@ target_sources(${PROJECT_NAME} PRIVATE
# options/properties
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99)
target_include_directories(${PROJECT_NAME} PRIVATE include)
-target_compile_options(${PROJECT_NAME} PRIVATE -O3 -Wall -Wextra -DLEXLIB_VERSION="${PROJECT_VERSION}")
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ target_compile_options(${PROJECT_NAME} PRIVATE -g -Wall -Wextra -fsanitize=address -DLEXLIB_VERSION="${PROJECT_VERSION}")
+ target_link_libraries(${PROJECT_NAME} PUBLIC m -fsanitize=address)
+else()
+ target_compile_options(${PROJECT_NAME} PRIVATE -O3 -Wall -Wextra -DLEXLIB_VERSION="${PROJECT_VERSION}")
+endif()
set_source_files_properties(src/path.c PROPERTIES COMPILE_FLAGS -Wdeprecated-declarations)
# explicitly define public headers
diff --git a/linux.sh b/linux.sh
index 24a36f0..23ec2e3 100755
--- a/linux.sh
+++ b/linux.sh
@@ -14,30 +14,42 @@ function message () {
if [[ $1 == cmake ]]; then
if [[ $2 == all ]]; then
- ./linux.sh cmake linux
- ./linux.sh cmake mingw32
- ./linux.sh cmake mingw64
+ ./linux.sh cmake linux $3
+ ./linux.sh cmake mingw32 $3
+ ./linux.sh cmake mingw64 $3
exit 0
fi
if [[ $2 == linux ]]; then
message "cmake linux"
mkdir -p build/linux
cd build/linux
- cmake ../..
+ if [[ $3 == debug ]]; then
+ cmake ../.. -DCMAKE_BUILD_TYPE=Debug
+ else
+ cmake ../..
+ fi
exit 0
fi
if [[ $2 == mingw32 ]]; then
message "cmake mingw32"
mkdir -p build/mingw32
cd build/mingw32
- cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../resources/tc_mingw32.cmake
+ if [[ $3 == debug ]]; then
+ cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../resources/tc_mingw32.cmake -DCMAKE_BUILD_TYPE=Debug
+ else
+ cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../resources/tc_mingw32.cmake
+ fi
exit 0
fi
if [[ $2 == mingw64 ]]; then
message "cmake mingw64"
mkdir -p build/mingw64
cd build/mingw64
- cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../resources/tc_mingw64.cmake
+ if [[ $3 == debug ]]; then
+ cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../resources/tc_mingw64.cmake -DCMAKE_BUILD_TYPE=Debug
+ else
+ cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../resources/tc_mingw64.cmake
+ fi
exit 0
fi
if [[ $2 == install ]]; then
--
GitLab
From 3adab047ea153f5b4efa9af428a14b934da001ff Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 15:29:30 -0400
Subject: [PATCH 43/64] fixed strPath buffer overflows
---
src/str.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/src/str.c b/src/str.c
index 302a0e9..fe61616 100644
--- a/src/str.c
+++ b/src/str.c
@@ -66,7 +66,7 @@ uint8_t lexlibStrPathPush(char** str, const char* add){
if(strLen == 0 || addLen == 0)
return LEXLIB_INVALID_VALUE;
- char* path = realloc(*str, (len+1) * sizeof(char));
+ char* path = realloc(*str, (len+2) * sizeof(char));
char* offPath = path+strLen;
if(!path)
@@ -167,10 +167,5 @@ uint8_t lexlibStrPathAsFile(char** str){
else
return LEXLIB_OK;
- char* new = realloc(*str, (len) * sizeof(char));
- if(!new)
- return LEXLIB_OUT_OF_MEMORY;
-
- *str = new;
return LEXLIB_OK;
}
\ No newline at end of file
--
GitLab
From b8034ac304b0f02dda96716b8c167b2e7d084a78 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 15:51:56 -0400
Subject: [PATCH 44/64] fixed buffer over in imageFlip (flip x)
---
src/image.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/src/image.c b/src/image.c
index 34f4a13..bf9fd38 100644
--- a/src/image.c
+++ b/src/image.c
@@ -93,7 +93,7 @@ uint8_t lexlibImageFlip(LexlibImage* image, uint8_t flags){
return imgStat;
// common
- size_t rowSize = image->width * image->channels * (image->depth / 8);
+ size_t rowSize = image->width * (image->bpp / 8);
// flip y
if(flags & LEXLIB_FLIP_Y){
@@ -150,20 +150,23 @@ uint8_t lexlibImageFlip(LexlibImage* image, uint8_t flags){
// flip x
if(flags & LEXLIB_FLIP_X){
// allocate a buffer
- uint8_t* tmp = calloc(rowSize, sizeof(uint8_t));
+ uint8_t* tmp = malloc(rowSize * sizeof(uint8_t));
if(!tmp)
return LEXLIB_OUT_OF_MEMORY;
size_t offset = 0;
- uint8_t pixelSize = image->channels * (image->depth / 8);
-
+ uint8_t pixelSize = image->bpp / 8;
+ printf("ps %u\n", pixelSize);
+ printf("rs %u\n", rowSize);
// copy pixel per pixel.
for(size_t y = 0; y < image->height; y++){
memcpy(tmp, image->data+offset, rowSize);
- size_t offsetX = rowSize;
- for(size_t x = 0; x < rowSize; x+=pixelSize){
- memcpy(image->data+(offsetX+offset), tmp+x, pixelSize);
- offsetX-=pixelSize;
+ size_t xOffset = rowSize - pixelSize;
+ size_t tmpOffset = 0;
+ for(size_t x = 0; x < image->width; x++){
+ memcpy(image->data+(xOffset + offset), tmp+tmpOffset, pixelSize);
+ xOffset -= pixelSize;
+ tmpOffset += pixelSize;
}
offset += rowSize;
}
--
GitLab
From 6f1399ffa8335be98ed64e300484806b51aa4f73 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 15:52:59 -0400
Subject: [PATCH 45/64] removed printfs from image.c
---
src/image.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/image.c b/src/image.c
index bf9fd38..f044202 100644
--- a/src/image.c
+++ b/src/image.c
@@ -156,8 +156,6 @@ uint8_t lexlibImageFlip(LexlibImage* image, uint8_t flags){
size_t offset = 0;
uint8_t pixelSize = image->bpp / 8;
- printf("ps %u\n", pixelSize);
- printf("rs %u\n", rowSize);
// copy pixel per pixel.
for(size_t y = 0; y < image->height; y++){
memcpy(tmp, image->data+offset, rowSize);
--
GitLab
From aebf47df73d90dc3b207184e209093f8d60cc36a Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 16:33:14 -0400
Subject: [PATCH 46/64] fixed bmp loader over_reads
---
src/image/bmp.c | 81 +++++++++++++++++++++++++++++++++++++++----------
1 file changed, 65 insertions(+), 16 deletions(-)
diff --git a/src/image/bmp.c b/src/image/bmp.c
index 45056e7..ef7d43a 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -398,10 +398,25 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
}}
if(profile == LEXLIB_RGB_BITFIELDS){ // bitfields without alpha
- uint32_t* bmpOffset = (uint32_t*)(bmp.data + fileHeader->offset);
+ uint8_t* bmpOffset = bmp.data + fileHeader->offset;
for(uint32_t y = 0; y < image.height; y++){
for(uint32_t x = 0; x < image.width; x++){
- uint32_t bmpPixel = *bmpOffset;
+ // get the pixel
+ uint32_t bmpPixel = 0x00000000;
+ switch(bmpPixelSize){
+ case 4:
+ bmpPixel |= bmpOffset[3] << 24;
+ LEXLIB_FALLTHROUGH;
+ case 3:
+ bmpPixel |= bmpOffset[2] << 16;
+ LEXLIB_FALLTHROUGH;
+ case 2:
+ bmpPixel |= bmpOffset[1] << 8;
+ LEXLIB_FALLTHROUGH;
+ case 1:
+ bmpPixel |= bmpOffset[0];
+ break;
+ }
LexlibColor imgPixel = {
.r = rintf((((bmpPixel & bitMask.rb) >> bitMask.rs) / colorMax.r) * 255.0f),
@@ -411,16 +426,32 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
};
lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
- bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpPixelSize);
+ bmpOffset += bmpPixelSize;
}
- bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpRowPadding);
+ bmpOffset += bmpRowPadding;
}}
if(profile == LEXLIB_RGBA_BITFIELDS){ // bitfields with alpha
- uint32_t* bmpOffset = (uint32_t*)(bmp.data + fileHeader->offset);
+ uint8_t* bmpOffset = (uint8_t*)(bmp.data + fileHeader->offset);
for(uint32_t y = 0; y < image.height; y++){
for(uint32_t x = 0; x < image.width; x++){
- uint32_t bmpPixel = *bmpOffset;
+ // get the pixel
+ uint32_t bmpPixel = 0x00000000;
+ switch(bmpPixelSize){
+ case 4:
+ bmpPixel |= bmpOffset[3] << 24;
+ LEXLIB_FALLTHROUGH;
+ case 3:
+ bmpPixel |= bmpOffset[2] << 16;
+ LEXLIB_FALLTHROUGH;
+ case 2:
+ bmpPixel |= bmpOffset[1] << 8;
+ LEXLIB_FALLTHROUGH;
+ case 1:
+ bmpPixel |= bmpOffset[0];
+ break;
+ }
+
LexlibColor imgPixel = {
.r = rintf((((bmpPixel & bitMask.rb) >> bitMask.rs) / colorMax.r) * 255.0f),
.g = rintf((((bmpPixel & bitMask.gb) >> bitMask.gs) / colorMax.g) * 255.0f),
@@ -429,19 +460,34 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
};
lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
- bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpPixelSize);
+ bmpOffset += bmpPixelSize;
}
- bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpRowPadding);
+ bmpOffset += bmpRowPadding;
}}
- // here bitMask.rb is used to determine how much of bmpOffset should be used;
- // 0x000000FF for 8 bit, 0x0000FFFF for 16 and so on.
if(profile == LEXLIB_RGB_PALETTE){ // color palette
- uint32_t* bmpOffset = (uint32_t*)(bmp.data + fileHeader->offset);
+ uint8_t* bmpOffset = (uint8_t*)(bmp.data + fileHeader->offset);
uint32_t* palette = (uint32_t*)(bmp.data + bmpHeadOffset);
for(uint32_t y = 0; y < image.height; y++){
for(uint32_t x = 0; x < image.width; x++){
- uint32_t bmpPixel = palette[*bmpOffset & bitMask.rb];
+ // get the pixel
+ uint32_t bmpPixel = 0x00000000;
+ switch(bmpPixelSize){
+ case 4:
+ bmpPixel |= bmpOffset[3] << 24;
+ LEXLIB_FALLTHROUGH;
+ case 3:
+ bmpPixel |= bmpOffset[2] << 16;
+ LEXLIB_FALLTHROUGH;
+ case 2:
+ bmpPixel |= bmpOffset[1] << 8;
+ LEXLIB_FALLTHROUGH;
+ case 1:
+ bmpPixel |= bmpOffset[0];
+ break;
+ }
+ bmpPixel = palette[bmpPixel];
+
LexlibColor imgPixel = {
.r = bmpPixel >> 16,
.g = bmpPixel >> 8,
@@ -450,15 +496,14 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
};
lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
- bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpPixelSize);
+ bmpOffset += bmpPixelSize;
}
- bmpOffset = (uint32_t*)(((uint8_t*)bmpOffset) + bmpRowPadding);
+ bmpOffset += bmpRowPadding;
}}
- if(profile == LEXLIB_1BPP){
+ if(profile == LEXLIB_1BPP){ // one bit per pixel
uint8_t* bmpOffset = bmp.data + fileHeader->offset;
uint8_t* palette = bmp.data + bmpHeadOffset;
- // bmpRowPadding = 1;
for(uint32_t y = 0; y < image.height; y++){
for(uint32_t x = 0; x < image.width;){
LexlibColor imgPixel;
@@ -477,7 +522,11 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
imgPixel.b = palette[0];
imgPixel.a = 0xFF;
}
+ /* in case the pixel is out of bounds pixelSet will handle it.
+ it would happend with images that aren't byte aligned, a width of 15 uses
+ 1111111111111110 which is not completly aligned and the last bit will be read and set. */
lexlibImagePixelSet(&image, x, y, imgPixel, LEXLIB_NONE);
+
x++;
} while(bit != 0);
--
GitLab
From 64215970b9636603707566d11babce968d52e94e Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 17:07:28 -0400
Subject: [PATCH 47/64] fixed linkedlist memleak and testStrPath memleak
---
src/linkedList.c | 31 +++++++++++--------------------
test/strPath.c | 1 +
2 files changed, 12 insertions(+), 20 deletions(-)
diff --git a/src/linkedList.c b/src/linkedList.c
index ae118a6..53ddd6e 100644
--- a/src/linkedList.c
+++ b/src/linkedList.c
@@ -33,40 +33,24 @@ void lexlibLinkedListDelete(struct LexlibLinkedList* list){
}
void lexlibLinkedListFree(struct LexlibLinkedList* list){
- typeof(list->head) curr = list->head;
- typeof(list->head)* all = calloc(list->count, sizeof(list->head));
+ LexlibLinkedNode* curr = list->head;
+ LexlibLinkedNode* old = list->head;
for(size_t i = 0; ;i++){
if(!curr)
break;
if(curr->data)
free(curr->data);
- all[i] = curr;
+ old = curr;
curr = curr->next;
+ free(old);
}
- for(size_t i = 0; i < list->count; i++){
- free(all[i]);
- }
-
- free(all);
list->head = NULL;
list->count = 0;
}
uint8_t lexlibLinkedListAdd(struct LexlibLinkedList* list, void* data){
- if(!list->head){
- list->head = malloc(sizeof(list->head));
- } else {
- typeof(list->head) newMem = realloc(list->head, (list->count+1) * sizeof(list->head));
- if(!newMem)
- return 1;
- list->head = newMem;
- }
-
- if(!list->head)
- return 1;
-
struct LexlibLinkedNode* node = malloc(sizeof(struct LexlibLinkedNode));
if(!node)
return 1;
@@ -74,6 +58,13 @@ uint8_t lexlibLinkedListAdd(struct LexlibLinkedList* list, void* data){
node->data = data;
node->next = NULL;
+ if(list->head){
+ typeof(list->head) newMem = realloc(list->head, (list->count+1) * sizeof(LexlibLinkedNode*));
+ if(!newMem)
+ return 1;
+ list->head = newMem;
+ }
+
if(list->count == 0){
list->head = node;
} else {
diff --git a/test/strPath.c b/test/strPath.c
index 3171ce5..48473a4 100644
--- a/test/strPath.c
+++ b/test/strPath.c
@@ -25,5 +25,6 @@ void testStrPath(void){
if(strcmp(path, patht))
err = 0;
+ free(path);
testEnd(err, NULL);
}
\ No newline at end of file
--
GitLab
From 33cc298f154fc7f07c9b292a3ffe4806430ba433 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 17:39:21 -0400
Subject: [PATCH 48/64] support for saving bmp header v3
---
CHANGELOG.md | 3 +++
src/image/bmp.c | 64 +++++++++++++++++++++++++++++++++++++++++++++----
test/imageBmp.c | 2 +-
3 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 292b04b..02921d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,9 @@
+ lexlibImageLoadBmp();
+ lexlibImagePixelGet();
+ lexlibImageSaveBmpEx();
++ fixed strPath buffer overflows.
++ fixed imageFlip X buffer overflow.
++ fixed linkedList memleaks.
## 1.4.0
+ function lexlibStrCopy().
diff --git a/src/image/bmp.c b/src/image/bmp.c
index ef7d43a..bd1dd9a 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -565,6 +565,7 @@ uint8_t lexlibImageSaveBmpEx(const LexlibImage* image, const char* filename, uin
switch(bmpheader){
// supported
case LEXLIB_BMP_INFO:
+ case LEXLIB_BMP_INFO_V3:
break;
default:
return LEXLIB_UNSUPORTED;
@@ -609,14 +610,67 @@ uint8_t lexlibImageSaveBmpEx(const LexlibImage* image, const char* filename, uin
default:
return LEXLIB_UNSUPORTED;
}
+ }
+
+ if(bmpheader == LEXLIB_BMP_INFO_V3){
+ header.info3.size = sizeof(BmpInfoHeader3);
+ header.info3.width = image->width;
+ header.info3.height = image->height;
+ header.info3.planes = 1;
+ header.info3.xresm = 2835;
+ header.info3.yresm = 2835;
+ header.info3.colorPalette = 0;
+ header.info3.colorImportant = 0;
- // calculate stride and image size
- rowStride = ((((header.info.width * header.info.bitdepth) + 31) & ~31) >> 3);
- rowPadding = (rowStride) - ceil(header.info.width * (header.info.bitdepth / 8.0f));
- header.info.imagesize = image->datasize + (header.info.height * rowPadding);
- fileHeader.size += header.info.imagesize;
+ // set profile
+ switch(profile){
+ case LEXLIB_RGB555:
+ header.info3.bitdepth = 16;
+ header.info3.compression = BMP_BITFIELDS;
+ pixelSize = 2;
+ header.info3.redbitmask = 0x00007C00;
+ header.info3.greenbitmask = 0x000003E0;
+ header.info3.bluebitmask = 0x0000001F;
+ header.info3.alphabitmask = 0x00000000;
+ break;
+ case LEXLIB_RGB565:
+ header.info3.bitdepth = 16;
+ header.info3.compression = BMP_BITFIELDS;
+ pixelSize = 2;
+ header.info3.redbitmask = 0x0000F800;
+ header.info3.greenbitmask = 0x000007E0;
+ header.info3.bluebitmask = 0x0000001F;
+ header.info3.alphabitmask = 0x00000000;
+ break;
+ case LEXLIB_RGB:
+ header.info3.bitdepth = 24;
+ header.info3.compression = BMP_BITFIELDS;
+ pixelSize = 3;
+ header.info3.redbitmask = 0x00FF0000;
+ header.info3.greenbitmask = 0x0000FF00;
+ header.info3.bluebitmask = 0x000000FF;
+ header.info3.alphabitmask = 0x00000000;
+ break;
+ case LEXLIB_RGBA:
+ header.info3.bitdepth = 32;
+ header.info3.compression = BMP_BITFIELDS;
+ pixelSize = 4;
+ header.info3.redbitmask = 0x00FF0000;
+ header.info3.greenbitmask = 0x0000FF00;
+ header.info3.bluebitmask = 0x000000FF;
+ header.info3.alphabitmask = 0xFF000000;
+ break;
+ default:
+ return LEXLIB_UNSUPORTED;
+ }
}
+ // calculate stride and image size
+ rowStride = ((((header.info.width * header.info.bitdepth) + 31) & ~31) >> 3);
+ rowPadding = (rowStride) - ceil(header.info.width * (header.info.bitdepth / 8.0f));
+ header.info.imagesize = image->datasize + (header.info.height * rowPadding);
+ fileHeader.size += header.info.imagesize;
+
fileHeader.size += header.core.size;
fileHeader.size += bitMaskCnt * sizeof(uint32_t);
fileHeader.offset = sizeof(BmpFileHeader) + header.core.size + (bitMaskCnt * sizeof(uint32_t));
diff --git a/test/imageBmp.c b/test/imageBmp.c
index cf01290..a8bcaff 100644
--- a/test/imageBmp.c
+++ b/test/imageBmp.c
@@ -128,7 +128,7 @@ void testImageBmp(void){
return;
}
- lexlibImageSaveBmpEx(&image, "resources/out/macintosh_alpha70.bmp", 0, 0);
+ lexlibImageSaveBmpEx(&image, "resources/out/macintosh_alpha70.bmp", 0, LEXLIB_BMP_INFO_V3);
lexlibImageDelete(&image);
testEnd(1, NULL);}
--
GitLab
From 827f2ce8788b85121d8b100875960f4923f79e9d Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 18:06:39 -0400
Subject: [PATCH 49/64] imageSaveBmp()
---
include/lexlib/image.h | 10 +++++++++-
src/image/bmp.c | 39 ++++++++++++++++++++++++++++++---------
test/imageBmp.c | 2 +-
3 files changed, 40 insertions(+), 11 deletions(-)
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index 1e1d3ed..e556d13 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -113,7 +113,15 @@ LEXLIB_EXTERN uint8_t lexlibImageSave(const LexlibImage* image, const char* file
// on error image.data will be NULL and the error code will be placed in image.depth. (LEXLIB_CANT_OPEN, LEXLIB_INVALID_OPERATION, LEXLIB_OUT_OF_MEMORY, LEXLIB_ERROR).
LEXLIB_EXTERN LexlibImage lexlibImageLoadBmp(const char* filename);
-// saves a bmp to a file
+// saves a image to a bmp file
+// sets the optimal bmp header and profile for the image.
+// returns LEXLIB_OK on success, on error LEXLIB_CANT_WRITE.
+LEXLIB_EXTERN uint8_t lexlibImageSaveBmp(const LexlibImage* image, const char* filename);
+
+// saves a image to a bmp file with extra options
+// for defaults profile and header can be left 0.
+// if the image/profile contains alpha its recommended to use LEXLIB_BMP_INFO_V3 for header.
+// returns LEXLIB_OK on success, on error LEXLIB_UNSUPORTED or LEXLIB_CANT_WRITE.
LEXLIB_EXTERN uint8_t lexlibImageSaveBmpEx(const LexlibImage* image, const char* filename, uint8_t profile, uint8_t header);
// loads a png into LexlibImage
diff --git a/src/image/bmp.c b/src/image/bmp.c
index bd1dd9a..b74b8c6 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -35,7 +35,7 @@
◇ ◇ ?? | ?..?? bpp | not sure about which one it is
● ● BmpInfoHeader | 1..32 bpp
◇ ◇ BmpInfoHeader2 | ?..?? bpp | not documented | no struct exist
- ● ◯ BmpInfoHeader3 | ?..?? bpp | not officially documented
+ ● ● BmpInfoHeader3 | ?..?? bpp | not officially documented
◯ ◯ BmpInfoHeader4 | 0..32 bpp
◯ ◯ BmpInfoHeader5 | 0..32 bpp
@@ -58,14 +58,14 @@
> pixel formats
left-most pixel in the most-significant bit of the first byte.
- C I 2 3 4 5
- ● ◯ ◯ ◯ ◯ ◯ 1bpp : 2 colors | table
- ◯ ◯ ◯ ◯ ◯ ◯ 2bpp : 4 colors | table
- ◯ ◯ ◯ ◯ ◯ ◯ 4bpp : 16 colors | table
- ◯ ● ◯ ● ◯ ◯ 8bpp : 256 colors | table
- ◯ ● ◯ ● ◯ ◯ 16bpp: 65536 colors | 555, 565, bitmask.
- ◯ ● ◯ ● ◯ ◯ 24bpp: 16777216 colors | b,g,r.
- ◯ ● ◯ ● ◯ ◯ 32bpp: 4294967296 colors | a,b,g,r.
+ S C I 2 3 4 5
+ ◯ ● ◯ ◯ ◯ ◯ ◯ 1bpp : 2 colors | table
+ ◯ ◯ ◯ ◯ ◯ ◯ ◯ 2bpp : 4 colors | table
+ ◯ ◯ ◯ ◯ ◯ ◯ ◯ 4bpp : 16 colors | table
+ ◯ ◯ ● ◯ ● ◯ ◯ 8bpp : 256 colors | table
+ ● ◯ ● ◯ ● ◯ ◯ 16bpp: 65536 colors | 555, 565, bitmask.
+ ● ◯ ● ◯ ● ◯ ◯ 24bpp: 16777216 colors | b,g,r.
+ ● ◯ ● ◯ ● ◯ ◯ 32bpp: 4294967296 colors | a,b,g,r.
> pixel storage
The size of each row is rounded up to a multiple of 4 bytes.
@@ -539,6 +539,27 @@ LexlibImage lexlibImageLoadBmp(const char* filename){
return image;
}
+uint8_t lexlibImageSaveBmp(const LexlibImage* image, const char* filename){
+ uint8_t profile = image->profile;
+ uint8_t bmpHeader;
+
+ // set the optimal header
+ switch(profile){
+ case LEXLIB_GRAY:
+ case LEXLIB_RGB:
+ bmpHeader = LEXLIB_BMP_INFO;
+ break;
+ case LEXLIB_RGBA:
+ bmpHeader = LEXLIB_BMP_INFO_V3;
+ break;
+ default:
+ bmpHeader = 0;
+ break;
+ }
+
+ return lexlibImageSaveBmpEx(image, filename, profile, bmpHeader);
+}
+
uint8_t lexlibImageSaveBmpEx(const LexlibImage* image, const char* filename, uint8_t profile, uint8_t bmpheader){
BmpFileHeader fileHeader = {0};
MasterHeader header = {0};
diff --git a/test/imageBmp.c b/test/imageBmp.c
index a8bcaff..8a1cf01 100644
--- a/test/imageBmp.c
+++ b/test/imageBmp.c
@@ -128,7 +128,7 @@ void testImageBmp(void){
return;
}
- lexlibImageSaveBmpEx(&image, "resources/out/macintosh_alpha70.bmp", 0, LEXLIB_BMP_INFO_V3);
+ lexlibImageSaveBmp(&image, "resources/out/macintosh_alpha70.bmp");
lexlibImageDelete(&image);
testEnd(1, NULL);}
--
GitLab
From 0a8adc6a552f9c9772e8be8997c8edfe9cefc354 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 18:11:42 -0400
Subject: [PATCH 50/64] added bmp to imageLoad() and imageSave()
---
src/image.c | 4 ++++
src/image/bmp.c | 5 -----
test/imageBmp.c | 4 ++--
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/image.c b/src/image.c
index f044202..9803630 100644
--- a/src/image.c
+++ b/src/image.c
@@ -380,6 +380,8 @@ LexlibImage lexlibImageLoad(const char* filename){
if(offset){
if(strcmp(offset, ".png") == 0)
return lexlibImageLoadPng(filename);
+ if(strcmp(offset, ".bmp") == 0)
+ return lexlibImageLoadBmp(filename);
}
image.data = NULL;
@@ -393,6 +395,8 @@ uint8_t lexlibImageSave(const LexlibImage* image, const char* filename){
if(offset){
if(strcmp(offset, ".png") == 0)
return lexlibImageSavePng(image, filename);
+ if(strcmp(offset, ".bmp") == 0)
+ return lexlibImageSaveBmp(image, filename);
}
return LEXLIB_INVALID_FILENAME;
diff --git a/src/image/bmp.c b/src/image/bmp.c
index b74b8c6..da6022d 100644
--- a/src/image/bmp.c
+++ b/src/image/bmp.c
@@ -696,11 +696,6 @@ uint8_t lexlibImageSaveBmpEx(const LexlibImage* image, const char* filename, uin
fileHeader.size += bitMaskCnt * sizeof(uint32_t);
fileHeader.offset = sizeof(BmpFileHeader) + header.core.size + (bitMaskCnt * sizeof(uint32_t));
- printf("pad %u\n", rowPadding);
- printf("head: %u\n", fileHeader.size);
- printf("offs: %u\n", fileHeader.offset);
- printf("siz: %u\n", header.info.imagesize);
-
// create file
FILE* file = fopen(filename, "wb");
if(!file)
diff --git a/test/imageBmp.c b/test/imageBmp.c
index 8a1cf01..18267a2 100644
--- a/test/imageBmp.c
+++ b/test/imageBmp.c
@@ -83,7 +83,7 @@ void testImageBmp(void){
testEnd(1, NULL);}
{testStart("bmp macintosh");
- LexlibImage image = lexlibImageLoadBmp("resources/image/macintosh.bmp");
+ LexlibImage image = lexlibImageLoad("resources/image/macintosh.bmp");
if(!image.data)
switch(image.depth){
case LEXLIB_CANT_OPEN:
@@ -128,7 +128,7 @@ void testImageBmp(void){
return;
}
- lexlibImageSaveBmp(&image, "resources/out/macintosh_alpha70.bmp");
+ lexlibImageSave(&image, "resources/out/macintosh_alpha70.bmp");
lexlibImageDelete(&image);
testEnd(1, NULL);}
--
GitLab
From 5ae70a8a7f71b5b2b491497e5a2b6ed3ae825f41 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 18:13:29 -0400
Subject: [PATCH 51/64] removed unused lexlibImagePixel() function declaration
---
include/lexlib/image.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index e556d13..938f211 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -85,9 +85,6 @@ LEXLIB_EXTERN uint8_t lexlibImageValidate(const LexlibImage* image);
// return LEXLIB_OK on success, on error might return LEXLIB_INVALID_VALUE or LEXLIB_OUT_OF_MEMORY.
LEXLIB_EXTERN uint8_t lexlibImageFlip(LexlibImage* image, uint8_t flags);
-// gets a pixel from a image at a coordinate
-LEXLIB_EXTERN LexlibColor lexlibImagePixel(const LexlibImage* image, uint32_t x, uint32_t y);
-
// sets a pixel of a LexlibImage
// according transformations to the passed color are performed depending of the image profile.
// alpha is premultiplied if the image does not have a alpha channel.
--
GitLab
From 843017061b1c16207c0f702fe1d3de7d8c8783bb Mon Sep 17 00:00:00 2001
From: alexevier
Date: Tue, 16 May 2023 23:31:57 -0400
Subject: [PATCH 52/64] imagePixelGet() bounds check
---
include/lexlib/image.h | 3 ++-
src/image.c | 5 ++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/lexlib/image.h b/include/lexlib/image.h
index 938f211..5fcdffa 100644
--- a/include/lexlib/image.h
+++ b/include/lexlib/image.h
@@ -90,11 +90,12 @@ LEXLIB_EXTERN uint8_t lexlibImageFlip(LexlibImage* image, uint8_t flags);
// alpha is premultiplied if the image does not have a alpha channel.
// if image is gray the color gets averaged.
// returns LEXLIB_OK on success, LEXLIB_INVALID_OPERATION on error.
-LEXLIB_EXTERN uint8_t lexlibImagePixelSet(const LexlibImage* image, uint32_t x, uint32_t y, LexlibColor color, uint8_t blendmode);
+LEXLIB_EXTERN uint8_t lexlibImagePixelSet(LexlibImage* image, uint32_t x, uint32_t y, LexlibColor color, uint8_t blendmode);
// gets a pixel from a LexlibImage
// according transformations to the returned color are performed depending of the image profile.
// alpha is at max if the image does not have a alpha channel.
+// in case of error LEXLIB_COLOR_MAGENTA is returned.
LEXLIB_EXTERN LexlibColor lexlibImagePixelGet(const LexlibImage* image, uint32_t x, uint32_t y);
// loads a image into a LexlibImage.
diff --git a/src/image.c b/src/image.c
index 9803630..7999aed 100644
--- a/src/image.c
+++ b/src/image.c
@@ -175,7 +175,7 @@ uint8_t lexlibImageFlip(LexlibImage* image, uint8_t flags){
return LEXLIB_OK;
}
-uint8_t lexlibImagePixelSet(const LexlibImage* image, uint32_t x, uint32_t y, LexlibColor color, uint8_t blendmode){
+uint8_t lexlibImagePixelSet(LexlibImage* image, uint32_t x, uint32_t y, LexlibColor color, uint8_t blendmode){
if(x >= image->width || y >= image->height)
return LEXLIB_INVALID_OPERATION;
@@ -305,6 +305,9 @@ uint8_t lexlibImagePixelSet(const LexlibImage* image, uint32_t x, uint32_t y, Le
}
LexlibColor lexlibImagePixelGet(const LexlibImage* image, uint32_t x, uint32_t y){
+ if(x >= image->width || y >= image->height)
+ return LEXLIB_COLOR_MAGENTA;
+
uint8_t pixelSize = image->bpp / 8;
size_t rowsize = image->width * pixelSize;
size_t offset = (y * rowsize) + (x * pixelSize);
--
GitLab
From d75502f803325bb73c1579c24ffc46ad4326d9e1 Mon Sep 17 00:00:00 2001
From: alexevier
Date: Wed, 17 May 2023 03:29:52 -0400
Subject: [PATCH 53/64] documentation updates
---
CHANGELOG.md | 9 +-
documentation/color.html | 1 +
documentation/file.html | 45 +++++++++-
documentation/frontpage.html | 14 +++
documentation/image.html | 164 ++++++++++++++++++++++++++++++++++-
documentation/lexlib.html | 7 ++
include/lexlib/image.h | 4 +-
7 files changed, 231 insertions(+), 13 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 02921d4..c223f9e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,11 @@
## 1.5.0 (under development)
-+ lexlibColor16Blend().
-+ lexlibImagePixelSet().
-+ lexlibFileBytes():
++ lexlibFileBytes();
+ lexlibPowu();
-+ lexlibImageLoadBmp();
++ lexlibColor16Blend();
++ lexlibImagePixelSet();
+ lexlibImagePixelGet();
++ lexlibImageLoadBmp();
++ lexlibImageSaveBmp();
+ lexlibImageSaveBmpEx();
+ fixed strPath buffer overflows.
+ fixed imageFlip X buffer overflow.
diff --git a/documentation/color.html b/documentation/color.html
index 42cdae4..197eefe 100644
--- a/documentation/color.html
+++ b/documentation/color.html
@@ -145,6 +145,7 @@
Functions
LexlibColor lexlibColorBlend(const LexlibColor dst, const LexlibColor src, uint8_t mode);
+ LexlibColor16 lexlibColor16Blend(const LexlibColor16 dst, const LexlibColor16 src, uint8_t mode);
LexlibColorFlt lexlibColorFltBlend(const LexlibColorFlt dst, const LexlibColorFlt src, uint8_t mode);
diff --git a/documentation/file.html b/documentation/file.html
index 7ddfc1d..6837a1e 100644
--- a/documentation/file.html
+++ b/documentation/file.html
@@ -12,14 +12,28 @@
Frontpage
GitLab
- lexlibFileToString();
- lexlibStringToFile();
+ Structs
+ lexlibFileToString()
+ lexlibStringToFile()
+ lexlibFileBytes()
lexlib file handeling.
- these functions are defined in <lexlib/file.h>
+ header: <lexlib/file.h>
+
+
+
+
Structs
+
+
+ struct LexlibBytes {
+ uint8_t* data;
+ size_t count;
+
};
+
+
@@ -83,6 +97,7 @@
Example
+
const char text[] = "the dog is a good boi";
switch(lexlibStringToFile(text, "path/to/goodbois/file.txt")){
case 0: printf("file written successfully.\n");
@@ -100,6 +115,30 @@
+
+
+
lexlibFileBytes()
+
+ reads a file as bytes and returns them in a LexlibBytes struct.
+
+
Function
+
LexlibBytes lexlibFileBytes(const char* filename);
+
+
Parameter
+
const char* filename : name/path of the file to be loaded.
+
+
Return
+
LexlibBytes : with the data.
+
+ - On error bytes.data will be NULL and the error is placed in bytes.count.
+
- LEXLIB_CANT_OPEN : can't open the file, might not exist or not have permissions.
+
- LEXLIB_OUT_OF_MEMORY : can't allocate the memory for the file data.
+
- LEXLIB_ERROR : error parsing the file.
+
- LEXLIB_PARTIAL_READ : couldn't read the entire file.
+
+
+
+