tuxpaint-pencil-sharpener/src/postscript_print.c
William Kendrick 088ff3f60f Add margin to updated postscript_print code.
Add some missing credits for PS print support.
2009-01-29 20:51:37 +00:00

357 lines
8.9 KiB
C

/*
postscript_print.c
For Tux Paint
PostScript(r) printing routine.
(for non-Windows, non-Mac OS X, non-BeOS platforms, e.g. Linux)
(moved from tuxpaint.c in 0.9.17)
Copyright (c) 2009 by Bill Kendrick and others
bill@newbreedsoftware.com
http://www.tuxpaint.org/
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
(See COPYING.txt)
Based loosely on examination of NetPBM's "pnmtops" code and output:
copyright (c) 1989 by Jef Poskanzer.
License from "pnmtops.c":
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. This software is provided "as is" without express or
implied warranty.
June 24, 2007 - January 29, 2009
$Id$
*/
#include "postscript_print.h"
#ifdef PRINTMETHOD_PS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <paper.h>
#include <math.h>
#include <errno.h>
#ifndef PAPER_H
#error "---------------------------------------------------"
#error "If you installed libpaper from a package, be sure"
#error "to get the development package, as well!"
#error "(e.g., 'libpaper-dev.rpm')"
#error "---------------------------------------------------"
#endif
#include "pixels.h"
#define MARGIN 36 /* Margin to put around image, in points (inch/72) (36pt = 0.5") */
#define my_min(x,y) ((x < y) ? (x) : (y))
int f2int(float f);
int f2dec(float f);
int f2int(float f)
{
return ((int)f);
}
int f2dec(float f)
{
return (int)((f - f2int(f)) * 100);
}
/* Actually save the PostScript data to the file stream: */
int do_ps_save(FILE * fi,
// const char *restrict const fname,
const char * fname,
SDL_Surface * surf,
char * pprsize,
int is_pipe)
{
const struct paper * ppr;
int img_w = surf->w;
int img_h = surf->h;
int r_img_w, r_img_h;
int ppr_w, ppr_h;
int x, y;
float tlate_x, tlate_y;
int cur_line_len;
int plane;
Uint8 r, g, b;
char buf[256];
Uint32(*getpixel) (SDL_Surface *, int, int) =
getpixels[surf->format->BytesPerPixel];
int printed_img_w, printed_img_h;
time_t t = time(NULL);
int rotate;
float scale;
/* Determine paper size: */
paperinit(); // FIXME: Should we do this at startup? -bjk 2007.06.25
if (pprsize == NULL)
{
/* User did not request a specific paper size (on command-line or
in config file), ask the system. It will return either their
$PAPER env. var., the value from /etc/papersize, or NULL: */
pprsize = (char *) systempapername();
if (pprsize == NULL)
{
/* No setting, env. var. or /etc/ file; use the default! */
pprsize = (char *) defaultpapername();
#ifdef DEBUG
printf("Using default paper\n");
#endif
}
#ifdef DEBUG
else
{
printf("Using system paper\n");
}
#endif
}
#ifdef DEBUG
else
{
printf("Using user paper\n");
}
#endif
#ifdef DEBUG
printf("Using paper size: %s\n", pprsize);
#endif
/* Determine attributes of paper of the size chosen/determined: */
ppr = paperinfo(pprsize);
ppr_w = paperpswidth(ppr);
ppr_h = paperpsheight(ppr);
#ifdef DEBUG
printf("Paper is %d x %d (%.2f\" x %.2f\")\n", ppr_w, ppr_h,
(float) ppr_w / 72.0, (float) ppr_h / 72.0);
#endif
paperdone(); // FIXME: Should we do this at quit? -bjk 2007.06.25
/* Determine whether it's best to rotate the image: */
if ((ppr_w >= ppr_h && img_w >= img_h) ||
(ppr_w <= ppr_h && img_w <= img_h))
{
rotate = 0;
r_img_w = img_w;
r_img_h = img_h;
}
else
{
rotate = 1;
r_img_w = img_h;
r_img_h = img_w;
}
#ifdef DEBUG
printf("Image is %d x %d\n", img_w, img_h);
printf("Rotated? %s\n", rotate ? "yes" : "no");
printf("Will print %d x %d pixels\n", r_img_w, r_img_h);
#endif
/* Determine scale: */
scale = my_min(((float) (ppr_w - (MARGIN * 2)) / (float) r_img_w),
((float) (ppr_h - (MARGIN * 2)) / (float) r_img_h));
printed_img_w = r_img_w * scale;
printed_img_h = r_img_h * scale;
#ifdef DEBUG
printf("Scaling image by %.2f (to %d x %d)\n", scale,
printed_img_w, printed_img_h);
#endif
// FIXME - doesn't seem to center well -bjk 2007.06.25
tlate_x = (ppr_w - printed_img_w) / 2;
tlate_y = (ppr_h - printed_img_h) / 2;
/* Based off of output from "pnmtops", Tux Paint 0.9.15 thru
0.9.17 CVS as of June 2007, and Adobe Systems Incorporated's
'PostScript(r) Language Reference, 3rd Ed.' */
/* Begin PostScript output with some useful meta info in comments: */
fprintf(fi, "%%!PS-Adobe-2.0 EPSF-2.0\n"); // we need LanguageLevel2 for color
fprintf(fi, "%%%%Title: (%s)\n", fname);
strftime(buf, sizeof buf - 1, "%a %b %e %H:%M:%S %Y", localtime(&t));
fprintf(fi, "%%%%CreationDate: (%s)\n", buf);
fprintf(fi, "%%%%Creator: (Tux Paint " VER_VERSION ", " VER_DATE ")\n");
fprintf(fi, "%%%%Pages: 1\n");
fprintf(fi, "%%%%BoundingBox: 0 0 %d %d\n", (int) (ppr_w + 0.5), (int)
(ppr_h + 0.5));
fprintf(fi, "%%%%EndComments\n");
/* Define a 'readstring' routine and 'picstr' routines for RGB: */
fprintf(fi, "/readstring {\n");
fprintf(fi, " currentfile exch readhexstring pop\n");
fprintf(fi, "} bind def\n");
fprintf(fi, "/rpicstr %d string def\n", img_w);
fprintf(fi, "/gpicstr %d string def\n", img_w);
fprintf(fi, "/bpicstr %d string def\n", img_w);
fprintf(fi, "%%%%EndProlog\n");
fprintf(fi, "%%%%Page: 1 1\n");
fprintf(fi, "<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n",
ppr_w, ppr_h);
fprintf(fi, "gsave\n");
/* 'translate' moves the user space origin to a new position with
respect to the current page, leaving the orientation of the axes and
the unit lengths unchanged. */
fprintf(fi, "%d.%02d %d.%02d translate\n",
f2int(tlate_x), f2dec(tlate_x),
f2int(tlate_y), f2dec(tlate_y));
/* 'scale' modifies the unit lengths independently along the current
x and y axes, leaving the origin location and the orientation of the
axes unchanged. */
fprintf(fi, "%d.%02d %d.%02d scale\n",
f2int(printed_img_w), f2dec(printed_img_w),
f2int(printed_img_h), f2dec(printed_img_h));
/* Rotate the image */
if (rotate)
fprintf(fi, "0.5 0.5 translate 90 rotate -0.5 -0.5 translate\n");
fprintf(fi, "%d %d 8\n", img_w, img_h);
fprintf(fi, "[ %d 0 0 %d 0 %d ]\n", img_w, -img_h, img_h);
fprintf(fi, "{ rpicstr readstring }\n");
fprintf(fi, "{ gpicstr readstring }\n");
fprintf(fi, "{ bpicstr readstring }\n");
fprintf(fi, "true 3\n");
fprintf(fi, "colorimage\n");
cur_line_len = 0;
for (y = 0; y < img_h; y++)
{
for (plane = 0; plane < 3; plane++)
{
for (x = 0; x < img_w; x++)
{
SDL_GetRGB(getpixel(surf, x, y), surf->format, &r, &g, &b);
fprintf(fi, "%02x", (plane == 0 ? r : (plane == 1 ? g : b)));
cur_line_len++;
if (cur_line_len >= 30)
{
fprintf(fi, "\n");
cur_line_len = 0;
}
}
}
}
fprintf(fi, "\n");
fprintf(fi, "grestore\n");
fprintf(fi, "showpage\n");
fprintf(fi, "%%%%Trailer\n");
fprintf(fi, "%%%%EOF\n");
if (!is_pipe)
{
fclose(fi);
return 1;
}
else
{
pid_t child_pid, w;
int status;
child_pid = pclose(fi);
/* debug */
/*
printf("pclose returned %d\n", child_pid); fflush(stdout);
printf("errno = %d\n", errno); fflush(stdout);
*/
if (child_pid < 0 || (errno != 0 && errno != EAGAIN)) { /* FIXME: This right? */
return 0;
} else if (child_pid == 0) {
return 1;
}
do
{
w = waitpid(child_pid, &status, 0);
/* debug */
/*
if (w == -1) { perror("waitpid"); exit(EXIT_FAILURE); }
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
*/
}
while (w != -1 && !WIFEXITED(status) && !WIFSIGNALED(status));
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) /* Not happy exit */
return 0;
return 1;
}
}
#endif