c99dc0fe03
We were not freeing the argument parse context in vipsedit.c. Thanks zodf0055980 see https://github.com/libvips/libvips/issues/1868
284 lines
7.9 KiB
C
284 lines
7.9 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
|
|
* 18/6/20 kleisauke
|
|
* - avoid using vips7 symbols
|
|
*/
|
|
|
|
/*
|
|
|
|
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/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 )
|
|
vips_error_exit( _( "'%s' is not a positive integer" ), arg );
|
|
}
|
|
|
|
int
|
|
main( int argc, char **argv )
|
|
{
|
|
GOptionContext *context;
|
|
GOptionGroup *main_group;
|
|
GError *error = NULL;
|
|
VipsImage *im;
|
|
unsigned char header[VIPS_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*/
|
|
{
|
|
vips_g_error( &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 = vips_image_new_from_file( argv[1], NULL )) )
|
|
vips_error_exit( _( "could not open image %s" ), argv[1] );
|
|
|
|
vips__seek( im->fd, 0, SEEK_SET );
|
|
if( read( im->fd, header, VIPS_SIZEOF_HEADER ) !=
|
|
VIPS_SIZEOF_HEADER ||
|
|
vips__read_header_bytes( im, header ) )
|
|
vips_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
|
|
vips_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 ) {
|
|
int f;
|
|
|
|
if( (f = vips_enum_from_nick( argv[0],
|
|
VIPS_TYPE_BAND_FORMAT, format )) < 0 )
|
|
vips_error_exit( _( "bad format %s" ), format );
|
|
|
|
im->BandFmt = f;
|
|
|
|
/* We don't use this, but make sure it's set in case any
|
|
* old binaries are expecting it.
|
|
*/
|
|
im->Bbits = vips_format_sizeof( f ) << 3;
|
|
}
|
|
if( interpretation ) {
|
|
int i;
|
|
|
|
if( (i = vips_enum_from_nick( argv[0],
|
|
VIPS_TYPE_INTERPRETATION, interpretation )) < 0 )
|
|
vips_error_exit( _( "bad interpretation %s" ),
|
|
interpretation );
|
|
|
|
im->Type = i;
|
|
}
|
|
if( coding ) {
|
|
int c;
|
|
|
|
if( (c = vips_enum_from_nick( argv[0],
|
|
VIPS_TYPE_CODING, coding )) < 0 )
|
|
vips_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( vips__seek( im->fd, 0, SEEK_SET ) == (off_t) -1 )
|
|
vips_error_exit( _( "could not seek on %s" ), im->filename );
|
|
if( vips__write_header_bytes( im, header ) ||
|
|
vips__write( im->fd, header, VIPS_SIZEOF_HEADER ) )
|
|
vips_error_exit( _( "could not write to %s" ), im->filename );
|
|
|
|
if( setext ) {
|
|
char *xml;
|
|
size_t size;
|
|
|
|
if( !(xml = vips__file_read( stdin, "stdin", &size )) )
|
|
vips_error_exit( "%s", _( "could not get ext data" ) );
|
|
|
|
/* Strip trailing whitespace ... we can get stray \n at the
|
|
* end, eg. "echo | vipsedit --setext fred.v".
|
|
*/
|
|
while( size > 0 && isspace( xml[size - 1] ) )
|
|
size -= 1;
|
|
|
|
if( vips__write_extension_block( im, xml, size ) )
|
|
vips_error_exit( "%s", _( "could not set extension" ) );
|
|
g_free( xml );
|
|
}
|
|
|
|
g_object_unref( im );
|
|
|
|
g_option_context_free( context );
|
|
|
|
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
|
|
g_strfreev( argv );
|
|
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
|
|
|
|
vips_shutdown();
|
|
|
|
return( 0 );
|
|
}
|
|
|