forked from mia/Aegisub
240 lines
6.5 KiB
C
240 lines
6.5 KiB
C
/*****************************************************************************
|
|
* 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 <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
|
|
#include <csri/csri.h>
|
|
#include <csri/logging.h>
|
|
|
|
#include "render.h"
|
|
|
|
extern csri_rend *r;
|
|
|
|
#ifdef HAVE_LIBPNG
|
|
#include <png.h>
|
|
|
|
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]);
|
|
}
|