Load/save unknown chunks from/to png files (fix #2153)

This commit is contained in:
David Capello 2019-09-23 15:32:33 -03:00
parent de4a7454ce
commit a532f21ec4

View File

@ -15,6 +15,7 @@
#include "app/file/file_format.h"
#include "app/file/format_options.h"
#include "app/file/png_format.h"
#include "app/file/png_options.h"
#include "base/file_handle.h"
#include "doc/doc.h"
#include "gfx/color_space.h"
@ -24,6 +25,8 @@
#include "png.h"
#define PNG_TRACE(...) // TRACE
namespace app {
using namespace base;
@ -122,6 +125,32 @@ png_fixed_point png_ftofix(float x)
return x * 100000.0f;
}
int png_user_chunk(png_structp png, png_unknown_chunkp unknown)
{
auto data = (std::shared_ptr<PngOptions>*)png_get_user_chunk_ptr(png);
std::shared_ptr<PngOptions>& opts = *data;
PNG_TRACE("PNG: Read unknown chunk '%c%c%c%c'\n",
unknown->name[0],
unknown->name[1],
unknown->name[2],
unknown->name[3]);
PngOptions::Chunk chunk;
chunk.location = unknown->location;
for (int i=0; i<4; ++i)
chunk.name.push_back(unknown->name[i]);
if (unknown->size > 0) {
chunk.data.resize(unknown->size);
std::copy(unknown->data,
unknown->data+unknown->size,
chunk.data.begin());
}
opts->addChunk(std::move(chunk));
return 1;
}
} // anonymous namespace
bool PngFormat::onLoad(FileOp* fop)
@ -156,6 +185,10 @@ bool PngFormat::onLoad(FileOp* fop)
// See this thread: https://community.aseprite.org/t/2656
png_set_option(png, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
// Set a function to read user data chunks
auto opts = std::make_shared<PngOptions>();
png_set_read_user_chunk_fn(png, &opts, png_user_chunk);
/* Allocate/initialize the memory for image information. */
png_infop info = png_create_info_struct(png);
DestroyReadPng destroyer(png, info);
@ -409,6 +442,10 @@ bool PngFormat::onLoad(FileOp* fop)
fop->document()->notifyColorSpaceChanged();
}
ASSERT(opts != nullptr);
if (!opts->isEmpty())
fop->setLoadedFormatOptions(opts);
return true;
}
@ -543,6 +580,32 @@ bool PngFormat::onSave(FileOp* fop)
png_set_IHDR(png, info, width, height, 8, color_type,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
// User chunks
auto opts = fop->formatOptionsOfDocument<PngOptions>();
if (opts && !opts->isEmpty()) {
int num_unknowns = opts->size();
ASSERT(num_unknowns > 0);
std::vector<png_unknown_chunk> unknowns(num_unknowns);
int i = 0;
for (const auto& chunk : opts->chunks()) {
png_unknown_chunk& unknown = unknowns[i];
for (int i=0; i<5; ++i) {
unknown.name[i] =
(i < int(chunk.name.size()) ? chunk.name[i]: 0);
}
PNG_TRACE("PNG: Write unknown chunk '%c%c%c%c'\n",
unknown.name[0],
unknown.name[1],
unknown.name[2],
unknown.name[3]);
unknown.data = (png_byte*)&chunk.data[0];
unknown.size = chunk.data.size();
unknown.location = chunk.location;
++i;
}
png_set_unknown_chunks(png, info, &unknowns[0], num_unknowns);
}
if (fop->preserveColorProfile() &&
fop->document()->sprite()->colorSpace())
saveColorSpace(png, info, fop->document()->sprite()->colorSpace().get());