298 lines
6.7 KiB
C
298 lines
6.7 KiB
C
/* vips_msb()
|
|
*
|
|
* Copyright: 2006, The Nottingham Trent University
|
|
*
|
|
* Author: Tom Vajzovic
|
|
*
|
|
* Written on: 2006-03-13
|
|
* 27/9/06
|
|
* - removed extra im_free() in im_copy() fallback
|
|
* 4/10/06
|
|
* - removed warning on uchar fallback: it happens a lot with nip2 and
|
|
* isn't very serious
|
|
* 1/2/10
|
|
* - revised, cleanups
|
|
* - gtkdoc
|
|
* 30/5/13
|
|
* - rewrite as a class
|
|
* - add --band option, remove im_msb_band()
|
|
*/
|
|
|
|
/*
|
|
|
|
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 <glib/gi18n-lib.h>
|
|
|
|
#include <vips/vips.h>
|
|
|
|
#include "pconversion.h"
|
|
|
|
#include "bandary.h"
|
|
|
|
typedef struct _VipsMsb {
|
|
VipsConversion parent_instance;
|
|
|
|
/* Params.
|
|
*/
|
|
VipsImage *in;
|
|
int band;
|
|
|
|
/* Initial input offset.
|
|
*/
|
|
int offset;
|
|
|
|
/* Input step.
|
|
*/
|
|
int instep;
|
|
|
|
/* Need to convert signed to unsgned.
|
|
*/
|
|
gboolean sign;
|
|
|
|
} VipsMsb;
|
|
|
|
typedef VipsConversionClass VipsMsbClass;
|
|
|
|
G_DEFINE_TYPE( VipsMsb, vips_msb, VIPS_TYPE_CONVERSION );
|
|
|
|
static int
|
|
vips_msb_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
|
{
|
|
VipsRegion *ir = (VipsRegion *) seq;
|
|
VipsMsb *msb = (VipsMsb *) b;
|
|
VipsConversion *conversion = (VipsConversion *) msb;
|
|
VipsRect *r = &or->valid;
|
|
int le = r->left;
|
|
int to = r->top;
|
|
int bo = VIPS_RECT_BOTTOM( r );
|
|
int sz = r->width * conversion->out->Bands;
|
|
|
|
int x, y, i;
|
|
|
|
if( vips_region_prepare( ir, r ) )
|
|
return( -1 );
|
|
|
|
for( y = to; y < bo; y++ ) {
|
|
VipsPel *p = VIPS_REGION_ADDR( ir, le, y );
|
|
VipsPel *q = VIPS_REGION_ADDR( or, le, y );
|
|
|
|
if( msb->in->Coding == VIPS_CODING_LABQ &&
|
|
msb->band == -1 ) {
|
|
/* LABQ, no sub-band select.
|
|
*/
|
|
for( x = 0; x < r->width; x++ ) {
|
|
q[0] = p[0];
|
|
q[1] = 0x80 ^ p[1];
|
|
q[2] = 0x80 ^ p[2];
|
|
|
|
q += 4;
|
|
p += 3;
|
|
}
|
|
}
|
|
else if( msb->sign ) {
|
|
/* Copy, converting signed to unsigned.
|
|
*/
|
|
p += msb->offset;
|
|
for( i = 0; i < sz; i++ ) {
|
|
q[i] = 0x80 ^ *p;
|
|
|
|
p += msb->instep;
|
|
}
|
|
}
|
|
else {
|
|
/* Just pick out bytes.
|
|
*/
|
|
p += msb->offset;
|
|
for( i = 0; i < sz; i++ ) {
|
|
q[i] = *p;
|
|
|
|
p += msb->instep;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static int
|
|
vips_msb_build( VipsObject *object )
|
|
{
|
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
|
VipsConversion *conversion = (VipsConversion *) object;
|
|
VipsMsb *msb = (VipsMsb *) object;
|
|
|
|
int vbands;
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_msb_parent_class )->build( object ) )
|
|
return( -1 );
|
|
|
|
if( vips_check_coding_noneorlabq( class->nickname, msb->in ) ||
|
|
vips_check_int( class->nickname, msb->in ) )
|
|
return( -1 );
|
|
|
|
/* Effective number of bands this image has.
|
|
*/
|
|
vbands = msb->in->Coding == VIPS_CODING_LABQ ?
|
|
3 : msb->in->Bands;
|
|
|
|
if( msb->band > vbands - 1 ) {
|
|
vips_error( class->nickname, "%s", _( "bad band" ) );
|
|
return( -1 );
|
|
}
|
|
|
|
/* Step to next input element.
|
|
*/
|
|
msb->instep = VIPS_IMAGE_SIZEOF_ELEMENT( msb->in );
|
|
|
|
/* Offset into first band element of high order byte.
|
|
*/
|
|
msb->offset = vips_amiMSBfirst() ?
|
|
0 : VIPS_IMAGE_SIZEOF_ELEMENT( msb->in ) - 1;
|
|
|
|
/* If we're picking out a band, they need scaling up.
|
|
*/
|
|
if( msb->band != -1 ) {
|
|
msb->offset += VIPS_IMAGE_SIZEOF_ELEMENT( msb->in ) *
|
|
msb->band;
|
|
msb->instep *= msb->in->Bands;
|
|
}
|
|
|
|
/* May need to flip sign if we're picking out a band from labq.
|
|
*/
|
|
if( msb->in->Coding == VIPS_CODING_LABQ &&
|
|
msb->band > 0 )
|
|
msb->sign = TRUE;
|
|
if( msb->in->Coding == VIPS_CODING_NONE &&
|
|
!vips_band_format_isuint( msb->in->BandFmt ) )
|
|
msb->sign = TRUE;
|
|
|
|
if( msb->band == -1 &&
|
|
msb->in->BandFmt == VIPS_FORMAT_UCHAR )
|
|
return( vips_image_write( msb->in, conversion->out ) );
|
|
if( msb->band == 0 &&
|
|
msb->in->Bands == 1 &&
|
|
msb->in->BandFmt == VIPS_FORMAT_UCHAR )
|
|
return( vips_image_write( msb->in, conversion->out ) );
|
|
|
|
if( vips_image_pipelinev( conversion->out,
|
|
VIPS_DEMAND_STYLE_THINSTRIP, msb->in, NULL ) )
|
|
return( -1 );
|
|
|
|
if( msb->band != -1 )
|
|
conversion->out->Bands = 1;
|
|
else
|
|
conversion->out->Bands = vbands;
|
|
conversion->out->BandFmt = VIPS_FORMAT_UCHAR;
|
|
conversion->out->Coding = VIPS_CODING_NONE;
|
|
if( conversion->out->Bands == 1 )
|
|
conversion->out->Type = VIPS_INTERPRETATION_B_W;
|
|
else
|
|
conversion->out->Type = VIPS_INTERPRETATION_MULTIBAND;
|
|
|
|
if( vips_image_generate( conversion->out,
|
|
vips_start_one, vips_msb_gen, vips_stop_one, msb->in, msb ) )
|
|
return( -1 );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static void
|
|
vips_msb_class_init( VipsMsbClass *class )
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
|
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
|
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
|
|
|
|
gobject_class->set_property = vips_object_set_property;
|
|
gobject_class->get_property = vips_object_get_property;
|
|
|
|
vobject_class->nickname = "msb";
|
|
vobject_class->description =
|
|
_( "pick most-significant byte from an image" );
|
|
vobject_class->build = vips_msb_build;
|
|
|
|
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
|
|
|
|
VIPS_ARG_IMAGE( class, "in", 0,
|
|
_( "Input" ),
|
|
_( "Input image" ),
|
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
|
G_STRUCT_OFFSET( VipsMsb, in ) );
|
|
|
|
VIPS_ARG_INT( class, "band", 3,
|
|
_( "Band" ),
|
|
_( "Band to msb" ),
|
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
|
G_STRUCT_OFFSET( VipsMsb, band ),
|
|
0, 100000000, 0 );
|
|
|
|
}
|
|
|
|
static void
|
|
vips_msb_init( VipsMsb *msb )
|
|
{
|
|
msb->band = -1;
|
|
}
|
|
|
|
/**
|
|
* vips_msb: (method)
|
|
* @in: input image
|
|
* @out: (out): output image
|
|
* @...: %NULL-terminated list of optional named arguments
|
|
*
|
|
* Optional arguments:
|
|
*
|
|
* * @band: %gint, msb just this band
|
|
*
|
|
* Turn any integer image to 8-bit unsigned char by discarding all but the most
|
|
* significant byte. Signed values are converted to unsigned by adding 128.
|
|
*
|
|
* Use @band to make a one-band 8-bit image.
|
|
*
|
|
* This operator also works for LABQ coding.
|
|
*
|
|
* See also: vips_scale(), vips_cast().
|
|
*
|
|
* Returns: 0 on success, -1 on error.
|
|
*/
|
|
int
|
|
vips_msb( VipsImage *in, VipsImage **out, ... )
|
|
{
|
|
va_list ap;
|
|
int result;
|
|
|
|
va_start( ap, out );
|
|
result = vips_call_split( "msb", ap, in, out );
|
|
va_end( ap );
|
|
|
|
return( result );
|
|
}
|
|
|