1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 22:37:35 +00:00

LibGfx: Improve PNG encoder API somewhat

This is still far from ideal, but let's at least make it take a
Gfx::Bitmap const&.
This commit is contained in:
Andreas Kling 2021-04-19 23:43:04 +02:00
parent 51fe25fdbb
commit 6793574003
4 changed files with 31 additions and 30 deletions

View file

@ -155,11 +155,11 @@ void Image::export_bmp(const String& file_path)
void Image::export_png(const String& file_path) void Image::export_png(const String& file_path)
{ {
auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, m_size); auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, m_size);
VERIFY(bitmap);
GUI::Painter painter(*bitmap); GUI::Painter painter(*bitmap);
paint_into(painter, { 0, 0, m_size.width(), m_size.height() }); paint_into(painter, { 0, 0, m_size.width(), m_size.height() });
Gfx::PNGWriter png_writer; auto png = Gfx::PNGWriter::encode(*bitmap);
auto png = png_writer.write(bitmap);
auto file = fopen(file_path.characters(), "wb"); auto file = fopen(file_path.characters(), "wb");
fwrite(png.data(), sizeof(u8), png.size(), file); fwrite(png.data(), sizeof(u8), png.size(), file);
fclose(file); fclose(file);

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021, Pierre Hoffmeister * Copyright (c) 2021, Pierre Hoffmeister
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -24,17 +25,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "PNGWriter.h"
#include <AK/String.h> #include <AK/String.h>
#include <LibCrypto/Checksum/CRC32.h> #include <LibCrypto/Checksum/CRC32.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/PNGWriter.h>
namespace Gfx { namespace Gfx {
class PNGChunk { class PNGChunk {
public: public:
PNGChunk(const String&); explicit PNGChunk(String);
const Vector<u8>& data() const { return m_data; }; Vector<u8> const& data() const { return m_data; };
const String& type() const { return m_type; }; String const& type() const { return m_type; };
void add_u8(u8); void add_u8(u8);
void add_u16_big(u16); void add_u16_big(u16);
void add_u32_big(u32); void add_u32_big(u32);
@ -51,8 +53,8 @@ public:
void finalize(PNGChunk&); void finalize(PNGChunk&);
void add_byte_to_block(u8 data, PNGChunk&); void add_byte_to_block(u8 data, PNGChunk&);
u32 adler_s1() { return m_adler_s1; } u32 adler_s1() const { return m_adler_s1; }
u32 adler_s2() { return m_adler_s2; } u32 adler_s2() const { return m_adler_s2; }
private: private:
void add_block_to_chunk(PNGChunk&, bool); void add_block_to_chunk(PNGChunk&, bool);
@ -63,7 +65,7 @@ private:
u32 m_adler_s2 { 0 }; u32 m_adler_s2 { 0 };
}; };
PNGChunk::PNGChunk(const String& type) PNGChunk::PNGChunk(String type)
: m_type(move(type)) : m_type(move(type))
{ {
} }
@ -141,7 +143,7 @@ void NonCompressibleBlock::update_adler(u8 data)
m_adler_s2 = (m_adler_s2 + m_adler_s1) % 65521; m_adler_s2 = (m_adler_s2 + m_adler_s1) % 65521;
} }
void PNGWriter::add_chunk(const PNGChunk& png_chunk) void PNGWriter::add_chunk(PNGChunk const& png_chunk)
{ {
Vector<u8> combined; Vector<u8> combined;
for (auto character : png_chunk.type()) { for (auto character : png_chunk.type()) {
@ -185,7 +187,7 @@ void PNGWriter::add_IEND_chunk()
add_chunk(png_chunk); add_chunk(png_chunk);
} }
void PNGWriter::add_IDAT_chunk(const RefPtr<Bitmap> bitmap) void PNGWriter::add_IDAT_chunk(Gfx::Bitmap const& bitmap)
{ {
PNGChunk png_chunk { "IDAT" }; PNGChunk png_chunk { "IDAT" };
@ -194,11 +196,11 @@ void PNGWriter::add_IDAT_chunk(const RefPtr<Bitmap> bitmap)
NonCompressibleBlock non_compressible_block; NonCompressibleBlock non_compressible_block;
for (int y = 0; y < bitmap->height(); ++y) { for (int y = 0; y < bitmap.height(); ++y) {
non_compressible_block.add_byte_to_block(0, png_chunk); non_compressible_block.add_byte_to_block(0, png_chunk);
for (int x = 0; x < bitmap->width(); ++x) { for (int x = 0; x < bitmap.width(); ++x) {
auto pixel = bitmap->get_pixel(x, y); auto pixel = bitmap.get_pixel(x, y);
non_compressible_block.add_byte_to_block(pixel.red(), png_chunk); non_compressible_block.add_byte_to_block(pixel.red(), png_chunk);
non_compressible_block.add_byte_to_block(pixel.green(), png_chunk); non_compressible_block.add_byte_to_block(pixel.green(), png_chunk);
non_compressible_block.add_byte_to_block(pixel.blue(), png_chunk); non_compressible_block.add_byte_to_block(pixel.blue(), png_chunk);
@ -213,16 +215,14 @@ void PNGWriter::add_IDAT_chunk(const RefPtr<Bitmap> bitmap)
add_chunk(png_chunk); add_chunk(png_chunk);
} }
ByteBuffer PNGWriter::write(const RefPtr<Bitmap> bitmap) ByteBuffer PNGWriter::encode(Gfx::Bitmap const& bitmap)
{ {
add_png_header(); PNGWriter writer;
add_IHDR_chunk(bitmap->width(), bitmap->height(), 8, 6, 0, 0, 0); writer.add_png_header();
add_IDAT_chunk(bitmap); writer.add_IHDR_chunk(bitmap.width(), bitmap.height(), 8, 6, 0, 0, 0);
add_IEND_chunk(); writer.add_IDAT_chunk(bitmap);
writer.add_IEND_chunk();
ByteBuffer buf; return ByteBuffer::copy(writer.m_data);
buf.append(m_data.data(), m_data.size());
return buf;
} }
} }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021, Pierre Hoffmeister * Copyright (c) 2021, Pierre Hoffmeister
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -26,9 +27,8 @@
#pragma once #pragma once
#include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibGfx/Bitmap.h> #include <LibGfx/Forward.h>
namespace Gfx { namespace Gfx {
@ -36,14 +36,16 @@ class PNGChunk;
class PNGWriter { class PNGWriter {
public: public:
ByteBuffer write(const RefPtr<Bitmap>); static ByteBuffer encode(Gfx::Bitmap const&);
private: private:
PNGWriter() { }
Vector<u8> m_data; Vector<u8> m_data;
void add_chunk(const PNGChunk&); void add_chunk(PNGChunk const&);
void add_png_header(); void add_png_header();
void add_IHDR_chunk(u32 width, u32 height, u8 bit_depth, u8 color_type, u8 compression_method, u8 filter_method, u8 interlace_method); void add_IHDR_chunk(u32 width, u32 height, u8 bit_depth, u8 color_type, u8 compression_method, u8 filter_method, u8 interlace_method);
void add_IDAT_chunk(const RefPtr<Bitmap>); void add_IDAT_chunk(Gfx::Bitmap const&);
void add_IEND_chunk(); void add_IEND_chunk();
}; };

View file

@ -67,8 +67,7 @@ int main(int argc, char** argv)
return 0; return 0;
} }
Gfx::PNGWriter writer; auto encoded_bitmap = Gfx::PNGWriter::encode(*bitmap);
auto encoded_bitmap = writer.write(bitmap);
if (encoded_bitmap.is_empty()) { if (encoded_bitmap.is_empty()) {
warnln("Failed to encode PNG"); warnln("Failed to encode PNG");
return 1; return 1;