Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 

154 строки
4.8 KiB

  1. /*
  2. * aptdec - A lightweight FOSS (NOAA) APT decoder
  3. * Copyright (C) 2004-2009 Thierry Leconte (F4DWV) 2019-2023 Xerbo (xerbo@protonmail.com)
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. #include "pngio.h"
  19. #include <png.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "util.h"
  23. writer_t *writer_init(const char *filename, aptdec_region_t region, uint32_t height, int color, char *channel) {
  24. writer_t *png = calloc(1, sizeof(writer_t));
  25. png->region = region;
  26. // Create writer
  27. png->png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  28. if (!png->png) {
  29. error_noexit("Could not create PNG write struct");
  30. return NULL;
  31. }
  32. png->info = png_create_info_struct(png->png);
  33. if (!png->info) {
  34. error_noexit("Could not create PNG info struct");
  35. return NULL;
  36. }
  37. png_set_IHDR(png->png, png->info, png->region.width, height, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  38. char version[128] = { 0 };
  39. int version_len = get_version(version);
  40. png_text text[] = {
  41. {PNG_TEXT_COMPRESSION_NONE, "Software", version, version_len},
  42. {PNG_TEXT_COMPRESSION_NONE, "Channel", channel, strlen(channel)}
  43. };
  44. png_set_text(png->png, png->info, text, 2);
  45. png->file = fopen(filename, "wb");
  46. if (!png->file) {
  47. error_noexit("Could not open PNG file");
  48. return NULL;
  49. }
  50. png_init_io(png->png, png->file);
  51. png_write_info(png->png, png->info);
  52. printf("Writing %s...\n", filename);
  53. return png;
  54. }
  55. void writer_write_image(writer_t *png, const aptdec_image_t *img) {
  56. for (size_t y = 0; y < img->rows; y++) {
  57. png_write_row(png->png, &img->data[y*APTDEC_IMG_WIDTH + png->region.offset]);
  58. }
  59. }
  60. void writer_write_image_gradient(writer_t *png, const aptdec_image_t *img, const uint32_t *gradient) {
  61. for (size_t y = 0; y < img->rows; y++) {
  62. png_color pixels[APTDEC_IMG_WIDTH];
  63. for (size_t x = 0; x < APTDEC_IMG_WIDTH; x++) {
  64. aptdec_rgb_t pixel = aptdec_gradient(gradient, img->data[y*APTDEC_IMG_WIDTH + x + png->region.offset]);
  65. pixels[x] = (png_color){ pixel.r, pixel.g, pixel.b };
  66. }
  67. png_write_row(png->png, (png_bytep)pixels);
  68. }
  69. }
  70. void writer_write_image_lut(writer_t *png, const aptdec_image_t *img, const png_colorp lut) {
  71. for (size_t y = 0; y < img->rows; y++) {
  72. png_color pixels[APTDEC_CH_WIDTH];
  73. for (size_t x = 0; x < APTDEC_CH_WIDTH; x++) {
  74. uint8_t a = img->data[y*APTDEC_IMG_WIDTH + x + APTDEC_CHA_OFFSET];
  75. uint8_t b = img->data[y*APTDEC_IMG_WIDTH + x + APTDEC_CHB_OFFSET];
  76. pixels[x] = lut[b*256 + a];
  77. }
  78. png_write_row(png->png, (png_bytep)pixels);
  79. }
  80. }
  81. void writer_free(writer_t *png) {
  82. png_write_end(png->png, png->info);
  83. png_destroy_write_struct(&png->png, &png->info);
  84. fclose(png->file);
  85. free(png);
  86. }
  87. int read_lut(const char *filename, png_colorp out) {
  88. png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  89. if (!png) {
  90. error_noexit("Could not create PNG read struct");
  91. return 0;
  92. }
  93. png_infop info = png_create_info_struct(png);
  94. if (!info) {
  95. error_noexit("Could not create PNG info struct");
  96. return 0;
  97. }
  98. FILE *file = fopen(filename, "rb");
  99. if (!file) {
  100. error_noexit("Cannot open LUT");
  101. return 0;
  102. }
  103. png_init_io(png, file);
  104. // Read metadata
  105. png_read_info(png, info);
  106. uint32_t width = png_get_image_width(png, info);
  107. uint32_t height = png_get_image_height(png, info);
  108. png_byte color_type = png_get_color_type(png, info);
  109. png_byte bit_depth = png_get_bit_depth(png, info);
  110. if (width != 256 && height != 256) {
  111. error_noexit("LUT must be 256x256");
  112. return 0;
  113. }
  114. if (bit_depth != 8) {
  115. error_noexit("LUT must be 8 bit");
  116. return 0;
  117. }
  118. if (color_type != PNG_COLOR_TYPE_RGB) {
  119. error_noexit("LUT must be RGB");
  120. return 0;
  121. }
  122. for (uint32_t i = 0; i < height; i++) {
  123. png_read_row(png, (png_bytep)&out[i*width], NULL);
  124. }
  125. png_read_end(png, info);
  126. png_destroy_read_struct(&png, &info, NULL);
  127. fclose(file);
  128. return 1;
  129. }