libvips/contrib/vips2dj/vips2dj.c

378 lines
9.0 KiB
C

/* Convert lab, cmyk and mono images to postscript.
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <vips/vips.h>
#include <vips/util.h>
#include "vips2dj.h"
static const char *argv0 = NULL;
/* Geometries for the printers we know about.
*/
PrinterGeometry printer_data[] = {
/* name, paper width, print width, print length, left, top */
{ "2500cp", 2592, 2502, 3728, 51, 82 },
{ "3500cp", 3888, 3786, 5212, 51, 82 },
{ "5000ps", 4320, 4280, 5212, 20, 99 },
{ "4600dn", 594, 570, 817, 11, 15 }
};
/* Print a geo entry.
*/
static void
print_printers( void )
{
int i;
printf( "%12s %12s %12s %12s %12s %12s\n", "printer name",
"paper width", "print width", "print length",
"left margin", "top margin" );
for( i = 0; i < IM_NUMBER( printer_data ); i++ )
printf( "%12s %12d %12d %12d %12d %12d\n",
printer_data[i].name,
printer_data[i].pwidth,
printer_data[i].width,
printer_data[i].length,
printer_data[i].left,
printer_data[i].top );
}
/* Turn a name to a printer geometry.
*/
static PrinterGeometry *
find_printer( char *name )
{
int i;
for( i = 0; i < IM_NUMBER( printer_data ); i++ )
if( strcmp( name, printer_data[i].name ) == 0 )
return( &printer_data[i] );
im_errormsg( "vips2dj: unknown printer \"%s\"", name );
return( NULL );
}
/* Copy between two fds
*/
static int
copy_bytes( FILE *in, FILE *out )
{
int ch;
while( (ch = getc( in )) != EOF )
if( putc( ch, out ) == EOF ) {
im_errormsg( "vips2dj: write error -- disc full?" );
return( -1 );
}
return( 0 );
}
/* Send a file to out. Used to transmit the preludes.
*/
static int
transmit_file( char *mode, char *name, FILE *out )
{
const char *prefix;
char buf[PATH_MAX];
FILE *in;
if( !(prefix = im_guess_prefix( argv0, "VIPSHOME" )) )
return( -1 );
/* Send it!
*/
im_snprintf( buf, PATH_MAX, "%s/share/vips/vips2dj/%s/%s",
prefix, mode, name );
if( !(in = fopen( buf, "r" )) ) {
im_errormsg( "vips2dj: can't find \"%s\"", name );
return( -1 );
}
if( copy_bytes( in, out ) ) {
fclose( in );
return( -1 );
}
fclose( in );
return( 0 );
}
/* Send the file to fp. width and height are the size to print at in points.
*/
static int
send_file( PrinterGeometry *geo, IMAGE *im, char *mode,
FILE *out, int width, int height )
{
/* Send all the start stuff.
*/
if( transmit_file( mode, "head1", out ) )
return( -1 );
/* Set page size.
*/
fprintf( out, "<</PageSize[%d %d]/ImagingBBox null>>setpagedevice\n",
geo->pwidth, height + 2*geo->top );
if( transmit_file( mode, "head2", out ) )
return( -1 );
/* Set mT (margin transform? don't know)
*/
fprintf( out, "/mT[1 0 0 -1 %d %d]def\n",
geo->left, height + geo->top );
if( transmit_file( mode, "head3", out ) )
return( -1 );
/* Set rC ... printable area.
*/
fprintf( out, "gS 0 0 %d %d rC\n", width, height );
if( transmit_file( mode, "head4", out ) )
return( -1 );
/* Set image params.
*/
fprintf( out, "/rows %d def\n", im->Ysize );
fprintf( out, "/cols %d def\n", im->Xsize );
fprintf( out, "%d %d scale\n", width, height );
if( transmit_file( mode, "head5", out ) )
return( -1 );
/* Send the body of the image.
*/
if( vips2asciihex( im, out ) )
return( -1 );
if( transmit_file( mode, "head6", out ) )
return( -1 );
return( 0 );
}
/* Start here!
*/
int
main( int argc, char **argv )
{
IMAGE *im = NULL;
FILE *out = stdout;
int width = -1;
int height = -1;
int dpi = -1;
int max = 0;
int one2one = 0;
PrinterGeometry *geo = find_printer( "2500cp" );
char *mode;
int i;
if( im_init_world( argv[0] ) )
error_exit( "unable to start VIPS" );
argv0 = argv[0];
if( argc <= 1 ) {
printf(
"usage:\n"
"\t%s [options] <image file>\n"
"convert LAB, CMYK and mono image files to postscript\n"
"\tLAB printed with printer colour management\n"
"\tCMYK sent directly as dot percent\n"
"\tmono prints as K only\n"
"options include:\n"
"\t-printer <name>\tformat for printer <name>\n"
"\t-3500cp\t\tfor HP 3500CP printer (default 2500cp)\n"
"\t-max\t\tprint as large as possible\n"
"\t-1:1\t\tsize the image to print at 1:1 ... resolution in\n"
"\t\t\timage header must be set for this\n"
"\t-width <n>\tforce specified width, in points\n"
"\t-height <n>\tforce specified height, in points\n"
"\t-dpi <n>\tforce specified resolution (default 150dpi)\n"
"\t-a5, -a4, -a3, -a2, -a1, -a0\n"
"\t\t\tforce specified height (width ignored)\n"
"\t-o <file>\toutput to file (default stdout)\n",
argv0 );
printf( "supported printers:\n" );
print_printers();
return( 1 );
}
/* Decode args .. just look for file names and our three options.
*/
for( i = 1; i < argc; i++ )
if( *argv[i] == '-' ) {
if( strcmp( argv[i]+1, "width" ) == 0 ) {
if( !argv[i+1] || sscanf( argv[i+1],
"%d", &width ) != 1 || width <= 10 )
error_exit( "bad width" );
i++;
}
else if( strcmp( argv[i]+1, "height" ) == 0 ) {
if( !argv[i+1] || sscanf( argv[i+1],
"%d", &height ) != 1 || height <= 10 )
error_exit( "bad height" );
i++;
}
else if( strcmp( argv[i]+1, "3500cp" ) == 0 ) {
geo = find_printer( "3500cp" );
}
else if( strcmp( argv[i]+1, "printer" ) == 0 ) {
if( !argv[i+1] ||
!(geo = find_printer( argv[i+1] )) )
error_exit( "bad printer model" );
i++;
}
else if( strcmp( argv[i]+1, "dpi" ) == 0 ) {
if( !argv[i+1] || sscanf( argv[i+1],
"%d", &dpi ) != 1 || dpi <= 1 ||
dpi >= 600 )
error_exit( "bad dpi" );
i++;
}
else if( strcmp( argv[i]+1, "o" ) == 0 ) {
if( !argv[i+1] || !(out = fopen(
argv[i+1], "w" )) )
error_exit( "bad output name" );
i++;
}
else if( strcmp( argv[i]+1, "1:1" ) == 0 )
one2one = 1;
else if( strcmp( argv[i]+1, "a5" ) == 0 )
height = 595;
else if( strcmp( argv[i]+1, "a4" ) == 0 )
height = 839;
else if( strcmp( argv[i]+1, "a3" ) == 0 )
height = 1187;
else if( strcmp( argv[i]+1, "a2" ) == 0 )
height = 1678;
else if( strcmp( argv[i]+1, "a1" ) == 0 )
height = 2373;
else if( strcmp( argv[i]+1, "a0" ) == 0 )
height = 3356;
else if( strcmp( argv[i]+1, "max" ) == 0 )
max = 1;
else
error_exit( "bad flag" );
}
else {
/* Try to open the file.
*/
if( im != NULL || !(im = im_open( argv[i], "r" )) )
error_exit( "bad input image" );
}
if( im == NULL )
error_exit( "no input image" );
/* Stop used-before-set complaints on mode.
*/
mode = "lab";
/* Pick a PS mode.
*/
if( im->Coding == IM_CODING_LABQ )
mode = "lab";
else if( im->Coding == IM_CODING_NONE &&
im->Bands == 4 && im->BandFmt == IM_BANDFMT_UCHAR )
mode = "cmyk";
else if( im->Coding == IM_CODING_NONE &&
im->Bands == 1 && im->BandFmt == IM_BANDFMT_UCHAR )
mode = "mono";
else
error_exit( "unsupported image type "
"(IM_CODING_LABQ, mono, IM_TYPE_CMYK only)" );
/* Make sure width and height are both set.
*/
if( one2one ) {
/* Set width/height from res.
*/
if( im->Xres <= 0 || im->Xres >= 100 ||
im->Yres <= 0 || im->Yres >= 100 )
error_exit( "uanble to print 1:1 - resolution not "
"set in image" );
height = (((im->Ysize / im->Yres) / 10.0) / 2.54) * 72.0;
width = (((im->Xsize / im->Xres) / 10.0) / 2.54) * 72.0;
}
else if( max ) {
float iaspect = (float) im->Xsize / im->Ysize;
float paspect = (float) geo->width / geo->length;
if( iaspect > paspect )
/* Image aspect ratio > paper ... fit width.
*/
width = geo->width;
else
height = geo->length;
}
else if( dpi > 0 ) {
/* Given res ... set width/height.
*/
height = (im->Ysize / (float) dpi) * 72.0;
width = (im->Xsize / (float) dpi) * 72.0;
}
if( width >= 0 || height >= 0 ) {
/* Given width or height or both --- set other one.
*/
if( height < 0 ) {
float fdpi = im->Xsize / (width / 72.0);
height = (im->Ysize / fdpi) * 72.0;
}
else {
float fdpi = im->Ysize / (height / 72.0);
width = (im->Xsize / fdpi) * 72.0;
}
}
else {
/* Nothing set ... default to 150 dpi.
*/
height = (im->Ysize / 150.0) * 72.0;
width = (im->Xsize / 150.0) * 72.0;
}
if( send_file( geo, im, mode, out, width, height ) )
error_exit( "error sending file" );
return( 0 );
}