add magic "-" stdin filename

this almost works!

$ vips invert - x.jpg < k2.jpg
This commit is contained in:
John Cupitt 2019-10-11 05:38:58 +01:00
parent 3a2bebdffb
commit 442720a0a1
8 changed files with 166 additions and 25 deletions

View File

@ -621,6 +621,55 @@ vips_foreign_find_load_buffer( const void *data, size_t size )
return( G_OBJECT_CLASS_NAME( load_class ) );
}
/* Can this VipsForeign open this stream?
*/
static void *
vips_foreign_find_load_stream_sub( void *item, void *a, void *b )
{
VipsForeignLoadClass *load_class = VIPS_FOREIGN_LOAD_CLASS( item );
VipsStreamInput *input = VIPS_STREAM_INPUT( a );
if( load_class->is_a_stream &&
load_class->is_a_stream( input ) )
return( load_class );
return( NULL );
}
/**
* vips_foreign_find_load_stream:
* @input: stream to load from
*
* Searches for an operation you could use to load a stream. To see the
* range of buffer loaders supported by your vips, try something like:
*
* vips -l | grep load_stream
*
* See also: vips_image_new_from_stream().
*
* Returns: (transfer none): the name of an operation on success, %NULL on
* error.
*/
const char *
vips_foreign_find_load_stream( VipsStreamInput *input )
{
VipsForeignLoadClass *load_class;
if( !(load_class = (VipsForeignLoadClass *) vips_foreign_map(
"VipsForeignLoad",
vips_foreign_find_load_stream_sub,
input, NULL )) ) {
vips_error( "VipsForeignLoad",
"%s", _( "stream is not in a known format" ) );
(void) vips_stream_input_rewind( input );
return( NULL );
}
(void) vips_stream_input_rewind( input );
return( G_OBJECT_CLASS_NAME( load_class ) );
}
/**
* vips_foreign_is_a:
* @loader: name of loader to use for test

View File

@ -134,9 +134,9 @@
*/
/*
*/
#define DEBUG_VERBOSE
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -1216,6 +1216,10 @@ vips__jpeg_read_stream( VipsStreamInput *input, VipsImage *out,
if( vips__jpeg_read( jpeg, out, header_only ) )
return( -1 );
/* We've read the header ... it's pixel decode from now on.
vips_stream_input_decode( input );
*/
return( 0 );
}

View File

@ -34,9 +34,9 @@
*/
/*
*/
#define DEBUG_VERBOSE
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -359,6 +359,8 @@ vips_foreign_load_jpeg_stream_load( VipsForeignLoad *load )
static gboolean
vips_foreign_load_jpeg_stream_is_a( VipsStreamInput *input )
{
printf( "vips_foreign_load_jpeg_stream_is_a:\n" );
return( vips__isjpeg_stream( input ) );
}

View File

@ -240,6 +240,7 @@ GType vips_foreign_load_get_type(void);
const char *vips_foreign_find_load( const char *filename );
const char *vips_foreign_find_load_buffer( const void *data, size_t size );
const char *vips_foreign_find_load_stream( VipsStreamInput *stream );
VipsForeignFlags vips_foreign_flags( const char *loader, const char *filename );
gboolean vips_foreign_is_a( const char *loader, const char *filename );

View File

@ -450,13 +450,16 @@ VipsImage *vips_image_new_from_memory_copy( const void *data, size_t size,
VipsImage *vips_image_new_from_buffer( const void *buf, size_t len,
const char *option_string, ... )
__attribute__((sentinel));
VipsImage *vips_image_new_from_stream( VipsStreamInput *input,
const char *option_string, ... ) __attribute__((sentinel));
VipsImage *vips_image_new_matrix( int width, int height );
VipsImage *vips_image_new_matrixv( int width, int height, ... );
VipsImage *vips_image_new_matrix_from_array( int width, int height,
const double *array, int size );
VipsImage *vips_image_matrix_from_array( int width, int height,
const double *array, int size );
VipsImage *vips_image_new_from_image( VipsImage *image, const double *c, int n );
VipsImage *vips_image_new_from_image( VipsImage *image,
const double *c, int n );
VipsImage *vips_image_new_from_image1( VipsImage *image, double c );
void vips_image_set_delete_on_close( VipsImage *image,

View File

@ -2167,6 +2167,48 @@ vips_image_new_from_buffer( const void *buf, size_t len,
return( out );
}
/**
* vips_image_new_from_stream: (constructor)
* @input: (transfer none): stream to fetch image from
* @option_string: set of extra options as a string
* @...: %NULL-terminated list of optional named arguments
*
* Loads an image from the formatted stream @input,
* loader recommended by vips_foreign_find_load_stream().
*
* Load options may be given in @option_string as "[name=value,...]" or given as
* a NULL-terminated list of name-value pairs at the end of the arguments.
* Options given in the function call override options given in the string.
*
* See also: vips_image_write_to_buffer().
*
* Returns: (transfer full): the new #VipsImage, or %NULL on error.
*/
VipsImage *
vips_image_new_from_stream( VipsStreamInput *input,
const char *option_string, ... )
{
const char *operation_name;
va_list ap;
int result;
VipsImage *out;
vips_check_init();
if( !(operation_name = vips_foreign_find_load_stream( input )) )
return( NULL );
va_start( ap, option_string );
result = vips_call_split_option_string( operation_name,
option_string, ap, input, &out );
va_end( ap );
if( result )
return( NULL );
return( out );
}
/**
* vips_image_new_matrix: (constructor)
* @width: image width

View File

@ -1899,16 +1899,35 @@ vips_object_set_argument_from_string( VipsObject *object,
/* Read the filename.
*/
if( flags & (VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
VIPS_OPERATION_SEQUENTIAL) )
if( flags &
(VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
VIPS_OPERATION_SEQUENTIAL) )
access = VIPS_ACCESS_SEQUENTIAL;
else
access = VIPS_ACCESS_RANDOM;
if( !(out = vips_image_new_from_file( value,
"access", access,
NULL )) )
return( -1 );
/* The special filename "-" means stdin.
*/
if( strcmp( value, "-" ) == 0 ) {
VipsStreamInput *input;
if( !(input =
vips_stream_input_new_from_descriptor( 0 )) )
return( -1 );
if( !(out = vips_image_new_from_stream( input, "",
"access", access,
NULL )) ) {
VIPS_UNREF( input );
return( -1 );
}
VIPS_UNREF( input );
}
else {
if( !(out = vips_image_new_from_file( value,
"access", access,
NULL )) )
return( -1 );
}
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
g_value_set_object( &gvalue, out );

View File

@ -41,8 +41,8 @@
*/
/*
#define VIPS_DEBUG
*/
#define VIPS_DEBUG
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -243,6 +243,8 @@ vips_stream_input_read_real( VipsStreamInput *input,
{
VipsStream *stream = VIPS_STREAM( input );
VIPS_DEBUG_MSG( "vips_stream_input_read_real:\n" );
if( input->blob ) {
VipsArea *area = (VipsArea *) input->blob;
ssize_t available = VIPS_MIN( length,
@ -255,7 +257,7 @@ vips_stream_input_read_real( VipsStreamInput *input,
return( available );
}
else if( stream->descriptor ) {
else if( stream->descriptor != -1 ) {
return( read( stream->descriptor, buffer, length ) );
}
else {
@ -269,6 +271,8 @@ vips_stream_input_rewind_real( VipsStreamInput *input )
{
VipsStream *stream = VIPS_STREAM( input );
VIPS_DEBUG_MSG( "vips_stream_input_rewind_real:\n" );
if( input->decode ) {
vips_error( STREAM_NAME( stream ),
"%s", _( "can't rewind after decode begins" ) );
@ -279,6 +283,9 @@ vips_stream_input_rewind_real( VipsStreamInput *input )
stream->descriptor != -1 ) {
off_t new_pos;
VIPS_DEBUG_MSG( " rewinding desriptor %d\n",
stream->descriptor );
new_pos = lseek( stream->descriptor, 0, SEEK_SET );
if( new_pos == -1 ) {
vips_error_system( errno, STREAM_NAME( stream ),
@ -468,12 +475,14 @@ vips_stream_input_read( VipsStreamInput *input,
ssize_t bytes_read;
VIPS_DEBUG_MSG( "vips_stream_input_read:\n" );
bytes_read = 0;
/* Are we serving from header_bytes? Get what we can from there.
*/
if( input->header_bytes &&
input->header_bytes->len < input->read_position ) {
input->read_position < input->header_bytes->len ) {
ssize_t available;
available = VIPS_MIN( length,
@ -485,19 +494,21 @@ vips_stream_input_read( VipsStreamInput *input,
buffer += available;
length -= available;
bytes_read += available;
VIPS_DEBUG_MSG( " %zd bytes from cache\n", available );
}
/* Any more bytes required? Call the read() method.
*/
if( length > 0 ) {
ssize_t read;
ssize_t n;
if( (read = class->read( input, buffer, length )) == -1 ) {
if( (n = class->read( input, buffer, length )) == -1 ) {
vips_error_system( errno, STREAM_NAME( input ),
"%s", _( "read error" ) );
return( -1 );
}
if( read == 0 )
if( n == 0 )
input->eof = TRUE;
/* If we're not rewindable, we need to save header bytes for
@ -506,14 +517,18 @@ vips_stream_input_read( VipsStreamInput *input,
if( input->header_bytes &&
!input->rewindable &&
!input->decode &&
read > 0 )
n > 0 )
g_byte_array_append( input->header_bytes,
buffer, read );
buffer, n );
input->read_position += read;
bytes_read += read;
input->read_position += n;
bytes_read += n;
VIPS_DEBUG_MSG( " %zd bytes from read()\n", n );
}
VIPS_DEBUG_MSG( " %zd bytes total\n", bytes_read );
return( bytes_read );
}
@ -522,18 +537,24 @@ vips_stream_input_rewind( VipsStreamInput *input )
{
VipsStreamInputClass *class = VIPS_STREAM_INPUT_GET_CLASS( input );
VIPS_DEBUG_MSG( "vips_stream_input_rewind:\n" );
return( class->rewind( input ) );
}
gboolean
vips_stream_input_eof( VipsStreamInput *input )
{
VIPS_DEBUG_MSG( "vips_stream_input_eof:\n" );
return( input->eof );
}
void
vips_stream_input_decode( VipsStreamInput *input )
{
VIPS_DEBUG_MSG( "vips_stream_input_decode:\n" );
input->decode = TRUE;
VIPS_FREEF( g_byte_array_unref, input->header_bytes );
VIPS_FREEF( g_byte_array_unref, input->sniff );
@ -548,20 +569,20 @@ vips_stream_input_decode( VipsStreamInput *input )
unsigned char *
vips_stream_input_sniff( VipsStreamInput *input, size_t length )
{
ssize_t read;
ssize_t n;
unsigned char *q;
VIPS_DEBUG_MSG( "vips_stream_input_sniff: %zd bytes\n", length );
if( vips_stream_input_rewind( input ) )
return( NULL );
g_byte_array_set_size( input->sniff, length );
for( q = input->sniff->data; length > 0; length -= read, q += read ) {
read = vips_stream_input_read( input, q, length );
if( read == -1 ||
read == 0 )
for( q = input->sniff->data; length > 0; length -= n, q += n )
if( (n = vips_stream_input_read( input, q, length )) == -1 ||
n == 0 )
return( NULL );
}
return( input->sniff->data );
}