add max and min to region_shrink
Add max and min to region_shrink. Useful with tiffsave and dzsave when the image is (for example) line art. Thanks rgluskin. See: https://github.com/libvips/libvips/issues/1490
This commit is contained in:
parent
df6ff62cde
commit
c14d7c254b
|
@ -1,6 +1,7 @@
|
||||||
24/1/20 started 8.10.0
|
24/1/20 started 8.10.0
|
||||||
- more conformat IIIF output from dzsave [regisrob]
|
- more conformat IIIF output from dzsave [regisrob]
|
||||||
- add @id to dzsave to set IIIF id property [regisrob]
|
- add @id to dzsave to set IIIF id property [regisrob]
|
||||||
|
- add max and min to region shrink [rgluskin]
|
||||||
|
|
||||||
20/6/19 started 8.9.1
|
20/6/19 started 8.9.1
|
||||||
- don't use the new source loaders for new_from_file or new_from_buffer, it
|
- don't use the new source loaders for new_from_file or new_from_buffer, it
|
||||||
|
|
|
@ -60,6 +60,8 @@ extern "C" {
|
||||||
* @VIPS_REGION_SHRINK_MEAN: use the average
|
* @VIPS_REGION_SHRINK_MEAN: use the average
|
||||||
* @VIPS_REGION_SHRINK_MEDIAN: use the median
|
* @VIPS_REGION_SHRINK_MEDIAN: use the median
|
||||||
* @VIPS_REGION_SHRINK_MODE: use the mode
|
* @VIPS_REGION_SHRINK_MODE: use the mode
|
||||||
|
* @VIPS_REGION_SHRINK_MAX: use the maximum
|
||||||
|
* @VIPS_REGION_SHRINK_MIN: use the minimum
|
||||||
*
|
*
|
||||||
* How to calculate the output pixels when shrinking a 2x2 region.
|
* How to calculate the output pixels when shrinking a 2x2 region.
|
||||||
*/
|
*/
|
||||||
|
@ -67,6 +69,8 @@ typedef enum {
|
||||||
VIPS_REGION_SHRINK_MEAN,
|
VIPS_REGION_SHRINK_MEAN,
|
||||||
VIPS_REGION_SHRINK_MEDIAN,
|
VIPS_REGION_SHRINK_MEDIAN,
|
||||||
VIPS_REGION_SHRINK_MODE,
|
VIPS_REGION_SHRINK_MODE,
|
||||||
|
VIPS_REGION_SHRINK_MAX,
|
||||||
|
VIPS_REGION_SHRINK_MIN,
|
||||||
VIPS_REGION_SHRINK_LAST
|
VIPS_REGION_SHRINK_LAST
|
||||||
} VipsRegionShrink;
|
} VipsRegionShrink;
|
||||||
|
|
||||||
|
|
|
@ -903,6 +903,8 @@ vips_region_shrink_get_type( void )
|
||||||
{VIPS_REGION_SHRINK_MEAN, "VIPS_REGION_SHRINK_MEAN", "mean"},
|
{VIPS_REGION_SHRINK_MEAN, "VIPS_REGION_SHRINK_MEAN", "mean"},
|
||||||
{VIPS_REGION_SHRINK_MEDIAN, "VIPS_REGION_SHRINK_MEDIAN", "median"},
|
{VIPS_REGION_SHRINK_MEDIAN, "VIPS_REGION_SHRINK_MEDIAN", "median"},
|
||||||
{VIPS_REGION_SHRINK_MODE, "VIPS_REGION_SHRINK_MODE", "mode"},
|
{VIPS_REGION_SHRINK_MODE, "VIPS_REGION_SHRINK_MODE", "mode"},
|
||||||
|
{VIPS_REGION_SHRINK_MAX, "VIPS_REGION_SHRINK_MAX", "max"},
|
||||||
|
{VIPS_REGION_SHRINK_MIN, "VIPS_REGION_SHRINK_MIN", "min"},
|
||||||
{VIPS_REGION_SHRINK_LAST, "VIPS_REGION_SHRINK_LAST", "last"},
|
{VIPS_REGION_SHRINK_LAST, "VIPS_REGION_SHRINK_LAST", "last"},
|
||||||
{0, NULL, NULL}
|
{0, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
|
@ -611,7 +611,7 @@ vips_operation_get_flags( VipsOperation *operation )
|
||||||
void
|
void
|
||||||
vips_operation_class_print_usage( VipsOperationClass *operation_class )
|
vips_operation_class_print_usage( VipsOperationClass *operation_class )
|
||||||
{
|
{
|
||||||
char str[2048];
|
char str[4096];
|
||||||
VipsBuf buf = VIPS_BUF_STATIC( str );
|
VipsBuf buf = VIPS_BUF_STATIC( str );
|
||||||
|
|
||||||
operation_class->usage( operation_class, &buf );
|
operation_class->usage( operation_class, &buf );
|
||||||
|
|
|
@ -1254,50 +1254,6 @@ vips_region_shrink_uncoded_mean( VipsRegion *from,
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate area @target in @to using pixels in @from. Non-complex.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
vips_region_shrink_uncoded_median( VipsRegion *from,
|
|
||||||
VipsRegion *to, const VipsRect *target )
|
|
||||||
{
|
|
||||||
int ls = VIPS_REGION_LSKIP( from );
|
|
||||||
int ps = VIPS_IMAGE_SIZEOF_PEL( from->im );
|
|
||||||
int nb = from->im->Bands;
|
|
||||||
|
|
||||||
int x, y, z;
|
|
||||||
|
|
||||||
for( y = 0; y < target->height; y++ ) {
|
|
||||||
VipsPel *p = VIPS_REGION_ADDR( from,
|
|
||||||
target->left * 2, (target->top + y) * 2 );
|
|
||||||
VipsPel *q = VIPS_REGION_ADDR( to,
|
|
||||||
target->left, target->top + y );
|
|
||||||
|
|
||||||
/* Process this line of pels.
|
|
||||||
*/
|
|
||||||
switch( from->im->BandFmt ) {
|
|
||||||
case VIPS_FORMAT_UCHAR:
|
|
||||||
SHRINK_TYPE_MEDIAN( unsigned char ); break;
|
|
||||||
case VIPS_FORMAT_CHAR:
|
|
||||||
SHRINK_TYPE_MEDIAN( signed char ); break;
|
|
||||||
case VIPS_FORMAT_USHORT:
|
|
||||||
SHRINK_TYPE_MEDIAN( unsigned short ); break;
|
|
||||||
case VIPS_FORMAT_SHORT:
|
|
||||||
SHRINK_TYPE_MEDIAN( signed short ); break;
|
|
||||||
case VIPS_FORMAT_UINT:
|
|
||||||
SHRINK_TYPE_MEDIAN( unsigned int ); break;
|
|
||||||
case VIPS_FORMAT_INT:
|
|
||||||
SHRINK_TYPE_MEDIAN( signed int ); break;
|
|
||||||
case VIPS_FORMAT_FLOAT:
|
|
||||||
SHRINK_TYPE_MEDIAN( float ); break;
|
|
||||||
case VIPS_FORMAT_DOUBLE:
|
|
||||||
SHRINK_TYPE_MEDIAN( double ); break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This method is implemented so as to perform well and to always select an
|
/* This method is implemented so as to perform well and to always select an
|
||||||
* output pixel from one of the input pixels. As such we make only the
|
* output pixel from one of the input pixels. As such we make only the
|
||||||
* following guarantees:
|
* following guarantees:
|
||||||
|
@ -1334,50 +1290,94 @@ vips_region_shrink_uncoded_median( VipsRegion *from,
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate area @target in @to using pixels in @from. Non-complex.
|
#define SHRINK_TYPE_MAX( TYPE ) { \
|
||||||
*/
|
for( x = 0; x < target->width; x++ ) { \
|
||||||
static void
|
TYPE *tp = (TYPE *) p; \
|
||||||
vips_region_shrink_uncoded_mode( VipsRegion *from,
|
TYPE *tp1 = (TYPE *) (p + ls); \
|
||||||
VipsRegion *to, const VipsRect *target )
|
TYPE *tq = (TYPE *) q; \
|
||||||
{
|
\
|
||||||
int ls = VIPS_REGION_LSKIP( from );
|
for( z = 0; z < nb; z++ ) { \
|
||||||
int ps = VIPS_IMAGE_SIZEOF_PEL( from->im );
|
tq[z] = VIPS_MAX( \
|
||||||
int nb = from->im->Bands;
|
VIPS_MAX( tp[z], tp[z + nb] ), \
|
||||||
|
VIPS_MAX( tp1[z], tp1[z + nb] ) \
|
||||||
int x, y, z;
|
); \
|
||||||
|
} \
|
||||||
for( y = 0; y < target->height; y++ ) {
|
\
|
||||||
VipsPel *p = VIPS_REGION_ADDR( from,
|
/* Move on two pels in input. \
|
||||||
target->left * 2, (target->top + y) * 2 );
|
*/ \
|
||||||
VipsPel *q = VIPS_REGION_ADDR( to,
|
p += ps << 1; \
|
||||||
target->left, target->top + y );
|
q += ps; \
|
||||||
|
} \
|
||||||
/* Process this line of pels.
|
|
||||||
*/
|
|
||||||
switch( from->im->BandFmt ) {
|
|
||||||
case VIPS_FORMAT_UCHAR:
|
|
||||||
SHRINK_TYPE_MODE( unsigned char ); break;
|
|
||||||
case VIPS_FORMAT_CHAR:
|
|
||||||
SHRINK_TYPE_MODE( signed char ); break;
|
|
||||||
case VIPS_FORMAT_USHORT:
|
|
||||||
SHRINK_TYPE_MODE( unsigned short ); break;
|
|
||||||
case VIPS_FORMAT_SHORT:
|
|
||||||
SHRINK_TYPE_MODE( signed short ); break;
|
|
||||||
case VIPS_FORMAT_UINT:
|
|
||||||
SHRINK_TYPE_MODE( unsigned int ); break;
|
|
||||||
case VIPS_FORMAT_INT:
|
|
||||||
SHRINK_TYPE_MODE( signed int ); break;
|
|
||||||
case VIPS_FORMAT_FLOAT:
|
|
||||||
SHRINK_TYPE_MODE( float ); break;
|
|
||||||
case VIPS_FORMAT_DOUBLE:
|
|
||||||
SHRINK_TYPE_MODE( double ); break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SHRINK_TYPE_MIN( TYPE ) { \
|
||||||
|
for( x = 0; x < target->width; x++ ) { \
|
||||||
|
TYPE *tp = (TYPE *) p; \
|
||||||
|
TYPE *tp1 = (TYPE *) (p + ls); \
|
||||||
|
TYPE *tq = (TYPE *) q; \
|
||||||
|
\
|
||||||
|
for( z = 0; z < nb; z++ ) { \
|
||||||
|
tq[z] = VIPS_MIN( \
|
||||||
|
VIPS_MIN( tp[z], tp[z + nb] ), \
|
||||||
|
VIPS_MIN( tp1[z], tp1[z + nb] ) \
|
||||||
|
); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Move on two pels in input. \
|
||||||
|
*/ \
|
||||||
|
p += ps << 1; \
|
||||||
|
q += ps; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VIPS_REGION_SHRINK( OP ) \
|
||||||
|
static void \
|
||||||
|
vips_region_shrink_uncoded_ ## OP( VipsRegion *from, \
|
||||||
|
VipsRegion *to, const VipsRect *target ) \
|
||||||
|
{ \
|
||||||
|
int ls = VIPS_REGION_LSKIP( from ); \
|
||||||
|
int ps = VIPS_IMAGE_SIZEOF_PEL( from->im ); \
|
||||||
|
int nb = from->im->Bands; \
|
||||||
|
\
|
||||||
|
int x, y, z; \
|
||||||
|
\
|
||||||
|
for( y = 0; y < target->height; y++ ) { \
|
||||||
|
VipsPel *p = VIPS_REGION_ADDR( from, \
|
||||||
|
target->left * 2, (target->top + y) * 2 ); \
|
||||||
|
VipsPel *q = VIPS_REGION_ADDR( to, \
|
||||||
|
target->left, target->top + y ); \
|
||||||
|
\
|
||||||
|
/* Process this line of pels. \
|
||||||
|
*/ \
|
||||||
|
switch( from->im->BandFmt ) { \
|
||||||
|
case VIPS_FORMAT_UCHAR: \
|
||||||
|
SHRINK_TYPE_ ## OP( unsigned char ); break; \
|
||||||
|
case VIPS_FORMAT_CHAR: \
|
||||||
|
SHRINK_TYPE_ ## OP( signed char ); break; \
|
||||||
|
case VIPS_FORMAT_USHORT: \
|
||||||
|
SHRINK_TYPE_ ## OP( unsigned short ); break; \
|
||||||
|
case VIPS_FORMAT_SHORT: \
|
||||||
|
SHRINK_TYPE_ ## OP( signed short ); break; \
|
||||||
|
case VIPS_FORMAT_UINT: \
|
||||||
|
SHRINK_TYPE_ ## OP( unsigned int ); break; \
|
||||||
|
case VIPS_FORMAT_INT: \
|
||||||
|
SHRINK_TYPE_ ## OP( signed int ); break; \
|
||||||
|
case VIPS_FORMAT_FLOAT: \
|
||||||
|
SHRINK_TYPE_ ## OP( float ); break; \
|
||||||
|
case VIPS_FORMAT_DOUBLE: \
|
||||||
|
SHRINK_TYPE_ ## OP( double ); break; \
|
||||||
|
\
|
||||||
|
default: \
|
||||||
|
g_assert_not_reached(); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
VIPS_REGION_SHRINK( MAX );
|
||||||
|
VIPS_REGION_SHRINK( MIN );
|
||||||
|
VIPS_REGION_SHRINK( MODE );
|
||||||
|
VIPS_REGION_SHRINK( MEDIAN );
|
||||||
|
|
||||||
/* Generate area @target in @to using pixels in @from. Non-complex.
|
/* Generate area @target in @to using pixels in @from. Non-complex.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
|
@ -1388,11 +1388,21 @@ vips_region_shrink_uncoded( VipsRegion *from,
|
||||||
case VIPS_REGION_SHRINK_MEAN:
|
case VIPS_REGION_SHRINK_MEAN:
|
||||||
vips_region_shrink_uncoded_mean( from, to, target );
|
vips_region_shrink_uncoded_mean( from, to, target );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIPS_REGION_SHRINK_MEDIAN:
|
case VIPS_REGION_SHRINK_MEDIAN:
|
||||||
vips_region_shrink_uncoded_median( from, to, target );
|
vips_region_shrink_uncoded_MEDIAN( from, to, target );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIPS_REGION_SHRINK_MODE:
|
case VIPS_REGION_SHRINK_MODE:
|
||||||
vips_region_shrink_uncoded_mode( from, to, target );
|
vips_region_shrink_uncoded_MODE( from, to, target );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VIPS_REGION_SHRINK_MAX:
|
||||||
|
vips_region_shrink_uncoded_MAX( from, to, target );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VIPS_REGION_SHRINK_MIN:
|
||||||
|
vips_region_shrink_uncoded_MIN( from, to, target );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue