1 /* Swap image byte order.
2  *
3  * 5/6/15
4  * 	- from copy.c
5  * 27/1/16
6  * 	- don't swap coded images
7  */
8 
9 /*
10 
11     This file is part of VIPS.
12 
13     VIPS is free software; you can redistribute it and/or modify
14     it under the terms of the GNU Lesser General Public License as published by
15     the Free Software Foundation; either version 2 of the License, or
16     (at your option) any later version.
17 
18     This program is distributed in the hope that it will be useful,
19     but WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21     GNU Lesser General Public License for more details.
22 
23     You should have received a copy of the GNU Lesser General Public License
24     along with this program; if not, write to the Free Software
25     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26     02110-1301  USA
27 
28  */
29 
30 /*
31 
32     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
33 
34  */
35 
36 /*
37 #define VIPS_DEBUG
38  */
39 
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif /*HAVE_CONFIG_H*/
43 #include <vips/intl.h>
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <math.h>
49 
50 #include <vips/vips.h>
51 #include <vips/internal.h>
52 #include <vips/debug.h>
53 
54 #include "pconversion.h"
55 
56 typedef struct _VipsByteswap {
57 	VipsConversion parent_instance;
58 
59 	/* The input image.
60 	 */
61 	VipsImage *in;
62 
63 } VipsByteswap;
64 
65 typedef VipsConversionClass VipsByteswapClass;
66 
67 G_DEFINE_TYPE( VipsByteswap, vips_byteswap, VIPS_TYPE_CONVERSION );
68 
69 /* Swap pairs of bytes.
70  */
71 static void
vips_byteswap_swap2(VipsPel * in,VipsPel * out,int width,VipsImage * im)72 vips_byteswap_swap2( VipsPel *in, VipsPel *out, int width, VipsImage *im )
73 {
74 	guint16 *p = (guint16 *) in;
75 	guint16 *q = (guint16 *) out;
76         int sz = (VIPS_IMAGE_SIZEOF_PEL( im ) * width) / 2;
77 
78         int x;
79 
80         for( x = 0; x < sz; x++ )
81 		q[x] = GUINT16_SWAP_LE_BE( p[x] );
82 }
83 
84 /* Swap 4- of bytes.
85  */
86 static void
vips_byteswap_swap4(VipsPel * in,VipsPel * out,int width,VipsImage * im)87 vips_byteswap_swap4( VipsPel *in, VipsPel *out, int width, VipsImage *im )
88 {
89 	guint32 *p = (guint32 *) in;
90 	guint32 *q = (guint32 *) out;
91         int sz = (VIPS_IMAGE_SIZEOF_PEL( im ) * width) / 4;
92 
93         int x;
94 
95         for( x = 0; x < sz; x++ )
96 		q[x] = GUINT32_SWAP_LE_BE( p[x] );
97 }
98 
99 /* Swap 8- of bytes.
100  */
101 static void
vips_byteswap_swap8(VipsPel * in,VipsPel * out,int width,VipsImage * im)102 vips_byteswap_swap8( VipsPel *in, VipsPel *out, int width, VipsImage *im )
103 {
104 	guint64 *p = (guint64 *) in;
105 	guint64 *q = (guint64 *) out;
106         int sz = (VIPS_IMAGE_SIZEOF_PEL( im ) * width) / 8;
107 
108         int x;
109 
110         for( x = 0; x < sz; x++ )
111 		q[x] = GUINT64_SWAP_LE_BE( p[x] );
112 }
113 
114 typedef void (*SwapFn)( VipsPel *in, VipsPel *out, int width, VipsImage *im );
115 
116 static SwapFn vips_byteswap_swap_fn[] = {
117 	NULL, 			/* VIPS_FORMAT_UCHAR = 0, */
118 	NULL, 			/* VIPS_FORMAT_CHAR = 1, */
119 	vips_byteswap_swap2,	/* VIPS_FORMAT_USHORT = 2, */
120 	vips_byteswap_swap2, 	/* VIPS_FORMAT_SHORT = 3, */
121 	vips_byteswap_swap4, 	/* VIPS_FORMAT_UINT = 4, */
122 	vips_byteswap_swap4, 	/* VIPS_FORMAT_INT = 5, */
123 	vips_byteswap_swap4, 	/* VIPS_FORMAT_FLOAT = 6, */
124 	vips_byteswap_swap4, 	/* VIPS_FORMAT_COMPLEX = 7, */
125 	vips_byteswap_swap8, 	/* VIPS_FORMAT_DOUBLE = 8, */
126 	vips_byteswap_swap8 	/* VIPS_FORMAT_DPCOMPLEX = 9, */
127 };
128 
129 /* Byteswap, turning bands into the x axis.
130  */
131 static int
vips_byteswap_gen(VipsRegion * or,void * seq,void * a,void * b,gboolean * stop)132 vips_byteswap_gen( VipsRegion *or,
133 	void *seq, void *a, void *b, gboolean *stop )
134 {
135 	VipsRegion *ir = (VipsRegion *) seq;
136 	VipsImage *im = ir->im;
137 	VipsRect *r = &or->valid;
138 	SwapFn swap = vips_byteswap_swap_fn[im->BandFmt];
139 
140 	int y;
141 
142 	g_assert( swap );
143 
144 	if( vips_region_prepare( ir, r ) )
145 		return( -1 );
146 
147 	for( y = 0; y < r->height; y++ ) {
148 		VipsPel *p = VIPS_REGION_ADDR( ir, r->left, r->top + y );
149 		VipsPel *q = VIPS_REGION_ADDR( or, r->left, r->top + y );
150 
151 		swap( p, q, r->width, im );
152 	}
153 
154 	return( 0 );
155 }
156 
157 static int
vips_byteswap_build(VipsObject * object)158 vips_byteswap_build( VipsObject *object )
159 {
160 	VipsConversion *conversion = VIPS_CONVERSION( object );
161 	VipsByteswap *byteswap = (VipsByteswap *) object;
162 
163 	if( VIPS_OBJECT_CLASS( vips_byteswap_parent_class )->build( object ) )
164 		return( -1 );
165 
166 	/* Lots of images don't need swapping.
167 	 */
168 	if( byteswap->in->Coding != VIPS_CODING_NONE ||
169 		!vips_byteswap_swap_fn[byteswap->in->BandFmt] )
170 		return( vips_image_write( byteswap->in, conversion->out ) );
171 
172 	if( vips_image_pio_input( byteswap->in ) )
173 		return( -1 );
174 
175 	if( vips_image_pipelinev( conversion->out,
176 		VIPS_DEMAND_STYLE_THINSTRIP, byteswap->in, NULL ) )
177 		return( -1 );
178 
179 	if( vips_image_generate( conversion->out,
180 		vips_start_one, vips_byteswap_gen, vips_stop_one,
181 		byteswap->in, byteswap ) )
182 		return( -1 );
183 
184 	return( 0 );
185 }
186 
187 static void
vips_byteswap_class_init(VipsByteswapClass * class)188 vips_byteswap_class_init( VipsByteswapClass *class )
189 {
190 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
191 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
192 	VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
193 
194 	VIPS_DEBUG_MSG( "vips_byteswap_class_init\n" );
195 
196 	gobject_class->set_property = vips_object_set_property;
197 	gobject_class->get_property = vips_object_get_property;
198 
199 	vobject_class->nickname = "byteswap";
200 	vobject_class->description = _( "byteswap an image" );
201 	vobject_class->build = vips_byteswap_build;
202 
203 	operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
204 
205 	VIPS_ARG_IMAGE( class, "in", 1,
206 		_( "Input" ),
207 		_( "Input image" ),
208 		VIPS_ARGUMENT_REQUIRED_INPUT,
209 		G_STRUCT_OFFSET( VipsByteswap, in ) );
210 
211 }
212 
213 static void
vips_byteswap_init(VipsByteswap * byteswap)214 vips_byteswap_init( VipsByteswap *byteswap )
215 {
216 }
217 
218 /**
219  * vips_byteswap: (method)
220  * @in: input image
221  * @out: (out): output image
222  * @...: %NULL-terminated list of optional named arguments
223  *
224  * Swap the byte order in an image.
225  *
226  * See also: vips_rawload().
227  *
228  * Returns: 0 on success, -1 on error.
229  */
230 int
vips_byteswap(VipsImage * in,VipsImage ** out,...)231 vips_byteswap( VipsImage *in, VipsImage **out, ... )
232 {
233 	va_list ap;
234 	int result;
235 
236 	va_start( ap, out );
237 	result = vips_call_split( "byteswap", ap, in, out );
238 	va_end( ap );
239 
240 	return( result );
241 }
242 
243 /* Convenience function: swap if @swap is %TRUE, otherwise copy.
244  */
245 int
vips__byteswap_bool(VipsImage * in,VipsImage ** out,gboolean swap)246 vips__byteswap_bool( VipsImage *in, VipsImage **out, gboolean swap )
247 {
248 	if( swap )
249 		return( vips_byteswap( in, out, NULL ) );
250 	else
251 		return( vips_copy( in, out, NULL ) );
252 }
253