From 7ec6c86c913fba820870565ee757fdf43ae47433 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 18 Dec 2021 21:26:05 +0100 Subject: [PATCH] Move Image::as_png() out to image_as_png(). --- src/lib/image.cc | 97 ------------------------- src/lib/image.h | 2 - src/lib/image_png.cc | 132 ++++++++++++++++++++++++++++++++++ src/lib/image_png.h | 22 ++++++ src/lib/reel_writer.cc | 3 +- src/lib/wscript | 1 + src/tools/dcpomatic_player.cc | 2 + test/image_test.cc | 9 +-- test/test.cc | 2 +- 9 files changed, 165 insertions(+), 105 deletions(-) create mode 100644 src/lib/image_png.cc create mode 100644 src/lib/image_png.h diff --git a/src/lib/image.cc b/src/lib/image.cc index 861367637..799d7af49 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -44,7 +44,6 @@ extern "C" { #include } LIBDCP_ENABLE_WARNINGS -#include #if HAVE_VALGRIND_MEMCHECK_H #include #endif @@ -1371,102 +1370,6 @@ Image::memory_used () const } -class Memory -{ -public: - Memory () - : data(0) - , size(0) - {} - - ~Memory () - { - free (data); - } - - uint8_t* data; - size_t size; -}; - - -static void -png_write_data (png_structp png_ptr, png_bytep data, png_size_t length) -{ - auto mem = reinterpret_cast(png_get_io_ptr(png_ptr)); - size_t size = mem->size + length; - - if (mem->data) { - mem->data = reinterpret_cast(realloc(mem->data, size)); - } else { - mem->data = reinterpret_cast(malloc(size)); - } - - if (!mem->data) { - throw EncodeError (N_("could not allocate memory for PNG")); - } - - memcpy (mem->data + mem->size, data, length); - mem->size += length; -} - - -static void -png_flush (png_structp) -{ - -} - - -static void -png_error_fn (png_structp, char const * message) -{ - throw EncodeError (String::compose("Error during PNG write: %1", message)); -} - - -dcp::ArrayData -Image::as_png () const -{ - DCPOMATIC_ASSERT (bytes_per_pixel(0) == 4); - DCPOMATIC_ASSERT (planes() == 1); - if (pixel_format() != AV_PIX_FMT_RGBA) { - return convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png(); - } - - /* error handling? */ - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, reinterpret_cast(const_cast(this)), png_error_fn, 0); - if (!png_ptr) { - throw EncodeError (N_("could not create PNG write struct")); - } - - Memory state; - - png_set_write_fn (png_ptr, &state, png_write_data, png_flush); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct (&png_ptr, &info_ptr); - throw EncodeError (N_("could not create PNG info struct")); - } - - png_set_IHDR (png_ptr, info_ptr, size().width, size().height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_byte ** row_pointers = reinterpret_cast(png_malloc(png_ptr, size().height * sizeof(png_byte *))); - for (int i = 0; i < size().height; ++i) { - row_pointers[i] = (png_byte *) (data()[0] + i * stride()[0]); - } - - png_write_info (png_ptr, info_ptr); - png_write_image (png_ptr, row_pointers); - png_write_end (png_ptr, info_ptr); - - png_destroy_write_struct (&png_ptr, &info_ptr); - png_free (png_ptr, row_pointers); - - return dcp::ArrayData (state.data, state.size); -} - - void Image::video_range_to_full_range () { diff --git a/src/lib/image.h b/src/lib/image.h index 328252e68..73d08b902 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -95,8 +95,6 @@ public: size_t memory_used () const; - dcp::ArrayData as_png () const; - static std::shared_ptr ensure_alignment (std::shared_ptr image, Alignment alignment); private: diff --git a/src/lib/image_png.cc b/src/lib/image_png.cc new file mode 100644 index 000000000..b97ef5aad --- /dev/null +++ b/src/lib/image_png.cc @@ -0,0 +1,132 @@ +/* + Copyright (C) 2021 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "dcpomatic_assert.h" +#include "exceptions.h" +#include "image.h" +#include + +#include "i18n.h" + + +using std::shared_ptr; + + +class Memory +{ +public: + Memory () {} + Memory (Memory const&) = delete; + Memory& operator= (Memory const&) = delete; + + ~Memory () + { + free (data); + } + + uint8_t* data = nullptr; + size_t size = 0; +}; + + +static void +png_write_data (png_structp png_ptr, png_bytep data, png_size_t length) +{ + auto mem = reinterpret_cast(png_get_io_ptr(png_ptr)); + size_t size = mem->size + length; + + if (mem->data) { + mem->data = reinterpret_cast(realloc(mem->data, size)); + } else { + mem->data = reinterpret_cast(malloc(size)); + } + + if (!mem->data) { + throw EncodeError (N_("could not allocate memory for PNG")); + } + + memcpy (mem->data + mem->size, data, length); + mem->size += length; +} + + +static void +png_flush (png_structp) +{ + +} + + +static void +png_error_fn (png_structp, char const * message) +{ + throw EncodeError (String::compose("Error during PNG write: %1", message)); +} + + +dcp::ArrayData +image_as_png (shared_ptr image) +{ + DCPOMATIC_ASSERT (image->bytes_per_pixel(0) == 4); + DCPOMATIC_ASSERT (image->planes() == 1); + if (image->pixel_format() != AV_PIX_FMT_RGBA) { + return image_as_png(image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)); + } + + /* error handling? */ + auto png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, reinterpret_cast(const_cast(image.get())), png_error_fn, 0); + if (!png_ptr) { + throw EncodeError (N_("could not create PNG write struct")); + } + + Memory state; + + png_set_write_fn (png_ptr, &state, png_write_data, png_flush); + + auto info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct (&png_ptr, &info_ptr); + throw EncodeError (N_("could not create PNG info struct")); + } + + int const width = image->size().width; + int const height = image->size().height; + + png_set_IHDR (png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + auto row_pointers = reinterpret_cast(png_malloc(png_ptr, image->size().height * sizeof(png_byte *))); + auto const data = image->data()[0]; + auto const stride = image->stride()[0]; + for (int i = 0; i < height; ++i) { + row_pointers[i] = reinterpret_cast(data + i * stride); + } + + png_write_info (png_ptr, info_ptr); + png_write_image (png_ptr, row_pointers); + png_write_end (png_ptr, info_ptr); + + png_destroy_write_struct (&png_ptr, &info_ptr); + png_free (png_ptr, row_pointers); + + return dcp::ArrayData (state.data, state.size); +} + + diff --git a/src/lib/image_png.h b/src/lib/image_png.h new file mode 100644 index 000000000..b3c0774fd --- /dev/null +++ b/src/lib/image_png.h @@ -0,0 +1,22 @@ +/* + Copyright (C) 2021 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +dcp::ArrayData image_as_png (std::shared_ptr image); diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index b5a95d8b1..7a2c9c670 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -28,6 +28,7 @@ #include "film.h" #include "font_data.h" #include "image.h" +#include "image_png.h" #include "job.h" #include "log.h" #include "reel_writer.h" @@ -908,7 +909,7 @@ ReelWriter::write (PlayerText subs, TextType type, optional track, for (auto i: subs.bitmap) { asset->add ( make_shared( - i.image->as_png(), + image_as_png(i.image), dcp::Time(period.from.seconds() - _period.from.seconds(), tcr), dcp::Time(period.to.seconds() - _period.from.seconds(), tcr), i.rectangle.x, dcp::HAlign::LEFT, i.rectangle.y, dcp::VAlign::TOP, diff --git a/src/lib/wscript b/src/lib/wscript index b3428f20b..49b0e4bac 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -122,6 +122,7 @@ sources = """ image_decoder.cc image_examiner.cc image_filename_sorter.cc + image_png.cc image_proxy.cc j2k_image_proxy.cc job.cc diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index 46dead850..5d5e2e825 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -45,6 +45,8 @@ #include "lib/ffmpeg_content.h" #include "lib/file_log.h" #include "lib/film.h" +#include "lib/image.h" +#include "lib/image_png.h" #include "lib/internet.h" #include "lib/job.h" #include "lib/job_manager.h" diff --git a/test/image_test.cc b/test/image_test.cc index 7369bd24f..18d96d4fc 100644 --- a/test/image_test.cc +++ b/test/image_test.cc @@ -30,6 +30,7 @@ #include "lib/image.h" #include "lib/image_content.h" #include "lib/image_decoder.h" +#include "lib/image_png.h" #include "lib/ffmpeg_image_proxy.h" #include "test.h" #include @@ -375,8 +376,8 @@ BOOST_AUTO_TEST_CASE (as_png_test) auto proxy = make_shared("test/data/3d_test/000001.png"); auto image_rgb = proxy->image(Image::Alignment::PADDED).image; auto image_bgr = image_rgb->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_BGRA, Image::Alignment::PADDED, false); - image_rgb->as_png().write ("build/test/as_png_rgb.png"); - image_bgr->as_png().write ("build/test/as_png_bgr.png"); + image_as_png(image_rgb).write ("build/test/as_png_rgb.png"); + image_as_png(image_bgr).write ("build/test/as_png_bgr.png"); check_image ("test/data/3d_test/000001.png", "build/test/as_png_rgb.png"); check_image ("test/data/3d_test/000001.png", "build/test/as_png_bgr.png"); @@ -391,7 +392,7 @@ fade_test_format_black (AVPixelFormat f, string name) yuv.make_black (); yuv.fade (0); string const filename = "fade_test_black_" + name + ".png"; - yuv.convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png().write("build/test/" + filename); + image_as_png(yuv.convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)).write("build/test/" + filename); check_image ("test/data/" + filename, "build/test/" + filename); } @@ -404,7 +405,7 @@ fade_test_format_red (AVPixelFormat f, float amount, string name) auto red = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, f, Image::Alignment::PADDED, false); red->fade (amount); string const filename = "fade_test_red_" + name + ".png"; - red->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png().write("build/test/" + filename); + image_as_png(red->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)).write("build/test/" + filename); check_image ("test/data/" + filename, "build/test/" + filename); } diff --git a/test/test.cc b/test/test.cc index a12d79916..6b2e584a2 100644 --- a/test/test.cc +++ b/test/test.cc @@ -699,7 +699,7 @@ png_flush (png_structp) static void -png_error_fn (png_structp png_ptr, char const * message) +png_error_fn (png_structp, char const * message) { throw EncodeError (String::compose("Error during PNG write: %1", message)); } -- 2.30.2