Add support for BGR formats to Pixmap, and RGB conversion.

The Cairo image surface backend uses the BGR format for "RGB24"
for some reason, and we need to handle that.
pull/33/head
whitequark 2016-07-24 23:53:08 +00:00
parent 6d5d88f01e
commit 803665404e
3 changed files with 55 additions and 4 deletions

View File

@ -216,6 +216,9 @@ void OpenGl1Renderer::SelectTexture(std::shared_ptr<const Pixmap> pm) {
case Pixmap::Format::RGBA: format = GL_RGBA; break; case Pixmap::Format::RGBA: format = GL_RGBA; break;
case Pixmap::Format::RGB: format = GL_RGB; break; case Pixmap::Format::RGB: format = GL_RGB; break;
case Pixmap::Format::A: format = GL_ALPHA; break; case Pixmap::Format::A: format = GL_ALPHA; break;
case Pixmap::Format::BGRA:
case Pixmap::Format::BGR:
ssassert(false, "Unexpected pixmap format");
} }
glTexImage2D(GL_TEXTURE_2D, 0, format, pm->width, pm->height, 0, glTexImage2D(GL_TEXTURE_2D, 0, format, pm->width, pm->height, 0,
format, GL_UNSIGNED_BYTE, &pm->data[0]); format, GL_UNSIGNED_BYTE, &pm->data[0]);

View File

@ -65,7 +65,9 @@ std::shared_ptr<Pixmap> LoadPng(const std::string &name) {
size_t Pixmap::GetBytesPerPixel() const { size_t Pixmap::GetBytesPerPixel() const {
switch(format) { switch(format) {
case Format::RGBA: return 4; case Format::RGBA: return 4;
case Format::BGRA: return 4;
case Format::RGB: return 3; case Format::RGB: return 3;
case Format::BGR: return 3;
case Format::A: return 1; case Format::A: return 1;
} }
ssassert(false, "Unexpected pixmap format"); ssassert(false, "Unexpected pixmap format");
@ -81,12 +83,52 @@ RgbaColor Pixmap::GetPixel(size_t x, size_t y) const {
case Format::RGB: case Format::RGB:
return RgbaColor::From(pixel[0], pixel[1], pixel[2], 255); return RgbaColor::From(pixel[0], pixel[1], pixel[2], 255);
case Format::BGRA:
return RgbaColor::From(pixel[2], pixel[1], pixel[0], pixel[3]);
case Format::BGR:
return RgbaColor::From(pixel[2], pixel[1], pixel[0], 255);
case Format::A: case Format::A:
return RgbaColor::From( 255, 255, 255, pixel[0]); return RgbaColor::From( 255, 255, 255, pixel[0]);
} }
ssassert(false, "Unexpected resource format"); ssassert(false, "Unexpected resource format");
} }
void Pixmap::ConvertTo(Format newFormat) {
switch(format) {
case Format::RGBA:
ssassert(newFormat == Format::BGRA, "Unexpected target format");
break;
case Format::BGRA:
ssassert(newFormat == Format::RGBA, "Unexpected target format");
break;
case Format::RGB:
ssassert(newFormat == Format::BGR, "Unexpected target format");
break;
case Format::BGR:
ssassert(newFormat == Format::RGB, "Unexpected target format");
break;
case Format::A:
ssassert(false, "Unexpected target format");
}
size_t bpp = GetBytesPerPixel();
for(size_t j = 0; j != height; j++) {
uint8_t *row = &data[j * stride];
for(size_t i = 0; i != width * bpp; i += bpp) {
// This handles both RGB<>BGR and RGBA<>BGRA.
std::swap(row[i], row[i + 2]);
}
}
format = newFormat;
}
static std::shared_ptr<Pixmap> ReadPngIntoPixmap(png_struct *png_ptr, png_info *info_ptr, static std::shared_ptr<Pixmap> ReadPngIntoPixmap(png_struct *png_ptr, png_info *info_ptr,
bool flip) { bool flip) {
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_GRAY_TO_RGB, NULL); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_GRAY_TO_RGB, NULL);
@ -175,10 +217,13 @@ exit:
bool Pixmap::WritePng(FILE *f, bool flip) { bool Pixmap::WritePng(FILE *f, bool flip) {
int colorType; int colorType;
bool bgr;
switch(format) { switch(format) {
case Format::RGBA: colorType = PNG_COLOR_TYPE_RGBA; break; case Format::RGBA: colorType = PNG_COLOR_TYPE_RGBA; bgr = false; break;
case Format::RGB: colorType = PNG_COLOR_TYPE_RGB; break; case Format::BGRA: colorType = PNG_COLOR_TYPE_RGBA; bgr = true; break;
case Format::A: ssassert(false, "Unexpected pixmap format"); case Format::RGB: colorType = PNG_COLOR_TYPE_RGB; bgr = false; break;
case Format::BGR: colorType = PNG_COLOR_TYPE_RGB; bgr = true; break;
case Format::A: colorType = PNG_COLOR_TYPE_GRAY; bgr = false; break;
} }
std::vector<uint8_t *> rows; std::vector<uint8_t *> rows;
@ -204,6 +249,7 @@ bool Pixmap::WritePng(FILE *f, bool flip) {
png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_set_IHDR(png_ptr, info_ptr, width, height, 8,
colorType, PNG_INTERLACE_NONE, colorType, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
if(bgr) png_set_bgr(png_ptr);
png_write_info(png_ptr, info_ptr); png_write_info(png_ptr, info_ptr);
png_write_image(png_ptr, &rows[0]); png_write_image(png_ptr, &rows[0]);
png_write_end(png_ptr, info_ptr); png_write_end(png_ptr, info_ptr);

View File

@ -24,7 +24,7 @@ std::shared_ptr<Pixmap> LoadPng(const std::string &name);
class Pixmap { class Pixmap {
public: public:
enum class Format { RGBA, RGB, A }; enum class Format { BGRA, RGBA, BGR, RGB, A };
Format format; Format format;
size_t width; size_t width;
@ -40,6 +40,8 @@ public:
size_t GetBytesPerPixel() const; size_t GetBytesPerPixel() const;
RgbaColor GetPixel(size_t x, size_t y) const; RgbaColor GetPixel(size_t x, size_t y) const;
void ConvertTo(Format newFormat);
}; };
class BitmapFont { class BitmapFont {