Merge branch 'master' of git://github.com/deftomat/libvips into deftomat-master
This commit is contained in:
commit
00676a2166
@ -1,5 +1,6 @@
|
|||||||
20/6/19 started 8.9.0
|
20/6/19 started 8.9.0
|
||||||
- add vips_image_get/set_array_int()
|
- add vips_image_get/set_array_int()
|
||||||
|
- disable webp alpha output if all frame fill the canvas and are solid
|
||||||
|
|
||||||
24/5/19 started 8.8.1
|
24/5/19 started 8.8.1
|
||||||
- improve realpath() use on older libc
|
- improve realpath() use on older libc
|
||||||
|
@ -351,6 +351,12 @@ public:
|
|||||||
vips_image_set_int( this->get_image(), field, value );
|
vips_image_set_int( this->get_image(), field, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set( const char *field, int *value, int n )
|
||||||
|
{
|
||||||
|
vips_image_set_array_int( this->get_image(), field, value, n );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
set( const char *field, double value )
|
set( const char *field, double value )
|
||||||
{
|
{
|
||||||
@ -388,6 +394,13 @@ public:
|
|||||||
return( value );
|
return( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
get_array_int( const char *field, int **out, int *n ) const
|
||||||
|
{
|
||||||
|
if( vips_image_get_array_int( this->get_image(), field, out, n ) )
|
||||||
|
throw( VError() );
|
||||||
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
get_double( const char *field ) const
|
get_double( const char *field ) const
|
||||||
{
|
{
|
||||||
|
@ -132,7 +132,7 @@ typedef struct _VipsForeignLoadGif {
|
|||||||
gboolean has_transparency;
|
gboolean has_transparency;
|
||||||
gboolean has_colour;
|
gboolean has_colour;
|
||||||
|
|
||||||
/* Delays between frames (in miliseconds).
|
/* Delays between frames (in milliseconds).
|
||||||
*/
|
*/
|
||||||
int *delays;
|
int *delays;
|
||||||
|
|
||||||
@ -519,9 +519,9 @@ vips_foreign_load_gif_scan_extension( VipsForeignLoadGif *gif )
|
|||||||
gif->has_transparency = TRUE;
|
gif->has_transparency = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( gif->n_pages % 64 == 0 ) {
|
if( gif->n_pages % 64 == 0 )
|
||||||
gif->delays = (int *) g_realloc( gif->delays, (gif->n_pages + 64) * sizeof(int) );
|
gif->delays = (int *) g_realloc( gif->delays, (gif->n_pages + 64) * sizeof(int) );
|
||||||
}
|
|
||||||
gif->delays[gif->n_pages] = (extension[2] | (extension[3] << 8)) * 10;
|
gif->delays[gif->n_pages] = (extension[2] | (extension[3] << 8)) * 10;
|
||||||
|
|
||||||
while( extension != NULL )
|
while( extension != NULL )
|
||||||
@ -575,11 +575,11 @@ vips_foreign_load_gif_set_header( VipsForeignLoadGif *gif, VipsImage *image )
|
|||||||
vips_image_set_int( image, "gif-loop", gif->loop );
|
vips_image_set_int( image, "gif-loop", gif->loop );
|
||||||
|
|
||||||
if( gif->delays ) {
|
if( gif->delays ) {
|
||||||
vips_image_set_int( image, "gif-delay", VIPS_RINT( gif->delays[0] / 10.0 ) );
|
vips_image_set_int( image,
|
||||||
|
"gif-delay", VIPS_RINT( gif->delays[0] / 10.0 ) );
|
||||||
vips_image_set_array_int( image, "delay", gif->delays, gif->n_pages );
|
vips_image_set_array_int( image, "delay", gif->delays, gif->n_pages );
|
||||||
} else {
|
} else
|
||||||
vips_image_set_int( image, "gif-delay", 4 );
|
vips_image_set_int( image, "gif-delay", 4 );
|
||||||
}
|
|
||||||
|
|
||||||
if( gif->comment )
|
if( gif->comment )
|
||||||
vips_image_set_string( image, "gif-comment", gif->comment );
|
vips_image_set_string( image, "gif-comment", gif->comment );
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
* 17/2/19
|
* 17/2/19
|
||||||
* - support ICC, XMP, EXIF, IPTC metadata
|
* - support ICC, XMP, EXIF, IPTC metadata
|
||||||
* - write with a single call to vips_sink_disc()
|
* - write with a single call to vips_sink_disc()
|
||||||
|
* 29/6/19
|
||||||
|
* - support "strip" option
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -68,6 +70,8 @@ typedef struct _VipsForeignSaveMagick {
|
|||||||
Image *current_image;
|
Image *current_image;
|
||||||
|
|
||||||
int page_height;
|
int page_height;
|
||||||
|
int *delays;
|
||||||
|
int delays_length;
|
||||||
|
|
||||||
/* The position of current_image in the output.
|
/* The position of current_image in the output.
|
||||||
*/
|
*/
|
||||||
@ -109,9 +113,8 @@ vips_foreign_save_magick_next_image( VipsForeignSaveMagick *magick )
|
|||||||
|
|
||||||
Image *image;
|
Image *image;
|
||||||
int number;
|
int number;
|
||||||
int *numbers;
|
|
||||||
int numbers_length;
|
|
||||||
const char *str;
|
const char *str;
|
||||||
|
int page_index;
|
||||||
|
|
||||||
g_assert( !magick->current_image );
|
g_assert( !magick->current_image );
|
||||||
|
|
||||||
@ -141,11 +144,13 @@ vips_foreign_save_magick_next_image( VipsForeignSaveMagick *magick )
|
|||||||
im->Xsize, magick->page_height, magick->exception ) )
|
im->Xsize, magick->page_height, magick->exception ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( vips_image_get_typeof( im, "delay" ) &&
|
/* Delay must be converted from milliseconds into centiseconds
|
||||||
!vips_image_get_array_int( im, "delay", &numbers, &numbers_length ) ) {
|
* as GIF image requires centiseconds.
|
||||||
int page_index = magick->position.top / magick->page_height;
|
*/
|
||||||
if( page_index < numbers_length )
|
if ( magick->delays != NULL) {
|
||||||
image->delay = (size_t) VIPS_RINT( numbers[page_index] / 10.0 );
|
page_index = magick->position.top / magick->page_height;
|
||||||
|
if( page_index < magick->delays_length )
|
||||||
|
image->delay = (size_t) VIPS_RINT( magick->delays[page_index] / 10.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ImageMagick uses iterations like this (at least in gif save):
|
/* ImageMagick uses iterations like this (at least in gif save):
|
||||||
@ -170,7 +175,8 @@ vips_foreign_save_magick_next_image( VipsForeignSaveMagick *magick )
|
|||||||
*/
|
*/
|
||||||
image->dispose = BackgroundDispose;
|
image->dispose = BackgroundDispose;
|
||||||
|
|
||||||
if( magick_set_magick_profile( image, im, magick->exception ) ) {
|
if( !save->strip &&
|
||||||
|
magick_set_magick_profile( image, im, magick->exception ) ) {
|
||||||
magick_vips_error( class->nickname, magick->exception );
|
magick_vips_error( class->nickname, magick->exception );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
@ -340,6 +346,12 @@ vips_foreign_save_magick_build( VipsObject *object )
|
|||||||
|
|
||||||
magick->page_height = vips_image_get_page_height( im );
|
magick->page_height = vips_image_get_page_height( im );
|
||||||
|
|
||||||
|
if( vips_image_get_typeof( im, "delay" ) &&
|
||||||
|
vips_image_get_array_int( im,
|
||||||
|
"delay", &magick->delays, &magick->delays_length ) ) {
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
if( vips_sink_disc( im,
|
if( vips_sink_disc( im,
|
||||||
vips_foreign_save_magick_write_block, magick ) )
|
vips_foreign_save_magick_write_block, magick ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
@ -308,7 +308,8 @@ get_array_int( VipsImage *image, const char *field, int* n )
|
|||||||
static int
|
static int
|
||||||
extract_delay( int index, int *delays, int delays_length, int default_delay )
|
extract_delay( int index, int *delays, int delays_length, int default_delay )
|
||||||
{
|
{
|
||||||
if( delays == NULL || index > delays_length ) return( default_delay );
|
if( delays == NULL || index > delays_length )
|
||||||
|
return( default_delay );
|
||||||
return( delays[index] );
|
return( delays[index] );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +352,7 @@ write_webp_anim( VipsWebPWrite *write, VipsImage *image, int page_height )
|
|||||||
for( top = 0; top < image->Ysize; top += page_height ) {
|
for( top = 0; top < image->Ysize; top += page_height ) {
|
||||||
VipsImage *x;
|
VipsImage *x;
|
||||||
WebPPicture pic;
|
WebPPicture pic;
|
||||||
|
int page_index;
|
||||||
|
|
||||||
if( vips_crop( image, &x,
|
if( vips_crop( image, &x,
|
||||||
0, top, image->Xsize, page_height, NULL ) )
|
0, top, image->Xsize, page_height, NULL ) )
|
||||||
@ -373,7 +375,7 @@ write_webp_anim( VipsWebPWrite *write, VipsImage *image, int page_height )
|
|||||||
|
|
||||||
WebPPictureFree( &pic );
|
WebPPictureFree( &pic );
|
||||||
|
|
||||||
int page_index = top / page_height;
|
page_index = top / page_height;
|
||||||
timestamp_ms += extract_delay( page_index, delays, delays_length, default_delay );
|
timestamp_ms += extract_delay( page_index, delays, delays_length, default_delay );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
* 30/4/19
|
* 30/4/19
|
||||||
* - deprecate shrink, use scale instead, and make it a double ... this
|
* - deprecate shrink, use scale instead, and make it a double ... this
|
||||||
* lets us do faster and more accurate thumbnailing
|
* lets us do faster and more accurate thumbnailing
|
||||||
|
* 27/6/19
|
||||||
|
* - disable alpha output if all frame fill the canvas and are solid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -97,17 +99,22 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
double scale;
|
double scale;
|
||||||
|
|
||||||
|
/* Size of each frame in input image coordinates.
|
||||||
|
*/
|
||||||
|
int canvas_width;
|
||||||
|
int canvas_height;
|
||||||
|
|
||||||
|
/* Size of each frame, in scaled output image coordinates,
|
||||||
|
*/
|
||||||
|
int frame_width;
|
||||||
|
int frame_height;
|
||||||
|
|
||||||
/* Size of final output image.
|
/* Size of final output image.
|
||||||
*/
|
*/
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
|
||||||
/* Size of each frame.
|
/* TRUE if we will save the final image as RGBA.
|
||||||
*/
|
|
||||||
int frame_width;
|
|
||||||
int frame_height;
|
|
||||||
|
|
||||||
/* TRUE for RGBA.
|
|
||||||
*/
|
*/
|
||||||
int alpha;
|
int alpha;
|
||||||
|
|
||||||
@ -280,11 +287,6 @@ vips_image_paint_image( VipsImage *frame,
|
|||||||
|
|
||||||
g_assert( VIPS_IMAGE_SIZEOF_PEL( sub ) == ps );
|
g_assert( VIPS_IMAGE_SIZEOF_PEL( sub ) == ps );
|
||||||
|
|
||||||
/* Disable blend if we are not RGBA.
|
|
||||||
*/
|
|
||||||
if( frame->Bands != 4 )
|
|
||||||
blend = FALSE;
|
|
||||||
|
|
||||||
vips_rect_intersectrect( &frame_rect, &sub_rect, &ovl );
|
vips_rect_intersectrect( &frame_rect, &sub_rect, &ovl );
|
||||||
if( !vips_rect_isempty( &ovl ) ) {
|
if( !vips_rect_isempty( &ovl ) ) {
|
||||||
VipsPel *p, *q;
|
VipsPel *p, *q;
|
||||||
@ -356,6 +358,7 @@ read_free( Read *read )
|
|||||||
|
|
||||||
VIPS_FREEF( vips_tracked_close, read->fd );
|
VIPS_FREEF( vips_tracked_close, read->fd );
|
||||||
VIPS_FREE( read->filename );
|
VIPS_FREE( read->filename );
|
||||||
|
VIPS_FREE( read->delays );
|
||||||
VIPS_FREE( read );
|
VIPS_FREE( read );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
@ -418,8 +421,6 @@ static int
|
|||||||
read_header( Read *read, VipsImage *out )
|
read_header( Read *read, VipsImage *out )
|
||||||
{
|
{
|
||||||
WebPData data;
|
WebPData data;
|
||||||
int canvas_width;
|
|
||||||
int canvas_height;
|
|
||||||
int flags;
|
int flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -430,16 +431,19 @@ read_header( Read *read, VipsImage *out )
|
|||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas_width = WebPDemuxGetI( read->demux, WEBP_FF_CANVAS_WIDTH );
|
read->canvas_width =
|
||||||
canvas_height = WebPDemuxGetI( read->demux, WEBP_FF_CANVAS_HEIGHT );
|
WebPDemuxGetI( read->demux, WEBP_FF_CANVAS_WIDTH );
|
||||||
|
read->canvas_height =
|
||||||
|
WebPDemuxGetI( read->demux, WEBP_FF_CANVAS_HEIGHT );
|
||||||
|
|
||||||
/* We round-to-nearest cf. pdfload etc.
|
/* We round-to-nearest cf. pdfload etc.
|
||||||
*/
|
*/
|
||||||
read->frame_width = VIPS_RINT( canvas_width * read->scale );
|
read->frame_width = VIPS_RINT( read->canvas_width * read->scale );
|
||||||
read->frame_height = VIPS_RINT( canvas_height * read->scale );
|
read->frame_height = VIPS_RINT( read->canvas_height * read->scale );
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "webp2vips: canvas_width = %d\n", canvas_width );
|
printf( "webp2vips: canvas_width = %d\n", read->canvas_width );
|
||||||
printf( "webp2vips: canvas_height = %d\n", canvas_height );
|
printf( "webp2vips: canvas_height = %d\n", read->canvas_height );
|
||||||
printf( "webp2vips: frame_width = %d\n", read->frame_width );
|
printf( "webp2vips: frame_width = %d\n", read->frame_width );
|
||||||
printf( "webp2vips: frame_height = %d\n", read->frame_height );
|
printf( "webp2vips: frame_height = %d\n", read->frame_height );
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
@ -447,10 +451,11 @@ read_header( Read *read, VipsImage *out )
|
|||||||
flags = WebPDemuxGetI( read->demux, WEBP_FF_FORMAT_FLAGS );
|
flags = WebPDemuxGetI( read->demux, WEBP_FF_FORMAT_FLAGS );
|
||||||
|
|
||||||
read->alpha = flags & ALPHA_FLAG;
|
read->alpha = flags & ALPHA_FLAG;
|
||||||
if( read->alpha )
|
|
||||||
|
/* We do everything as RGBA and then, if we can, drop the alpha on
|
||||||
|
* save.
|
||||||
|
*/
|
||||||
read->config.output.colorspace = MODE_RGBA;
|
read->config.output.colorspace = MODE_RGBA;
|
||||||
else
|
|
||||||
read->config.output.colorspace = MODE_RGB;
|
|
||||||
|
|
||||||
if( flags & ANIMATION_FLAG ) {
|
if( flags & ANIMATION_FLAG ) {
|
||||||
int loop_count;
|
int loop_count;
|
||||||
@ -471,29 +476,39 @@ read_header( Read *read, VipsImage *out )
|
|||||||
VIPS_META_PAGE_HEIGHT, read->frame_height );
|
VIPS_META_PAGE_HEIGHT, read->frame_height );
|
||||||
|
|
||||||
if ( read->frame_count > 1) {
|
if ( read->frame_count > 1) {
|
||||||
read->delays = (int *) g_malloc( read->frame_count * sizeof(int) );
|
int i;
|
||||||
|
read->delays = (int *) g_malloc0( read->frame_count * sizeof(int) );
|
||||||
|
|
||||||
for( int i = 0; i < read->frame_count; i++ ) {
|
for( i = 0; i < read->frame_count; i++ ) {
|
||||||
if( WebPDemuxGetFrame( read->demux, i + 1, &iter ) ) {
|
if( WebPDemuxGetFrame( read->demux, i + 1, &iter ) )
|
||||||
read->delays[i] = iter.duration;
|
read->delays[i] = iter.duration;
|
||||||
} else {
|
|
||||||
read->delays[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for( int i = 0; i < read->frame_count; i++ ) {
|
for( i = 0; i < read->frame_count; i++ ) {
|
||||||
printf( "webp2vips: frame = %d; duration = %d\n", i + 1, read->delays[i] );
|
printf( "webp2vips: frame = %d; duration = %d\n", i + 1, read->delays[i] );
|
||||||
}
|
}
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
vips_image_set_array_int( out, "delay", read->delays, read->frame_count );
|
vips_image_set_array_int( out, "delay", read->delays, read->frame_count );
|
||||||
g_free( read->delays );
|
|
||||||
|
|
||||||
/* webp uses ms for delays, gif uses centiseconds.
|
/* webp uses ms for delays, gif uses centiseconds.
|
||||||
*/
|
*/
|
||||||
vips_image_set_int( out, "gif-delay",
|
vips_image_set_int( out, "gif-delay",
|
||||||
VIPS_RINT( read->delays[0] / 10.0 ) );
|
VIPS_RINT( read->delays[0] / 10.0 ) );
|
||||||
|
|
||||||
|
/* We need the alpha in an animation if:
|
||||||
|
* - any frame has transparent pixels
|
||||||
|
* - any frame doesn't fill the whole canvas.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
if( iter.has_alpha ||
|
||||||
|
iter.width != read->canvas_width ||
|
||||||
|
iter.height != read->canvas_height ) {
|
||||||
|
read->alpha = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while( WebPDemuxNextFrame( &iter ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPDemuxReleaseIterator( &iter );
|
WebPDemuxReleaseIterator( &iter );
|
||||||
@ -543,10 +558,12 @@ read_header( Read *read, VipsImage *out )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The canvas is always RGBA, we drop alpha to RGB on output if we
|
||||||
|
* can.
|
||||||
|
*/
|
||||||
read->frame = vips_image_new_memory();
|
read->frame = vips_image_new_memory();
|
||||||
vips_image_init_fields( read->frame,
|
vips_image_init_fields( read->frame,
|
||||||
read->frame_width, read->frame_height,
|
read->frame_width, read->frame_height, 4,
|
||||||
read->alpha ? 4 : 3,
|
|
||||||
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
|
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
|
||||||
VIPS_INTERPRETATION_sRGB,
|
VIPS_INTERPRETATION_sRGB,
|
||||||
1.0, 1.0 );
|
1.0, 1.0 );
|
||||||
@ -609,8 +626,7 @@ read_frame( Read *read,
|
|||||||
|
|
||||||
frame = vips_image_new_memory();
|
frame = vips_image_new_memory();
|
||||||
vips_image_init_fields( frame,
|
vips_image_init_fields( frame,
|
||||||
width, height,
|
width, height, 4,
|
||||||
read->alpha ? 4 : 3,
|
|
||||||
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
|
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
|
||||||
VIPS_INTERPRETATION_sRGB,
|
VIPS_INTERPRETATION_sRGB,
|
||||||
1.0, 1.0 );
|
1.0, 1.0 );
|
||||||
@ -750,9 +766,29 @@ read_webp_generate( VipsRegion *or,
|
|||||||
read->frame_no += 1;
|
read->frame_no += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( or->im->Bands == 4 )
|
||||||
memcpy( VIPS_REGION_ADDR( or, 0, r->top ),
|
memcpy( VIPS_REGION_ADDR( or, 0, r->top ),
|
||||||
VIPS_IMAGE_ADDR( read->frame, 0, line ),
|
VIPS_IMAGE_ADDR( read->frame, 0, line ),
|
||||||
VIPS_IMAGE_SIZEOF_LINE( read->frame ) );
|
VIPS_IMAGE_SIZEOF_LINE( read->frame ) );
|
||||||
|
else {
|
||||||
|
int x;
|
||||||
|
VipsPel *p;
|
||||||
|
VipsPel *q;
|
||||||
|
|
||||||
|
/* We know that alpha is solid, so we can just drop the 4th
|
||||||
|
* band.
|
||||||
|
*/
|
||||||
|
p = VIPS_IMAGE_ADDR( read->frame, 0, line );
|
||||||
|
q = VIPS_REGION_ADDR( or, 0, r->top );
|
||||||
|
for( x = 0; x < r->width; x++ ) {
|
||||||
|
q[0] = p[0];
|
||||||
|
q[1] = p[1];
|
||||||
|
q[2] = p[2];
|
||||||
|
|
||||||
|
q += 3;
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,7 @@ class TestForeign:
|
|||||||
def test_webp(self):
|
def test_webp(self):
|
||||||
def webp_valid(im):
|
def webp_valid(im):
|
||||||
a = im(10, 10)
|
a = im(10, 10)
|
||||||
assert_almost_equal_objects(a, [71, 166, 236])
|
assert_almost_equal_objects(a, [70, 165, 235])
|
||||||
assert im.width == 550
|
assert im.width == 550
|
||||||
assert im.height == 368
|
assert im.height == 368
|
||||||
assert im.bands == 3
|
assert im.bands == 3
|
||||||
@ -478,7 +478,7 @@ class TestForeign:
|
|||||||
im = pyvips.Image.new_from_file(WEBP_FILE)
|
im = pyvips.Image.new_from_file(WEBP_FILE)
|
||||||
buf = im.webpsave_buffer(lossless=True)
|
buf = im.webpsave_buffer(lossless=True)
|
||||||
im2 = pyvips.Image.new_from_buffer(buf, "")
|
im2 = pyvips.Image.new_from_buffer(buf, "")
|
||||||
assert im.avg() == im2.avg()
|
assert abs(im.avg() - im2.avg()) < 1
|
||||||
|
|
||||||
# higher Q should mean a bigger buffer
|
# higher Q should mean a bigger buffer
|
||||||
b1 = im.webpsave_buffer(Q=10)
|
b1 = im.webpsave_buffer(Q=10)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user