/* * 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, aptdec_region_t region, uint32_t height, int color, char *channel) { writer_t *png = calloc(1, 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] = { 0 }; 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 aptdec_image_t *img) { for (size_t y = 0; y < img->rows; y++) { png_write_row(png->png, &img->data[y*APTDEC_IMG_WIDTH + png->region.offset]); } } void writer_write_image_gradient(writer_t *png, const aptdec_image_t *img, const uint32_t *gradient) { for (size_t y = 0; y < img->rows; y++) { png_color pixels[APTDEC_IMG_WIDTH]; for (size_t x = 0; x < APTDEC_IMG_WIDTH; x++) { aptdec_rgb_t pixel = aptdec_gradient(gradient, img->data[y*APTDEC_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 aptdec_image_t *img, const png_colorp lut) { for (size_t y = 0; y < img->rows; y++) { png_color pixels[APTDEC_CH_WIDTH]; for (size_t x = 0; x < APTDEC_CH_WIDTH; x++) { uint8_t a = img->data[y*APTDEC_IMG_WIDTH + x + APTDEC_CHA_OFFSET]; uint8_t b = img->data[y*APTDEC_IMG_WIDTH + x + APTDEC_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; }