diff options
| author | Clement Sibille <clements+git@lisible.xyz> | 2024-03-08 01:16:53 +0900 | 
|---|---|---|
| committer | Clement Sibille <clements+git@lisible.xyz> | 2024-03-08 01:16:53 +0900 | 
| commit | 943bcac90e5e3aaee0647b070e760c0985d03d0d (patch) | |
| tree | 135bb1a1a20c7655f5ecfd94ea36c82750f61f7f | |
| parent | 665e6155ac8b055d89cead210300ab22a91f74ff (diff) | |
Add LisPng_write_RGBA8_data()
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | lisiblepng-bin/src/main.c | 5 | ||||
| -rw-r--r-- | lisiblepng/src/lisiblepng.c | 66 | ||||
| -rw-r--r-- | lisiblepng/src/lisiblepng.h | 9 | 
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  | 
