/****************************************************************************
image.c - a simple image manipulation library. Distributed with Xplanet.
Copyright (C) 2002 Hari Nair <hari@alumni.caltech.edu>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
****************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "checkfuncs.h"
int
read_bmp(const char *filename, int *width, int *height, unsigned char *rgb);
int
write_bmp(const char *filename, int width, int height, unsigned char *rgb);
#ifdef HAVE_LIBGIF
int
read_gif(const char *filename, int *width, int *height, unsigned char *rgb);
int
write_gif(const char *filename, int width, int height, unsigned char *rgb);
#endif
#ifdef HAVE_LIBJPEG
int
read_jpeg(const char *filename, int *width, int *height, unsigned char *rgb);
int
write_jpeg(FILE *outfile, int width, int height, unsigned char *rgb,
int quality);
#endif
#ifdef HAVE_LIBPNG
int
read_png(const char *filename, int *width, int *height, unsigned char *rgb);
int
write_png(FILE *outfile, int width, int height, unsigned char *rgb,
unsigned char *alpha);
#endif
#ifdef HAVE_LIBPNM
#include <pnm.h>
int
read_pnm(const char *filename, int *width, int *height, unsigned char *rgb);
int
write_pnm(FILE *outfile, int width, int height, unsigned char *rgb,
int maxv, int format, int forceplain);
#endif
#ifdef HAVE_LIBTIFF
int
read_tiff(const char *filename, int *width, int *height, unsigned char *rgb);
int
write_tiff(const char *filename, int width, int height, unsigned char *rgb);
#endif
static unsigned char *alpha; /* PNG alpha (opacity) channel */
static int Q; /* JPEG Quality */
void
set_alpha(unsigned char *A)
{
alpha = A;
}
void
set_quality(int q)
{
Q = q;
}
int
read_image(const char *filename, int *width, int *height,
unsigned char *rgb)
{
char buf[4];
unsigned char *ubuf = (unsigned char *) buf;
int success = 0;
FILE *file;
file = fopen(filename, "rb");
if (file == NULL) return(0);
/* see what kind of file we have */
fread(buf, 1, 4, file);
fclose(file);
if (!strncmp("BM", buf, 2))
{
success = read_bmp(filename, width, height, rgb);
}
else if (!strncmp("GIF8", buf, 4))
{
#ifdef HAVE_LIBGIF
success = read_gif(filename, width, height, rgb);
#else
fprintf(stderr,
"Sorry, this program was not compiled with GIF support\n");
success = 0;
#endif /* HAVE_LIBGIF */
}
else if ((ubuf[0] == 0xff) && (ubuf[1] == 0xd8))
{
#ifdef HAVE_LIBJPEG
success = read_jpeg(filename, width, height, rgb);
#else
fprintf(stderr,
"Sorry, this program was not compiled with JPEG support\n");
success = 0;
#endif /* HAVE_LIBJPEG */
}
else if ((ubuf[0] == 0x89) && !strncmp("PNG", buf+1, 3))
{
#ifdef HAVE_LIBPNG
success = read_png(filename, width, height, rgb);
#else
fprintf(stderr,
"Sorry, this program was not compiled with PNG support\n");
success = 0;
#endif /* HAVE_LIBPNG */
}
else if (( !strncmp("P6\n", buf, 3))
|| (!strncmp("P5\n", buf, 3))
|| (!strncmp("P4\n", buf, 3))
|| (!strncmp("P3\n", buf, 3))
|| (!strncmp("P2\n", buf, 3))
|| (!strncmp("P1\n", buf, 3)))
{
#ifdef HAVE_LIBPNM
success = read_pnm(filename, width, height, rgb);
#else
fprintf(stderr,
"Sorry, this program was not compiled with PNM support\n");
success = 0;
#endif /* HAVE_LIBPNM */
}
else if (((!strncmp ("MM", buf, 2)) && (ubuf[2] == 0x00)
&& (ubuf[3] == 0x2a))
|| ((!strncmp ("II", buf, 2)) && (ubuf[2] == 0x2a)
&& (ubuf[3] == 0x00)))
{
#ifdef HAVE_LIBTIFF
success = read_tiff(filename, width, height, rgb);
#else
fprintf(stderr,
"Sorry, this program was not compiled with TIFF support\n");
success = 0;
#endif
}
else
{
fprintf(stderr, "Unknown image format\n");
success = 0;
}
return(success);
}
int
write_image(const char *filename, int width, int height, unsigned char *rgb)
{
FILE *outfile;
char *extension = strrchr(filename, '.');
char *lowercase;
char *ptr;
int success = 0;
lowercase = malloc(strlen(extension) + 1);
strcpy(lowercase, extension);
ptr = lowercase;
while (*ptr != '\0') *ptr++ = tolower(*extension++);
outfile = fopen(filename, "wb");
if (outfile == NULL) return(0);
if (strcmp(lowercase, ".bmp" ) == 0)
{
success = write_bmp(filename, width, height, rgb);
}
else if (strcmp(lowercase, ".gif" ) == 0)
{
#ifdef HAVE_LIBGIF
success = write_gif(filename, width, height, rgb);
#else
fprintf(stderr,
"Sorry, this program was not compiled with GIF support\n");
success = 0;
#endif /* HAVE_LIBPNG */
}
else if (( strcmp(lowercase, ".jpg" ) == 0)
|| (strcmp(lowercase, ".jpeg") == 0))
{
#ifdef HAVE_LIBJPEG
success = write_jpeg(outfile, width, height, rgb, Q);
#else
fprintf(stderr,
"Sorry, this program was not compiled with JPEG support\n");
success = 0;
#endif /* HAVE_LIBJPEG */
}
else if (strcmp(lowercase, ".png" ) == 0)
{
#ifdef HAVE_LIBPNG
success = write_png(outfile, width, height, rgb, alpha);
#else
fprintf(stderr,
"Sorry, this program was not compiled with PNG support\n");
success = 0;
#endif /* HAVE_LIBPNG */
}
else if (( strcmp(lowercase, ".pbm") == 0)
|| (strcmp(lowercase, ".pgm") == 0)
|| (strcmp(lowercase, ".ppm") == 0))
{
#ifdef HAVE_LIBPNM
if (strcmp(lowercase, ".pbm") == 0)
success = write_pnm(outfile, width, height, rgb, 1, PBM_TYPE, 0);
else if (strcmp(lowercase, ".pgm") == 0)
success = write_pnm(outfile, width, height, rgb, 255,
PGM_TYPE, 0);
else if (strcmp(lowercase, ".ppm") == 0)
success = write_pnm(outfile, width, height, rgb, 255,
PPM_TYPE, 0);
#else
fprintf(stderr,
"Sorry, this program was not compiled with PNM support\n");
success = 0;
#endif /* HAVE_LIBPNM */
}
else if ((strcmp(lowercase, ".tif" ) == 0)
|| (strcmp(lowercase, ".tiff" ) == 0))
{
#ifdef HAVE_LIBTIFF
success = write_tiff(filename, width, height, rgb);
#else
fprintf(stderr,
"Sorry, this program was not compiled with TIFF support\n");
success = 0;
#endif /* HAVE_LIBTIFF */
}
else
{
fprintf(stderr, "Unknown image format\n");
success = 0;
}
free(lowercase);
fclose(outfile);
return(success);
}
/* Write an image to memory in PNG format--returned as a pointer and a size from this routine */
/* D. Hunt 9/9/09 at 8:54am */
int
write_png_mem(char **img_ptr, size_t *img_size, int width, int height, unsigned char *rgb)
{
FILE *out;
int success = 0;
out = open_memstream(img_ptr, img_size);
if (out == NULL) return (0);
success = write_png(out, width, height, rgb, alpha);
fclose(out);
return(success);
}
int
delete_image(unsigned char **rgb)
{
free(rgb[0]);
rgb[0] = NULL;
return(1);
}
int
crop_image(unsigned char *rgb, int in_width, int in_height, unsigned char *outrgb, int x, int y,
int width, int height)
{
int i, j;
int ipos = 0;
for (j = 0; j < height; j++)
for (i = 0; i < width; i++)
{
memcpy(outrgb + ipos,
rgb + 3 * ((j + y) * in_width + (i + x)), 3);
ipos += 3;
}
return(1);
}
int
resize_image(unsigned char *rgb, int in_width, int in_height,
unsigned char *outrgb, int out_width, int out_height, int bilinear)
{
int i, j, ii, jj;
double dx, dy;
double t, u;
int in_pos[4], out_pos;
int sum;
double weight[4];
int ix[4], iy[4];
double frac_h = ((double) in_height - 1) / (out_height - 1);
double frac_w = ((double) in_width - 1) / (out_width - 1);
if (in_width == out_width && in_height == out_height) return(1);
if (bilinear)
{
for (j = 0; j < out_height; j++)
{
dy = ((double) j / (out_height - 1)) * (in_height - 1);
iy[0] = iy[1] = (int) dy;
iy[2] = iy[0] + 1;
if (iy[2] == in_height) iy[2]--;
iy[3] = iy[2];
u = 1 - (dy - iy[0]);
for (i = 0; i < out_width; i++)
{
dx = ((double) i / (out_width - 1)) * (in_width - 1);
ix[0] = ix[2] = (int) dx;
ix[1] = ix[0] + 1;
if (ix[1] == in_width) ix[1] = 0;
ix[3] = ix[1];
t = dx - ix[0];
if (t > in_width/2)
t -= in_width;
else if (t < -in_width/2)
t += in_width;
/*
Weights are from Numerical Recipes, 2nd Edition
weight[0] = (1 - t) * u;
weight[1] = t * u;
weight[2] = (1-t) * (1-u);
weight[3] = t * (1-u);
*/
weight[1] = t * u;
weight[0] = u - weight[1];
weight[2] = 1 - t - u + weight[1];
weight[3] = t - weight[1];
for (jj = 0; jj < 4; jj++)
in_pos[jj] = 3 * (iy[jj] * in_width + ix[jj]);
out_pos = 3 * (j * out_width + i);
for (ii = 0; ii < 3; ii++)
{
sum = 0;
for (jj = 0; jj < 4; jj++)
sum += (int) (weight[jj] * rgb[in_pos[jj] + ii]);
outrgb[out_pos + ii] = (unsigned char) (sum & 0xff);
}
}
}
}
else
{
out_pos = 0;
for (j = 0; j < out_height; j++)
{
dy = j * frac_h;
iy[0] = (int) dy;
for (i = 0; i < out_width; i++)
{
dx = i * frac_w;
ix[0] = (int) dx;
in_pos[0] = 3 * (iy[0] * in_width + ix[0]);
memcpy(outrgb + out_pos, rgb + in_pos[0], 3);
out_pos += 3;
}
}
}
return(1);
}