Skip to content

Commit

Permalink
Image API: Refactor. Return original bit depth of the image.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ghabry committed Apr 15, 2024
1 parent 9c29b62 commit 0f6f8fb
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 73 deletions.
47 changes: 23 additions & 24 deletions src/bitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,67 +99,66 @@ Bitmap::Bitmap(Filesystem_Stream::InputStream stream, bool transparent, uint32_t
return;
}

int w = 0;
int h = 0;
void* pixels = nullptr;
ImageOut image_out;

uint8_t data[4] = {};
size_t bytes = stream.read(reinterpret_cast<char*>(data), 4).gcount();
stream.seekg(0, std::ios::ios_base::beg);

bool img_okay = false;

if (bytes >= 4 && strncmp((char*)data, "XYZ1", 4) == 0)
img_okay = ImageXYZ::ReadXYZ(stream, transparent, w, h, pixels);
else if (bytes > 2 && strncmp((char*)data, "BM", 2) == 0)
img_okay = ImageBMP::ReadBMP(stream, transparent, w, h, pixels);
else if (bytes >= 4 && strncmp((char*)(data + 1), "PNG", 3) == 0)
img_okay = ImagePNG::ReadPNG(stream, transparent, w, h, pixels);
else
if (bytes >= 4 && strncmp((char*)data, "XYZ1", 4) == 0) {
img_okay = ImageXYZ::Read(stream, transparent, image_out);
} else if (bytes > 2 && strncmp((char*)data, "BM", 2) == 0) {
img_okay = ImageBMP::Read(stream, transparent, image_out);
} else if (bytes >= 4 && strncmp((char*)(data + 1), "PNG", 3) == 0) {
img_okay = ImagePNG::Read(stream, transparent, image_out);
} else
Output::Warning("Unsupported image file {} (Magic: {:02X})", stream.GetName(), *reinterpret_cast<uint32_t*>(data));

if (!img_okay) {
free(pixels);
pixels = nullptr;
free(image_out.pixels);
return;
}

Init(w, h, nullptr);
Init(image_out.width, image_out.height, nullptr);

ConvertImage(w, h, pixels, transparent);
ConvertImage(image_out.width, image_out.height, image_out.pixels, transparent);

CheckPixels(flags);

original_bpp = image_out.bpp;

filename = ToString(stream.GetName());
}

Bitmap::Bitmap(const uint8_t* data, unsigned bytes, bool transparent, uint32_t flags) {
format = (transparent ? pixel_format : opaque_pixel_format);
pixman_format = find_format(format);

int w = 0, h = 0;
void* pixels = nullptr;
ImageOut image_out;

bool img_okay = false;

if (bytes > 4 && strncmp((char*) data, "XYZ1", 4) == 0)
img_okay = ImageXYZ::ReadXYZ(data, bytes, transparent, w, h, pixels);
img_okay = ImageXYZ::Read(data, bytes, transparent, image_out);
else if (bytes > 2 && strncmp((char*) data, "BM", 2) == 0)
img_okay = ImageBMP::ReadBMP(data, bytes, transparent, w, h, pixels);
img_okay = ImageBMP::Read(data, bytes, transparent, image_out);
else if (bytes > 4 && strncmp((char*)(data + 1), "PNG", 3) == 0)
img_okay = ImagePNG::ReadPNG((const void*) data, transparent, w, h, pixels);
img_okay = ImagePNG::Read((const void*) data, transparent, image_out);
else
Output::Warning("Unsupported image (Magic: {:02X})", bytes >= 4 ? *reinterpret_cast<const uint32_t*>(data) : 0);

if (!img_okay) {
free(pixels);
pixels = nullptr;
free(image_out.pixels);
return;
}

Init(w, h, nullptr);
Init(image_out.width, image_out.height, nullptr);

ConvertImage(image_out.width, image_out.height, image_out.pixels, transparent);

ConvertImage(w, h, pixels, transparent);
original_bpp = image_out.bpp;

CheckPixels(flags);
}
Expand All @@ -183,7 +182,7 @@ bool Bitmap::WritePNG(std::ostream& os) const {
pixman_image_composite32(PIXMAN_OP_SRC, bitmap.get(), NULL, dst.get(),
0, 0, 0, 0, 0, 0, width, height);

return ImagePNG::WritePNG(os, width, height, &data.front());
return ImagePNG::Write(os, width, height, &data.front());
}

size_t Bitmap::GetSize() const {
Expand Down
21 changes: 21 additions & 0 deletions src/bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ class Bitmap {
*/
StringView GetFilename() const;

/**
* Gets bpp of the source image.
*
* @return Bpp
*/
int GetOriginalBpp() const;

void CheckPixels(uint32_t flags);

/**
Expand Down Expand Up @@ -599,6 +606,9 @@ class Bitmap {

std::string filename;

/** Bpp of the source image */
int original_bpp;

/** Bitmap data. */
PixmanImagePtr bitmap;
pixman_format_code_t pixman_format;
Expand Down Expand Up @@ -636,6 +646,13 @@ class Bitmap {
bool read_only = false;
};

struct ImageOut {
int width = 0;
int height = 0;
void* pixels = nullptr;
int bpp = 0;
};

inline ImageOpacity Bitmap::GetImageOpacity() const {
return image_opacity;
}
Expand Down Expand Up @@ -672,4 +689,8 @@ inline StringView Bitmap::GetFilename() const {
return filename;
}

inline int Bitmap::GetOriginalBpp() const {
return original_bpp;
}

#endif
21 changes: 10 additions & 11 deletions src/image_bmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,8 @@ ImageBMP::BitmapHeader ImageBMP::ParseHeader(const uint8_t*& ptr, uint8_t const*
return hdr;
}

bool ImageBMP::ReadBMP(const uint8_t* data, unsigned len, bool transparent,
int& width, int& height, void*& pixels) {
pixels = nullptr;
bool ImageBMP::Read(const uint8_t* data, unsigned len, bool transparent, ImageOut& output) {
output.pixels = nullptr;

if (len < 64) {
Output::Warning("Not a valid BMP file.");
Expand Down Expand Up @@ -142,13 +141,13 @@ bool ImageBMP::ReadBMP(const uint8_t* data, unsigned len, bool transparent,
int line_width = (hdr.depth == 4) ? (hdr.w + 1) >> 1 : hdr.w;
int padding = (-line_width)&3;

pixels = malloc(hdr.w * hdr.h * 4);
if (!pixels) {
output.pixels = malloc(hdr.w * hdr.h * 4);
if (!output.pixels) {
Output::Warning("Error allocating BMP pixel buffer.");
return false;
}

uint8_t* dst = (uint8_t*) pixels;
uint8_t* dst = (uint8_t*) output.pixels;
for (int y = 0; y < hdr.h; y++) {
const uint8_t* src = src_pixels + (vflip ? hdr.h - 1 - y : y) * (line_width + padding);
for (int x = 0; x < hdr.w; x += 2) {
Expand Down Expand Up @@ -182,13 +181,13 @@ bool ImageBMP::ReadBMP(const uint8_t* data, unsigned len, bool transparent,
}
}

width = hdr.w;
height = hdr.h;
output.width = hdr.w;
output.height = hdr.h;
output.bpp = hdr.depth; // Currently only 4 and 8 bit (indexed) are supported
return true;
}

bool ImageBMP::ReadBMP(Filesystem_Stream::InputStream& stream, bool transparent,
int& width, int& height, void*& pixels) {
bool ImageBMP::Read(Filesystem_Stream::InputStream& stream, bool transparent, ImageOut& output) {
std::vector<uint8_t> buffer = Utils::ReadStream(stream);
return ReadBMP(&buffer.front(), (unsigned) buffer.size(), transparent, width, height, pixels);
return Read(&buffer.front(), (unsigned) buffer.size(), transparent, output);
}
5 changes: 3 additions & 2 deletions src/image_bmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define EP_IMAGE_BMP_H

#include <cstdint>
#include "bitmap.h"
#include "filesystem_stream.h"

namespace ImageBMP {
Expand All @@ -33,8 +34,8 @@ namespace ImageBMP {
int palette_size = 0;
};

bool ReadBMP(const uint8_t* data, unsigned len, bool transparent, int& width, int& height, void*& pixels);
bool ReadBMP(Filesystem_Stream::InputStream& stream, bool transparent, int& width, int& height, void*& pixels);
bool Read(const uint8_t* data, unsigned len, bool transparent, ImageOut& output);
bool Read(Filesystem_Stream::InputStream& stream, bool transparent, ImageOut& output);

BitmapHeader ParseHeader(const uint8_t*& ptr, uint8_t const* e);
}
Expand Down
42 changes: 22 additions & 20 deletions src/image_png.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,23 @@ static void on_png_error(png_structp, png_const_charp error_msg) {
Output::Warning("libpng: {}", error_msg);
}

static bool ReadPNGWithReadFunction(png_voidp,png_rw_ptr, bool, int&, int&, void*&);
static bool ReadPNGWithReadFunction(png_voidp,png_rw_ptr, bool, ImageOut&);
static void ReadPalettedData(png_struct*, png_info*, png_uint_32, png_uint_32, bool, uint32_t*);
static void ReadGrayData(png_struct*, png_info*, png_uint_32, png_uint_32, bool, uint32_t*);
static void ReadGrayAlphaData(png_struct*, png_info*, png_uint_32, png_uint_32, uint32_t*);
static void ReadRGBData(png_struct*, png_info*, png_uint_32, png_uint_32, uint32_t*);
static void ReadRGBAData(png_struct*, png_info*, png_uint_32, png_uint_32, uint32_t*);

bool ImagePNG::ReadPNG(const void* buffer, bool transparent,
int& width, int& height, void*& pixels) {
return ReadPNGWithReadFunction((png_voidp)&buffer, read_data, transparent, width, height, pixels);
bool ImagePNG::Read(const void* buffer, bool transparent, ImageOut& output) {
return ReadPNGWithReadFunction((png_voidp)&buffer, read_data, transparent, output);
}

bool ImagePNG::ReadPNG(Filesystem_Stream::InputStream& stream, bool transparent,
int& width, int& height, void*& pixels) {
return ReadPNGWithReadFunction(&stream, read_data_istream, transparent, width, height, pixels);
bool ImagePNG::Read(Filesystem_Stream::InputStream& stream, bool transparent, ImageOut& output) {
return ReadPNGWithReadFunction(&stream, read_data_istream, transparent, output);
}

static bool ReadPNGWithReadFunction(png_voidp user_data, png_rw_ptr fn, bool transparent,
int& width, int& height, void*& pixels) {
pixels = nullptr;
static bool ReadPNGWithReadFunction(png_voidp user_data, png_rw_ptr fn, bool transparent, ImageOut& output) {
output.pixels = nullptr;

png_struct *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, on_png_error, on_png_warning);
if (png_ptr == NULL) {
Expand Down Expand Up @@ -94,35 +91,40 @@ static bool ReadPNGWithReadFunction(png_voidp user_data, png_rw_ptr fn, bool tra
png_get_IHDR(png_ptr, info_ptr, &w, &h,
&bit_depth, &color_type, NULL, NULL, NULL);

pixels = malloc(w * h * 4);
if (!pixels) {
output.pixels = malloc(w * h * 4);
if (!output.pixels) {
Output::Warning("Error allocating PNG pixel buffer.");
return false;
}

switch (color_type) {
case PNG_COLOR_TYPE_PALETTE:
ReadPalettedData(png_ptr, info_ptr, w, h, transparent, (uint32_t*)pixels);
ReadPalettedData(png_ptr, info_ptr, w, h, transparent, (uint32_t*)output.pixels);
output.bpp = 8;
break;
case PNG_COLOR_TYPE_GRAY:
ReadGrayData(png_ptr, info_ptr, w, h, transparent, (uint32_t*)pixels);
ReadGrayData(png_ptr, info_ptr, w, h, transparent, (uint32_t*)output.pixels);
output.bpp = 8;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
ReadGrayAlphaData(png_ptr, info_ptr, w, h, (uint32_t*)pixels);
ReadGrayAlphaData(png_ptr, info_ptr, w, h, (uint32_t*)output.pixels);
output.bpp = 8;
break;
case PNG_COLOR_TYPE_RGB:
ReadRGBData(png_ptr, info_ptr, w, h, (uint32_t*)pixels);
ReadRGBData(png_ptr, info_ptr, w, h, (uint32_t*)output.pixels);
output.bpp = 24;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
ReadRGBAData(png_ptr, info_ptr, w, h, (uint32_t*)pixels);
ReadRGBAData(png_ptr, info_ptr, w, h, (uint32_t*)output.pixels);
output.bpp = 32;
break;
}

png_read_end(png_ptr, NULL);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

width = w;
height = h;
output.width = w;
output.height = h;
return true;
}

Expand Down Expand Up @@ -251,7 +253,7 @@ static void flush_stream(png_structp out_ptr) {
reinterpret_cast<Filesystem_Stream::OutputStream*>(png_get_io_ptr(out_ptr))->flush();
}

bool ImagePNG::WritePNG(std::ostream& os, uint32_t width, uint32_t height, uint32_t* data) {
bool ImagePNG::Write(std::ostream& os, uint32_t width, uint32_t height, uint32_t* data) {
png_structp write = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!write) {
Output::Warning("Bitmap::WritePNG: error in png_create_write");
Expand Down
7 changes: 4 additions & 3 deletions src/image_png.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
#define EP_IMAGE_PNG_H

#include <cstdint>
#include "bitmap.h"
#include "filesystem_stream.h"

namespace ImagePNG {
bool ReadPNG(const void* buffer, bool transparent, int& width, int& height, void*& pixels);
bool ReadPNG(Filesystem_Stream::InputStream& is, bool transparent, int& width, int& height, void*& pixels);
bool WritePNG(std::ostream& os, uint32_t width, uint32_t height, uint32_t* data);
bool Read(const void* buffer, bool transparent, ImageOut& output);
bool Read(Filesystem_Stream::InputStream& is, bool transparent, ImageOut& output);
bool Write(std::ostream& os, uint32_t width, uint32_t height, uint32_t* data);
}

#endif
22 changes: 11 additions & 11 deletions src/image_xyz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@
#include "output.h"
#include "image_xyz.h"

bool ImageXYZ::ReadXYZ(const uint8_t* data, unsigned len, bool transparent,
int& width, int& height, void*& pixels) {
pixels = nullptr;
bool ImageXYZ::Read(const uint8_t* data, unsigned len, bool transparent, ImageOut& output) {
output.pixels = nullptr;

if (len < 8) {
Output::Warning("Not a valid XYZ file.");
Expand All @@ -47,13 +46,13 @@ bool ImageXYZ::ReadXYZ(const uint8_t* data, unsigned len, bool transparent,
}
const uint8_t (*palette)[3] = (const uint8_t(*)[3]) &dst_buffer.front();

pixels = malloc(w * h * 4);
if (!pixels) {
output.pixels = malloc(w * h * 4);
if (!output.pixels) {
Output::Warning("Error allocating XYZ pixel buffer.");
return false;
}

uint8_t* dst = (uint8_t*) pixels;
uint8_t* dst = (uint8_t*) output.pixels;
const uint8_t* src = (const uint8_t*) &dst_buffer[768];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Expand All @@ -66,13 +65,14 @@ bool ImageXYZ::ReadXYZ(const uint8_t* data, unsigned len, bool transparent,
}
}

width = w;
height = h;
output.width = w;
output.height = h;
output.bpp = 8;

return true;
}

bool ImageXYZ::ReadXYZ(Filesystem_Stream::InputStream& stream, bool transparent,
int& width, int& height, void*& pixels) {
bool ImageXYZ::Read(Filesystem_Stream::InputStream& stream, bool transparent, ImageOut& output) {
std::vector<uint8_t> buffer = Utils::ReadStream(stream);
return ReadXYZ(&buffer.front(), (unsigned) buffer.size(), transparent, width, height, pixels);
return Read(&buffer.front(), (unsigned) buffer.size(), transparent, output);
}
5 changes: 3 additions & 2 deletions src/image_xyz.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@

#include <cstdio>
#include <cstdint>
#include "bitmap.h"
#include "filesystem_stream.h"

namespace ImageXYZ {
bool ReadXYZ(const uint8_t* data, unsigned len, bool transparent, int& width, int& height, void*& pixels);
bool ReadXYZ(Filesystem_Stream::InputStream& stream, bool transparent, int& width, int& height, void*& pixels);
bool Read(const uint8_t* data, unsigned len, bool transparent, ImageOut& output);
bool Read(Filesystem_Stream::InputStream& stream, bool transparent, ImageOut& output);
}

#endif

0 comments on commit 0f6f8fb

Please sign in to comment.