/*
* aptdec - A lightweight FOSS (NOAA) APT decoder
* Copyright (C) 2004-2009 Thierry Leconte (F4DWV) 2019-2023 Xerbo (xerbo@protonmail.com)
*
* This program 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.
*
* This program 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 this program. If not, see .
*/
#include "pngio.h"
#include
#include
#include
#include "util.h"
writer_t *writer_init(const char *filename, apt_region_t region, uint32_t height, int color, char *channel) {
writer_t *png = (writer_t *)malloc(sizeof(writer_t));
png->region = region;
// Create writer
png->png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png->png) {
error_noexit("Could not create PNG write struct");
return NULL;
}
png->info = png_create_info_struct(png->png);
if (!png->info) {
error_noexit("Could not create PNG info struct");
return NULL;
}
png_set_IHDR(png->png, png->info, png->region.width, height, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
char version[128];
int version_len = get_version(version);
png_text text[] = {
{PNG_TEXT_COMPRESSION_NONE, "Software", version, version_len},
{PNG_TEXT_COMPRESSION_NONE, "Channel", channel, strlen(channel)}
};
png_set_text(png->png, png->info, text, 2);
png->file = fopen(filename, "wb");
if (!png->file) {
error_noexit("Could not open PNG file");
return NULL;
}
png_init_io(png->png, png->file);
png_write_info(png->png, png->info);
printf("Writing %s...\n", filename);
return png;
}
void writer_write_image(writer_t *png, const apt_image_t *img) {
for (size_t y = 0; y < img->rows; y++) {
png_write_row(png->png, &img->data[y*APT_IMG_WIDTH + png->region.offset]);
}
}
void writer_write_image_gradient(writer_t *png, const apt_image_t *img, const uint32_t *gradient) {
for (size_t y = 0; y < img->rows; y++) {
png_color pixels[APT_IMG_WIDTH];
for (size_t x = 0; x < APT_IMG_WIDTH; x++) {
apt_rgb_t pixel = apt_gradient(gradient, img->data[y*APT_IMG_WIDTH + x + png->region.offset]);
pixels[x] = (png_color){ pixel.r, pixel.g, pixel.b };
}
png_write_row(png->png, (png_bytep)pixels);
}
}
void writer_write_image_lut(writer_t *png, const apt_image_t *img, const png_colorp lut) {
for (size_t y = 0; y < img->rows; y++) {
png_color pixels[APT_CH_WIDTH];
for (size_t x = 0; x < APT_CH_WIDTH; x++) {
uint8_t a = img->data[y*APT_IMG_WIDTH + x + APT_CHA_OFFSET];
uint8_t b = img->data[y*APT_IMG_WIDTH + x + APT_CHB_OFFSET];
pixels[x] = lut[b*256 + a];
}
png_write_row(png->png, (png_bytep)pixels);
}
}
void writer_free(writer_t *png) {
png_write_end(png->png, png->info);
png_destroy_write_struct(&png->png, &png->info);
fclose(png->file);
free(png);
}
int read_lut(const char *filename, png_colorp out) {
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
error_noexit("Could not create PNG read struct");
return 0;
}
png_infop info = png_create_info_struct(png);
if (!info) {
error_noexit("Could not create PNG info struct");
return 0;
}
FILE *file = fopen(filename, "rb");
if (!file) {
error_noexit("Cannot open LUT");
return 0;
}
png_init_io(png, file);
// Read metadata
png_read_info(png, info);
uint32_t width = png_get_image_width(png, info);
uint32_t height = png_get_image_height(png, info);
png_byte color_type = png_get_color_type(png, info);
png_byte bit_depth = png_get_bit_depth(png, info);
if (width != 256 && height != 256) {
error_noexit("LUT must be 256x256");
return 0;
}
if (bit_depth != 8) {
error_noexit("LUT must be 8 bit");
return 0;
}
if (color_type != PNG_COLOR_TYPE_RGB) {
error_noexit("LUT must be RGB");
return 0;
}
for (uint32_t i = 0; i < height; i++) {
png_read_row(png, (png_bytep)&out[i*width], NULL);
}
png_read_end(png, info);
png_destroy_read_struct(&png, &info, NULL);
fclose(file);
return 1;
}