blob: e0a118b3cfca9082376133b6b16d86042c94640d [file] [log] [blame]
#define LOG_TAG "ImageIo"
#include <private/dvr/image_io_png.h>
#include <fstream>
#include <string>
#include <vector>
#include <private/dvr/image_io_logging.h>
#include "png.h"
namespace {
void WriteChunkCallback(png_structp out_ptr, png_bytep chunk_ptr,
png_size_t chunk_size) {
auto* writer = static_cast<ImageIoPngWriter*>(png_get_io_ptr(out_ptr));
const char* chunk = reinterpret_cast<const char*>(chunk_ptr);
writer->WriteChunk(chunk, chunk_size);
}
} // namespace
ImageIoPngWriter::ImageIoPngWriter(const char* filename, int width, int height,
const uint8_t* image)
: ImageIoWriter(filename, width, height, image),
out_(filename_),
write_failed_(false) {}
bool ImageIoPngWriter::WriteChunk(const char* chunk, int chunk_size) {
out_.write(chunk, chunk_size);
if (!out_) {
if (write_failed_) {
// Error was already logged once.
return false;
}
ALOGE("Failed to write .png image to %s.", filename_.c_str());
write_failed_ = true;
return false;
}
return true;
}
// Writes RGB888 image to png file.
// Refactored from Chromium:
// WebKit/Source/platform/image-encoders/skia/PNGImageEncoder.cpp
bool ImageIoPngWriter::WriteRgb888() {
if (width_ <= 0 || height_ <= 0) {
ALOGE("Invalid width or height.");
return false;
}
if (!out_) {
ALOGE("Failed to open output file %s.", filename_.c_str());
return false;
}
png_struct* png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
png_info* info = png_create_info_struct(png);
if (!png || !info || setjmp(png_jmpbuf(png))) {
png_destroy_write_struct(png ? &png : 0, info ? &info : 0);
return false;
}
png_set_compression_level(png, 3);
png_set_filter(png, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
png_set_write_fn(png, this, WriteChunkCallback, 0);
png_set_IHDR(png, info, width_, height_, 8, PNG_COLOR_TYPE_RGB, 0, 0, 0);
png_write_info(png, info);
unsigned char* pixels =
reinterpret_cast<unsigned char*>(const_cast<uint8_t*>(image_));
const size_t stride = width_ * 3;
for (int y = 0; y < height_; ++y) {
png_write_row(png, pixels);
if (write_failed_)
return false;
pixels += stride;
}
png_write_end(png, info);
png_destroy_write_struct(&png, &info);
return !write_failed_;
}