/***************************************************************************** * asa: portable digital subtitle renderer ***************************************************************************** * Copyright (C) 2007 David Lamparter * * 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "acconf.h" #endif #include #include #include #include #include #include #include #include #include "render.h" extern csri_rend *r; #ifdef HAVE_LIBPNG #include struct csri_frame *png_load(const char *filename, uint32_t *width, uint32_t *height, enum csri_pixfmt fmt) { struct csri_frame *frame; int bit_depth, color_type; png_structp png_ptr; png_infop info_ptr; png_bytep *rows; unsigned char *imgdata; FILE *fp; if (!csri_is_rgb(fmt)) { fprintf(stderr, "PNG loader: can't load non-RGB.\n"); return NULL; } frame = (struct csri_frame *)malloc(sizeof(struct csri_frame)); if (!frame) return NULL; memset(frame, 0, sizeof(*frame)); frame->pixfmt = fmt; fp = fopen(filename, "rb"); if (!fp) { fprintf(stderr, "Error opening \"%s\": %s (%d)\n", filename, strerror(errno), errno); return NULL; } assert(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)); assert(info_ptr = png_create_info_struct(png_ptr)); //keepalpha ? CSRI_F_RGBA : CSRI_F_RGB_; png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)width, (png_uint_32 *)height, &bit_depth, &color_type, NULL, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if ((fmt < 0x200 && (fmt & 2)) || fmt == CSRI_F_BGR) png_set_bgr(png_ptr); if (csri_has_alpha(fmt)) { int before = fmt == CSRI_F_ARGB || fmt == CSRI_F_ABGR; if (color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xff, before ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); else { png_set_invert_alpha(png_ptr); if (before) png_set_swap_alpha(png_ptr); } } else { if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); if (fmt != CSRI_F_RGB && fmt != CSRI_F_BGR) { int before = fmt == CSRI_F__RGB || fmt == CSRI_F__BGR; png_set_filler(png_ptr, 0xff, before ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); } } rows = (png_bytep *)malloc(sizeof(png_bytep) * *height); assert(rows); imgdata = (unsigned char *)malloc(4 * *height * *width); assert(imgdata); for (uint32_t y = 0; y < *height; y++) rows[y] = imgdata + 4 * *width * y; png_read_image(png_ptr, rows); png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(rows); frame->planes[0] = imgdata; frame->strides[0] = *width * 4; printf("\033[32;1mloaded %ux%u\033[m\n", *width, *height); return frame; } void png_store(struct csri_frame *frame, const char *filename, uint32_t width, uint32_t height) { enum csri_pixfmt fmt = frame->pixfmt; int xforms = 0, before = 0, after = 0; png_structp png_ptr; png_infop info_ptr; png_bytep *rows; FILE *fp; fp = fopen(filename, "wb"); if (!fp) { fprintf(stderr, "Error opening \"%s\": %s (%d)\n", filename, strerror(errno), errno); return; } rows = (png_bytep *)malloc(sizeof(png_bytep) * height); assert(rows); after = fmt == CSRI_F_RGB_ || fmt == CSRI_F_BGR_; before = fmt == CSRI_F__RGB || fmt == CSRI_F__BGR; for (uint32_t y = 0; y < height; y++) { rows[y] = frame->planes[0] + frame->strides[0] * y; if (before || after) { unsigned char *d = rows[y], *s = rows[y], *e = d + frame->strides[0]; if (before) s++; while (d < e) { *d++ = *s++; *d++ = *s++; *d++ = *s++; s++; } } } assert(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)); assert(info_ptr = png_create_info_struct(png_ptr)); png_init_io(png_ptr, fp); if (csri_has_alpha(fmt) && (fmt == CSRI_F_ARGB || fmt == CSRI_F_ABGR)) xforms |= PNG_TRANSFORM_SWAP_ALPHA; if ((fmt < 0x200 && (fmt & 2)) || fmt == CSRI_F_BGR) xforms |= PNG_TRANSFORM_BGR; png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); png_set_IHDR(png_ptr, info_ptr, width, height, 8, csri_has_alpha(fmt) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_rows(png_ptr, info_ptr, rows); png_write_png(png_ptr, info_ptr, xforms, NULL); fflush(fp); png_destroy_write_struct(&png_ptr, &info_ptr); } #else struct csri_frame *png_load(const char *filename, uint32_t *width, uint32_t *height, enum csri_pixfmt fmt) { fprintf(stderr, "PNG support not compiled in.\n"); return NULL; } void png_store(struct csri_frame *frame, const char *filename, uint32_t width, uint32_t height) { fprintf(stderr, "PNG support not compiled in.\n"); return; } #endif struct csri_frame *frame_alloc(uint32_t width, uint32_t height, enum csri_pixfmt fmt) { int bpp; unsigned char *d; struct csri_frame *frame; if (!csri_is_rgb(fmt)) return NULL; bpp = fmt < CSRI_F_RGB ? 4 : 3; d = (unsigned char *)malloc(width * height * bpp); frame = (struct csri_frame *)malloc(sizeof(struct csri_frame)); if (!frame || !d) return NULL; memset(frame, 0, sizeof(*frame)); frame->pixfmt = fmt; frame->strides[0] = width * bpp; memset(d, csri_has_alpha(fmt) ? 0x00 : 0x80, width * height * bpp); frame->planes[0] = d; return frame; } void frame_free(struct csri_frame *frame) { int c; for (c = 0; c < 4; c++) if (frame->planes[c]) free(frame->planes[c]); free(frame); } void frame_copy(struct csri_frame *dst, struct csri_frame *src, uint32_t width, uint32_t height) { memcpy(dst->planes[0], src->planes[0], height * src->strides[0]); }