summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClement Sibille <clements+git@lisible.xyz>2024-03-08 01:16:53 +0900
committerClement Sibille <clements+git@lisible.xyz>2024-03-08 01:16:53 +0900
commit943bcac90e5e3aaee0647b070e760c0985d03d0d (patch)
tree135bb1a1a20c7655f5ecfd94ea36c82750f61f7f
parent665e6155ac8b055d89cead210300ab22a91f74ff (diff)
Add LisPng_write_RGBA8_data()
-rw-r--r--CHANGELOG.md1
-rw-r--r--lisiblepng-bin/src/main.c5
-rw-r--r--lisiblepng/src/lisiblepng.c66
-rw-r--r--lisiblepng/src/lisiblepng.h9
4 files changed, 80 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 04ecdb0..52f492f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
- Add LisPngColourType_sample_count() function
- Add LisPng accessor functions
- Improve lisiblepng-bin error handling
+- Add LisPng_write_RGBA8_data()
## 0.1.0 (2024-03-05)
- Add PNG decoding support for colour types Greyscale and Truecolour
diff --git a/lisiblepng-bin/src/main.c b/lisiblepng-bin/src/main.c
index 6b52f2f..730ae9a 100644
--- a/lisiblepng-bin/src/main.c
+++ b/lisiblepng-bin/src/main.c
@@ -14,6 +14,11 @@ int main(int argc, char **argv) {
const char *png_filepath = argv[1];
FILE *png_file = fopen(png_filepath, "r");
+ fseek(png_file, 0, SEEK_END);
+ long file_size = ftell(png_file);
+ LOGN("File size: %ld bytes", file_size);
+ fseek(png_file, 0, SEEK_SET);
+
if (!png_file) {
const char *error_message = strerror(errno);
LOGN("Couldn't open PNG file: %s", error_message);
diff --git a/lisiblepng/src/lisiblepng.c b/lisiblepng/src/lisiblepng.c
index bf1c27c..ffd2342 100644
--- a/lisiblepng/src/lisiblepng.c
+++ b/lisiblepng/src/lisiblepng.c
@@ -521,8 +521,72 @@ cleanup_data:
err:
return NULL;
}
-
#undef PARSE_FIELD
+
+void LisPng_write_RGBA8_data(const LisPng *png, uint8_t *output_data) {
+ ASSERT(png != NULL);
+ ASSERT(output_data != NULL);
+ static const int TARGET_BYTES_PER_PIXEL = 4;
+ size_t sample_count = LisPngColourType_sample_count(png->colour_type);
+ size_t bits_per_pixel = png->bits_per_sample * sample_count;
+ size_t bytes_per_pixel = bits_per_pixel / 8;
+ if (png->bits_per_sample < 8) {
+ bytes_per_pixel = 1;
+ }
+
+ for (size_t pixel_index = 0; pixel_index < png->width * png->height;
+ pixel_index++) {
+ size_t source_pixel_base = pixel_index * bytes_per_pixel;
+ size_t target_pixel_base = pixel_index * TARGET_BYTES_PER_PIXEL;
+
+ if (png->colour_type == LisPngColourType_Greyscale) {
+ if (bits_per_pixel == 16) {
+ uint16_t grey = (png->data[source_pixel_base] << 8) |
+ png->data[source_pixel_base + 1];
+ output_data[target_pixel_base] = grey / 2;
+ output_data[target_pixel_base + 1] = grey / 2;
+ output_data[target_pixel_base + 2] = grey / 2;
+ output_data[target_pixel_base + 3] = 0xFF;
+ } else {
+ size_t absolute_bit_offset = pixel_index * bits_per_pixel;
+ size_t byte_offset = absolute_bit_offset / 8;
+ size_t relative_bit_offset = absolute_bit_offset % 8;
+ uint8_t grey = (png->data[byte_offset] >>
+ (7 - relative_bit_offset - (bits_per_pixel - 1))) &
+ ((1 << bits_per_pixel) - 1);
+ output_data[target_pixel_base] = grey;
+ output_data[target_pixel_base + 1] = grey;
+ output_data[target_pixel_base + 2] = grey;
+ output_data[target_pixel_base + 3] = 0xFF;
+ }
+ } else if (png->colour_type == LisPngColourType_Truecolour) {
+ if (png->bits_per_sample == 16) {
+ uint16_t r = (png->data[source_pixel_base] << 8) |
+ png->data[source_pixel_base + 1];
+ uint16_t g = (png->data[source_pixel_base + 2] << 8) |
+ png->data[source_pixel_base + 3];
+ uint16_t b = (png->data[source_pixel_base + 4] << 8) |
+ png->data[source_pixel_base + 5];
+ output_data[target_pixel_base] = r / 2;
+ output_data[target_pixel_base + 1] = g / 2;
+ output_data[target_pixel_base + 2] = b / 2;
+ output_data[target_pixel_base + 3] = 0xFF;
+ } else {
+ uint8_t r = png->data[source_pixel_base];
+ uint8_t g = png->data[source_pixel_base + 1];
+ uint8_t b = png->data[source_pixel_base + 2];
+ output_data[target_pixel_base] = r;
+ output_data[target_pixel_base + 1] = g;
+ output_data[target_pixel_base + 2] = b;
+ output_data[target_pixel_base + 3] = 0xFF;
+ }
+ } else {
+ LPNG_LOG_ERR0("Unsupported colour type");
+ exit(1);
+ }
+ }
+}
+
void LisPng_destroy(LisPng *png) {
free(png->data);
free(png);
diff --git a/lisiblepng/src/lisiblepng.h b/lisiblepng/src/lisiblepng.h
index a23ac91..e7f94ec 100644
--- a/lisiblepng/src/lisiblepng.h
+++ b/lisiblepng/src/lisiblepng.h
@@ -24,6 +24,15 @@ typedef struct LisPng LisPng;
/// The returned PNG is owned by the caller and must be destroyed with
/// Png_destroy.
LisPng *LisPng_decode(FILE *stream);
+
+/// Writes the PNG image data as RGBA8 data to a buffer
+///
+/// Note: The output_data buffer must be allocated with enough memory
+/// (width*height*32)
+/// @param png The png
+/// @param output_data The output buffer
+void LisPng_write_RGBA8_data(const LisPng *png, uint8_t *output_data);
+
/// Outputs the provided Png struct as a PPM image to stdout
///
/// @param png The png
Go back to lisible.xyz