Aegisub/csri/frontends/cmdline/render.c

241 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]);
}