|
Packit Service |
df60bb |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
df60bb |
#include "config.h"
|
|
Packit Service |
df60bb |
#endif
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Bring in standard I/O and string manipulation functions */
|
|
Packit Service |
df60bb |
#include <stdarg.h>
|
|
Packit Service |
df60bb |
#ifdef HAVE_ERRNO_H
|
|
Packit Service |
df60bb |
#include <errno.h>
|
|
Packit Service |
df60bb |
#endif
|
|
Packit Service |
df60bb |
#include <stdio.h>
|
|
Packit Service |
df60bb |
#ifdef HAVE_STDLIB_H
|
|
Packit Service |
df60bb |
#include <stdlib.h>
|
|
Packit Service |
df60bb |
#endif
|
|
Packit Service |
df60bb |
#ifdef HAVE_STRING_H
|
|
Packit Service |
df60bb |
#include <string.h>
|
|
Packit Service |
df60bb |
#endif
|
|
Packit Service |
df60bb |
#ifdef HAVE_UNISTD_H
|
|
Packit Service |
df60bb |
#include <unistd.h>
|
|
Packit Service |
df60bb |
#endif
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#ifdef __clang__
|
|
Packit Service |
df60bb |
/* Workaround broken clang behavior: https://llvm.org/bugs/show_bug.cgi?id=20144 */
|
|
Packit Service |
df60bb |
#undef strcmp
|
|
Packit Service |
df60bb |
#endif
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Bring in the gd library functions */
|
|
Packit Service |
df60bb |
#include "gd.h"
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#define KEEP_TRANS (-100)
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static const char argv0[] = "webpng";
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static void usage(const char *msg)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
/* If the command failed, output an explanation. */
|
|
Packit Service |
df60bb |
fprintf(msg == NULL ? stdout : stderr,
|
|
Packit Service |
df60bb |
"Usage: %s [-i y|n] [-l] [-t index|none] [-d] [-a] pngname.png\n"
|
|
Packit Service |
df60bb |
" -i <y|n> Turns on/off interlace\n"
|
|
Packit Service |
df60bb |
" -l Prints the table of color indexes\n"
|
|
Packit Service |
df60bb |
" -t <index> Set the transparent color to the specified index (0-255 or \"none\")\n"
|
|
Packit Service |
df60bb |
" -d Reports the dimensions and other characteristics of the image\n"
|
|
Packit Service |
df60bb |
" -a Prints all alpha channels that are not 100%% opaque\n"
|
|
Packit Service |
df60bb |
"\n"
|
|
Packit Service |
df60bb |
"If you specify '-' as the input file, stdin/stdout will be used as input/output.\n",
|
|
Packit Service |
df60bb |
argv0);
|
|
Packit Service |
df60bb |
if (msg)
|
|
Packit Service |
df60bb |
fprintf(stderr, "\nError: %s\n", msg);
|
|
Packit Service |
df60bb |
exit(msg == NULL ? 0 : 1);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static void err(const char *fmt, ...)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
va_list ap;
|
|
Packit Service |
df60bb |
int e = errno;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
fprintf(stderr, "%s: error: ", argv0);
|
|
Packit Service |
df60bb |
va_start(ap, fmt);
|
|
Packit Service |
df60bb |
vfprintf(stderr, fmt, ap);
|
|
Packit Service |
df60bb |
va_end(ap);
|
|
Packit Service |
df60bb |
if (e)
|
|
Packit Service |
df60bb |
fprintf(stderr, ": %s", strerror(e));
|
|
Packit Service |
df60bb |
fputs("\n", stderr);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
exit(1);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
int
|
|
Packit Service |
df60bb |
main(int argc, char **argv)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
FILE *in;
|
|
Packit Service |
df60bb |
FILE *out;
|
|
Packit Service |
df60bb |
const char *infile;
|
|
Packit Service |
df60bb |
char *tmpfile;
|
|
Packit Service |
df60bb |
int i;
|
|
Packit Service |
df60bb |
int use_stdin_stdout = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
int interlace = -100;
|
|
Packit Service |
df60bb |
int list_color_table = 0;
|
|
Packit Service |
df60bb |
int trans_col = KEEP_TRANS;
|
|
Packit Service |
df60bb |
int report_details = 0;
|
|
Packit Service |
df60bb |
int print_alpha = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Declare our image pointer */
|
|
Packit Service |
df60bb |
gdImagePtr im = 0;
|
|
Packit Service |
df60bb |
/* We'll set 'write' once we know the user's request
|
|
Packit Service |
df60bb |
requires that the image be written back to disk. */
|
|
Packit Service |
df60bb |
int write = 0;
|
|
Packit Service |
df60bb |
int got_a_flag = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Consider each argument in turn. */
|
|
Packit Service |
df60bb |
opterr = 0;
|
|
Packit Service |
df60bb |
while ((i = getopt(argc, argv, "i:lt:da")) != -1) {
|
|
Packit Service |
df60bb |
got_a_flag = 1;
|
|
Packit Service |
df60bb |
switch (i) {
|
|
Packit Service |
df60bb |
case 'i':
|
|
Packit Service |
df60bb |
/* -i turns on and off interlacing. */
|
|
Packit Service |
df60bb |
if (strcmp(optarg, "y") == 0)
|
|
Packit Service |
df60bb |
interlace = 1;
|
|
Packit Service |
df60bb |
else if (strcmp(optarg, "n") == 0)
|
|
Packit Service |
df60bb |
interlace = 0;
|
|
Packit Service |
df60bb |
else
|
|
Packit Service |
df60bb |
usage("-i specified without y or n");
|
|
Packit Service |
df60bb |
write = 1;
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case 'l':
|
|
Packit Service |
df60bb |
/* List the colors in the color table. */
|
|
Packit Service |
df60bb |
list_color_table = 1;
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case 't':
|
|
Packit Service |
df60bb |
/* Set transparent index (or none). */
|
|
Packit Service |
df60bb |
if (strcmp(optarg, "none") == 0) {
|
|
Packit Service |
df60bb |
/* -1 means not transparent. */
|
|
Packit Service |
df60bb |
trans_col = -1;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
/* XXX: Should check for errors. */
|
|
Packit Service |
df60bb |
trans_col = atoi(optarg);
|
|
Packit Service |
df60bb |
if (trans_col < 0 || trans_col > 255)
|
|
Packit Service |
df60bb |
err("-t has to be in the range of 0 and 255 (inclusive)");
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
write = 1;
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case 'd':
|
|
Packit Service |
df60bb |
/* Output dimensions, etc. */
|
|
Packit Service |
df60bb |
report_details = 1;
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case 'a':
|
|
Packit Service |
df60bb |
/* Alpha channel info -- thanks to Wez Furlong */
|
|
Packit Service |
df60bb |
print_alpha = 1;
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case 'h':
|
|
Packit Service |
df60bb |
usage(NULL);
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
default:
|
|
Packit Service |
df60bb |
case '?':
|
|
Packit Service |
df60bb |
if (optind < argc && strcmp(argv[optind], "--help") == 0)
|
|
Packit Service |
df60bb |
usage(NULL);
|
|
Packit Service |
df60bb |
usage("unknown option");
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (got_a_flag == 0)
|
|
Packit Service |
df60bb |
usage("missing operation flag");
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (argc == optind)
|
|
Packit Service |
df60bb |
usage("missing filename");
|
|
Packit Service |
df60bb |
else if (argc != optind + 1)
|
|
Packit Service |
df60bb |
usage("can only specify one file");
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
infile = argv[optind];
|
|
Packit Service |
df60bb |
if (strcmp(infile, "-") == 0) {
|
|
Packit Service |
df60bb |
/* - is synonymous with STDIN */
|
|
Packit Service |
df60bb |
use_stdin_stdout = 1;
|
|
Packit Service |
df60bb |
in = stdin;
|
|
Packit Service |
df60bb |
} else
|
|
Packit Service |
df60bb |
in = fopen(infile, "rb");
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!in)
|
|
Packit Service |
df60bb |
err("can't open file %s", infile);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Now load the image. */
|
|
Packit Service |
df60bb |
im = gdImageCreateFromPng(in);
|
|
Packit Service |
df60bb |
fclose(in);
|
|
Packit Service |
df60bb |
/* If the load failed, it must not be a PNG file. */
|
|
Packit Service |
df60bb |
if (!im)
|
|
Packit Service |
df60bb |
err("%s is not a valid PNG file", infile);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (list_color_table) {
|
|
Packit Service |
df60bb |
/* List the colors in the color table. */
|
|
Packit Service |
df60bb |
if (!im->trueColor) {
|
|
Packit Service |
df60bb |
int j;
|
|
Packit Service |
df60bb |
/* Tabs used below. */
|
|
Packit Service |
df60bb |
printf("Index Red Green Blue Alpha\n");
|
|
Packit Service |
df60bb |
for (j = 0; j < gdImageColorsTotal(im); ++j) {
|
|
Packit Service |
df60bb |
/* Use access macros to learn colors. */
|
|
Packit Service |
df60bb |
printf("%d %d %d %d %d\n", j,
|
|
Packit Service |
df60bb |
gdImageRed(im, j),
|
|
Packit Service |
df60bb |
gdImageGreen(im, j),
|
|
Packit Service |
df60bb |
gdImageBlue(im, j),
|
|
Packit Service |
df60bb |
gdImageAlpha(im, j));
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else
|
|
Packit Service |
df60bb |
printf("Truecolor image, no palette entries to list.\n");
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (report_details) {
|
|
Packit Service |
df60bb |
/* Output dimensions, etc. */
|
|
Packit Service |
df60bb |
int t;
|
|
Packit Service |
df60bb |
printf("Width: %d Height: %d Colors: %d\n",
|
|
Packit Service |
df60bb |
gdImageSX(im),
|
|
Packit Service |
df60bb |
gdImageSY(im),
|
|
Packit Service |
df60bb |
gdImageColorsTotal(im));
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* -1 means the image is not transparent. */
|
|
Packit Service |
df60bb |
t = gdImageGetTransparent(im);
|
|
Packit Service |
df60bb |
if (t != -1)
|
|
Packit Service |
df60bb |
printf("First 100%% transparent index: %d\n", t);
|
|
Packit Service |
df60bb |
else
|
|
Packit Service |
df60bb |
printf("First 100%% transparent index: none\n");
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (gdImageGetInterlaced(im))
|
|
Packit Service |
df60bb |
printf("Interlaced: yes\n");
|
|
Packit Service |
df60bb |
else
|
|
Packit Service |
df60bb |
printf("Interlaced: no\n");
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (print_alpha) {
|
|
Packit Service |
df60bb |
/* Alpha channel info -- thanks to Wez Furlong */
|
|
Packit Service |
df60bb |
int maxx, maxy, x, y, alpha, pix, nalpha = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
maxx = gdImageSX(im);
|
|
Packit Service |
df60bb |
maxy = gdImageSY(im);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
printf("alpha channel information:\n");
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (im->trueColor) {
|
|
Packit Service |
df60bb |
for (y = 0; y < maxy; y++) {
|
|
Packit Service |
df60bb |
for (x = 0; x < maxx; x++) {
|
|
Packit Service |
df60bb |
pix = gdImageGetPixel(im, x, y);
|
|
Packit Service |
df60bb |
alpha = gdTrueColorGetAlpha(pix);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (alpha > gdAlphaOpaque) {
|
|
Packit Service |
df60bb |
/* Use access macros to learn colors. */
|
|
Packit Service |
df60bb |
printf("%d %d %d %d\n",
|
|
Packit Service |
df60bb |
gdTrueColorGetRed(pix),
|
|
Packit Service |
df60bb |
gdTrueColorGetGreen(pix),
|
|
Packit Service |
df60bb |
gdTrueColorGetBlue(pix),
|
|
Packit Service |
df60bb |
alpha);
|
|
Packit Service |
df60bb |
nalpha++;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else
|
|
Packit Service |
df60bb |
printf("NOT a true color image\n");
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
printf("%d alpha channels\n", nalpha);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* If no modifications requested, break out. */
|
|
Packit Service |
df60bb |
if (write == 0) {
|
|
Packit Service |
df60bb |
gdImageDestroy(im);
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (interlace == 1)
|
|
Packit Service |
df60bb |
gdImageInterlace(im, 1);
|
|
Packit Service |
df60bb |
else if (interlace == 0)
|
|
Packit Service |
df60bb |
gdImageInterlace(im, 0);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (trans_col != KEEP_TRANS)
|
|
Packit Service |
df60bb |
gdImageColorTransparent(im, trans_col);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (use_stdin_stdout) {
|
|
Packit Service |
df60bb |
out = stdout;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
/* Open a temporary file. */
|
|
Packit Service |
df60bb |
size_t filelen = strlen(infile);
|
|
Packit Service |
df60bb |
size_t len = filelen + 8;
|
|
Packit Service |
df60bb |
int outfd;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
tmpfile = malloc(len);
|
|
Packit Service |
df60bb |
if (tmpfile == NULL)
|
|
Packit Service |
df60bb |
err("could not create a tempfile");
|
|
Packit Service |
df60bb |
memcpy(tmpfile, infile, filelen);
|
|
Packit Service |
df60bb |
strcpy(tmpfile + filelen, ".XXXXXX");
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
outfd = mkstemp(tmpfile);
|
|
Packit Service |
df60bb |
if (outfd == -1)
|
|
Packit Service |
df60bb |
err("could not open %s", tmpfile);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
out = fdopen(outfd, "wb");
|
|
Packit Service |
df60bb |
if (!out)
|
|
Packit Service |
df60bb |
err("could not open %s", tmpfile);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Write the new PNG. */
|
|
Packit Service |
df60bb |
gdImagePng(im, out);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!use_stdin_stdout) {
|
|
Packit Service |
df60bb |
fclose(out);
|
|
Packit Service |
df60bb |
/* Erase the old PNG. */
|
|
Packit Service |
df60bb |
unlink(infile);
|
|
Packit Service |
df60bb |
/* Rename the new to the old. */
|
|
Packit Service |
df60bb |
if (rename(tmpfile, infile) != 0)
|
|
Packit Service |
df60bb |
err("unable to rename %s to %s", infile, tmpfile);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Delete the image from memory. */
|
|
Packit Service |
df60bb |
gdImageDestroy(im);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* All's well that ends well. */
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|