libvips/tools/vipsedit.c

273 lines
7.6 KiB
C

/* modify vips file header! - useful for setting resolution, coding...
very dangerous!
no way of setting non-used codes in variables like newxres
so need flags to show new parameter has been set.. boring
Copyright K.Martinez 30/6/93
29/7/93 JC
-format added
- ==0 added to strcmp!
17/11/94 JC
- new header fields added
21/10/04
- more header updates
22/8/05
- less-stupid-ified
20/9/05
- rewritten with glib option parser, ready for xml options to go in
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 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 <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <locale.h>
#include <vips/vips.h>
#include <vips/vips7compat.h>
#include <vips/internal.h>
#include <vips/debug.h>
/* We have to represent all header fields as char * so we can spot unset args
* safely.
*/
static char *xsize = NULL;
static char *ysize = NULL;
static char *bands = NULL;
static char *format = NULL;
static char *interpretation = NULL;
static char *coding = NULL;
static char *xres = NULL;
static char *yres = NULL;
static char *xoffset = NULL;
static char *yoffset = NULL;
static char *endian = NULL;
static gboolean setext = FALSE;
static GOptionEntry entries[] = {
{ "endian", 'n', 0, G_OPTION_ARG_STRING, &endian,
N_( "tag file as big or little-endian" ), NULL },
{ "width", 'w', 0, G_OPTION_ARG_STRING, &xsize,
N_( "set width to N pixels" ), "N" },
{ "height", 'h', 0, G_OPTION_ARG_STRING, &ysize,
N_( "set height to N pixels" ), "N" },
{ "bands", 'b', 0, G_OPTION_ARG_STRING, &bands,
N_( "set Bands to N" ), "N" },
{ "format", 'f', 0, G_OPTION_ARG_STRING, &format,
N_( "set BandFmt to F (eg. uchar, float)" ), "F" },
{ "interpretation", 'i', 0, G_OPTION_ARG_STRING, &interpretation,
N_( "set interpretation to I (eg. xyz)" ), "I" },
{ "coding", 'c', 0, G_OPTION_ARG_STRING, &coding,
N_( "set Coding to C (eg. labq)" ), "C" },
{ "xres", 'X', 0, G_OPTION_ARG_STRING, &xres,
N_( "set Xres to R pixels/mm" ), "R" },
{ "yres", 'Y', 0, G_OPTION_ARG_STRING, &yres,
N_( "set Yres to R pixels/mm" ), "R" },
{ "xoffset", 'u', 0, G_OPTION_ARG_STRING, &xoffset,
N_( "set Xoffset to N pixels" ), "N" },
{ "yoffset", 'v', 0, G_OPTION_ARG_STRING, &yoffset,
N_( "set Yoffset to N pixels" ), "N" },
{ "setext", 'e', 0, G_OPTION_ARG_NONE, &setext,
N_( "replace extension block with stdin" ), NULL },
{ "xsize", 'x', 0, G_OPTION_ARG_STRING, &xsize,
N_( "set Xsize to N (deprecated, use width)" ), "N" },
{ "ysize", 'y', 0, G_OPTION_ARG_STRING, &ysize,
N_( "set Ysize to N (deprecated, use height)" ), "N" },
{ "type", 't', 0, G_OPTION_ARG_STRING, &interpretation,
N_( "set Type to T (deprecated, use interpretation)" ), "T" },
{ NULL }
};
static void
parse_pint( char *arg, int *out )
{
/* Might as well set an upper limit.
*/
*out = atoi( arg );
if( *out <= 0 || *out > 1000000 )
error_exit( _( "'%s' is not a positive integer" ), arg );
}
int
main( int argc, char **argv )
{
GOptionContext *context;
GOptionGroup *main_group;
GError *error = NULL;
IMAGE *im;
unsigned char header[IM_SIZEOF_HEADER];
if( VIPS_INIT( argv[0] ) )
vips_error_exit( "%s", _( "unable to start VIPS" ) );
textdomain( GETTEXT_PACKAGE );
setlocale( LC_ALL, "" );
/* On Windows, argv is ascii-only .. use this to get a utf-8 version of
* the args.
*/
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
argv = g_win32_get_command_line();
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
context = g_option_context_new(
_( "vipsedit - edit vips file header" ) );
main_group = g_option_group_new( NULL, NULL, NULL, NULL, NULL );
g_option_group_add_entries( main_group, entries );
vips_add_option_entries( main_group );
g_option_group_set_translation_domain( main_group, GETTEXT_PACKAGE );
g_option_context_set_main_group( context, main_group );
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
if( !g_option_context_parse_strv( context, &argv, &error ) )
#else /*!HAVE_G_WIN32_GET_COMMAND_LINE*/
if( !g_option_context_parse( context, &argc, &argv, &error ) )
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
{
if( error ) {
fprintf( stderr, "%s\n", error->message );
g_error_free( error );
}
exit( -1 );
}
/* On Windows, argc will not have been updated by
* g_option_context_parse_strv().
*/
for( argc = 0; argv[argc]; argc++ )
;
if( argc != 2 ) {
fprintf( stderr, _( "usage: %s [OPTION...] vips-file\n" ),
g_get_prgname() );
exit( -1 );
}
if( !(im = im_init( argv[1] )) ||
(im->fd = im__open_image_file( im->filename )) == -1 )
error_exit( _( "could not open image %s" ), argv[1] );
if( read( im->fd, header, IM_SIZEOF_HEADER ) != IM_SIZEOF_HEADER ||
im__read_header_bytes( im, header ) )
error_exit( _( "could not read VIPS header for %s" ),
im->filename );
if( endian ) {
if( strcmp( endian, "little" ) == 0 )
im->magic = VIPS_MAGIC_INTEL;
else if( strcmp( endian, "big" ) == 0 )
im->magic = VIPS_MAGIC_SPARC;
else
error_exit( _( "bad endian-ness %s, "
"should be 'big' or 'little'" ), endian );
}
if( xsize )
parse_pint( xsize, &im->Xsize );
if( ysize )
parse_pint( ysize, &im->Ysize );
if( bands )
parse_pint( bands, &im->Bands );
if( format ) {
VipsBandFormat f;
if( (f = im_char2BandFmt( format )) < 0 )
error_exit( _( "bad format %s" ), format );
im->BandFmt = f;
im->Bbits = im_bits_of_fmt( f );
}
if( interpretation ) {
VipsInterpretation i;
if( (i = im_char2Type( interpretation )) < 0 )
error_exit( _( "bad interpretation %s" ),
interpretation );
im->Type = i;
}
if( coding ) {
VipsCoding c;
if( (c = im_char2Coding( coding )) < 0 )
error_exit( _( "bad coding %s" ), coding );
im->Coding = c;
}
if( xres )
im->Xres = atof( xres );
if( yres )
im->Yres = atof( yres );
if( xoffset )
im->Xoffset = atoi( xoffset );
if( yoffset )
im->Yoffset = atoi( yoffset );
if( lseek( im->fd, 0, SEEK_SET ) == (off_t) -1 )
error_exit( _( "could not seek on %s" ), im->filename );
if( im__write_header_bytes( im, header ) ||
im__write( im->fd, header, IM_SIZEOF_HEADER ) )
error_exit( _( "could not write to %s" ), im->filename );
if( setext ) {
char *xml;
size_t size;
if( !(xml = im__file_read( stdin, "stdin", &size )) )
error_exit( "%s", _( "could not get ext data" ) );
/* Strip trailing whitespace ... we can get stray \n at the
* end, eg. "echo | editvips --setext fred.v".
*/
while( size > 0 && isspace( xml[size - 1] ) )
size -= 1;
if( im__write_extension_block( im, xml, size ) )
error_exit( "%s", _( "could not set extension" ) );
im_free( xml );
}
im_close( im );
/* We don't free this on error exit, sadly.
*/
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
g_strfreev( argv );
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
vips_shutdown();
return( 0 );
}