1 /*
2 * imagesource_rotate.cpp - filter to rotate an image through
3 * 0, 90, 180 or 270 degrees.
4 * supports random access, unless source image doesn't, and rotation is zero.
5 *
6 * Copyright (c) 2004 by Alastair M. Robinson
7 * Distributed under the terms of the GNU General Public License -
8 * see the file named "COPYING" for more details.
9 *
10 */
11
12 #include <iostream>
13
14 #include <stdlib.h>
15
16 #include "../support/debug.h"
17
18 #include "imagesource_rotate.h"
19
20 using namespace std;
21
~ImageSource_Rotate()22 ImageSource_Rotate::~ImageSource_Rotate()
23 {
24 if(source)
25 delete source;
26 if(spanbuffer)
27 free(spanbuffer);
28 }
29
30
GetRow(int row)31 ISDataType *ImageSource_Rotate::GetRow(int row)
32 {
33 int x;
34 int firstrow,lastrow;
35 ISDataType *dst;
36 ISDataType *src;
37 ISDataType c;
38
39 switch(rotation)
40 {
41 case 0:
42 // FIXME - if source doesn't support random access, image needs
43 // to be cached.
44 return(source->GetRow(row));
45 break;
46 case 90:
47 if((row<spanfirstrow) || (row>=(spanfirstrow+spanrows)))
48 {
49 spanfirstrow=row;
50
51 firstrow=row;
52 lastrow=row+spanrows;
53 if(lastrow>height)
54 lastrow=height;
55
56 for(int i=0;i<source->height;++i)
57 {
58 src=source->GetRow(i);
59 dst=spanbuffer+samplesperpixel*i;
60 switch(samplesperpixel)
61 {
62 case 1:
63 for(x=firstrow;x<lastrow;++x)
64 {
65 int sx=(source->width-1)-x;
66 c=src[sx];
67 dst[(x-firstrow)*samplesperrow]=c;
68 }
69 break;
70 case 3:
71 for(x=firstrow;x<lastrow;++x)
72 {
73 int sx=(source->width-1)-x;
74 c=src[sx*3];
75 dst[(x-firstrow)*samplesperrow]=c;
76 c=src[sx*3+1];
77 dst[(x-firstrow)*samplesperrow+1]=c;
78 c=src[sx*3+2];
79 dst[(x-firstrow)*samplesperrow+2]=c;
80 }
81 break;
82 case 4:
83 for(x=firstrow;x<lastrow;++x)
84 {
85 int sx=(source->width-1)-x;
86 c=src[sx*4];
87 dst[(x-firstrow)*samplesperrow]=c;
88 c=src[sx*4+1];
89 dst[(x-firstrow)*samplesperrow+1]=c;
90 c=src[sx*4+2];
91 dst[(x-firstrow)*samplesperrow+2]=c;
92 c=src[sx*4+3];
93 dst[(x-firstrow)*samplesperrow+3]=c;
94 }
95 break;
96 default:
97 for(x=firstrow;x<lastrow;++x)
98 {
99 int sx=(source->width-1)-x;
100 for(int s=0;s<samplesperpixel;++s)
101 {
102 c=src[sx*samplesperpixel+s];
103 dst[(x-firstrow)*samplesperrow+s]=c;
104 }
105 }
106 break;
107 }
108 if(TestBreak())
109 i=source->height;
110 }
111 }
112 row-=spanfirstrow;
113 return(spanbuffer+row*samplesperrow);
114 break;
115 case 180:
116 // FIXME: support partial image caching here.
117
118 if((row<spanfirstrow) || (row>=(spanfirstrow+spanrows)))
119 {
120 spanfirstrow=row;
121
122 firstrow=row;
123 lastrow=row+spanrows;
124 if(lastrow>height)
125 lastrow=height;
126
127 for(int y=0;y<height;++y)
128 {
129 src=source->GetRow(y);
130 dst=spanbuffer+((height-1)-y)*samplesperrow;
131 switch(samplesperpixel)
132 {
133 case 1:
134 for(x=0;x<width;++x)
135 {
136 int sx=(width-1)-x;
137 c=src[sx];
138 dst[x]=c;
139 }
140 break;
141 case 3:
142 for(x=0;x<width;++x)
143 {
144 int sx=(width-1)-x;
145 c=src[sx*3];
146 dst[x*3]=c;
147 c=src[sx*3+1];
148 dst[x*3+1]=c;
149 c=src[sx*3+2];
150 dst[x*3+2]=c;
151 }
152 break;
153 case 4:
154 for(x=0;x<width;++x)
155 {
156 int sx=(width-1)-x;
157 c=src[sx*4];
158 dst[x*4]=c;
159 c=src[sx*4+1];
160 dst[x*4+1]=c;
161 c=src[sx*4+2];
162 dst[x*4+2]=c;
163 c=src[sx*4+3];
164 dst[x*4+3]=c;
165 }
166 break;
167 default:
168 for(x=firstrow;x<lastrow;++x)
169 {
170 int sx=(width-1)-x;
171 for(int s=0;s<samplesperpixel;++s)
172 {
173 c=src[sx*samplesperpixel+s];
174 dst[x*samplesperrow+s]=c;
175 }
176 }
177 break;
178 }
179 if(TestBreak())
180 y=source->height;
181 }
182 }
183 row-=spanfirstrow;
184 return(spanbuffer+row*samplesperrow);
185 break;
186 case 270:
187 if((row<spanfirstrow) || (row>=(spanfirstrow+spanrows)))
188 {
189 spanfirstrow=row;
190
191 firstrow=row;
192 lastrow=row+spanrows;
193 if(lastrow>height)
194 lastrow=height;
195
196 for(int i=source->height-1;i>=0;--i)
197 {
198 src=source->GetRow((source->height-1)-i);
199 dst=spanbuffer+samplesperpixel*i;
200 switch(samplesperpixel)
201 {
202 case 1:
203 for(x=firstrow;x<lastrow;++x)
204 {
205 int sx=x;
206 c=src[sx];
207 dst[(x-firstrow)*samplesperrow]=c;
208 }
209 break;
210 case 3:
211 for(x=firstrow;x<lastrow;++x)
212 {
213 int sx=x;
214 c=src[sx*3];
215 dst[(x-firstrow)*samplesperrow]=c;
216 c=src[sx*3+1];
217 dst[(x-firstrow)*samplesperrow+1]=c;
218 c=src[sx*3+2];
219 dst[(x-firstrow)*samplesperrow+2]=c;
220 }
221 break;
222 case 4:
223 for(x=firstrow;x<lastrow;++x)
224 {
225 int sx=x;
226 c=src[sx*4];
227 dst[(x-firstrow)*samplesperrow]=c;
228 c=src[sx*4+1];
229 dst[(x-firstrow)*samplesperrow+1]=c;
230 c=src[sx*4+2];
231 dst[(x-firstrow)*samplesperrow+2]=c;
232 c=src[sx*4+3];
233 dst[(x-firstrow)*samplesperrow+3]=c;
234 }
235 break;
236 default:
237 for(x=firstrow;x<lastrow;++x)
238 {
239 int sx=x;
240 for(int s=0;s<samplesperpixel;++s)
241 {
242 c=src[sx*samplesperpixel+s];
243 dst[(x-firstrow)*samplesperrow+s]=c;
244 }
245 }
246 break;
247 }
248 if(TestBreak())
249 i=source->height;
250 }
251 }
252 row-=spanfirstrow;
253 return(spanbuffer+row*samplesperrow);
254 break;
255 default:
256 throw "Currently only multples of 90 degrees are supported";
257 }
258 return(rowbuffer);
259 }
260
261
ImageSource_Rotate(ImageSource * source,int rotation,int spanrows)262 ImageSource_Rotate::ImageSource_Rotate(ImageSource *source,int rotation,int spanrows)
263 : ImageSource_Interruptible(source), source(source), rotation(rotation), spanfirstrow(0), spanrows(spanrows), spanbuffer(NULL)
264 {
265 rowbuffer=NULL;
266 switch(rotation)
267 {
268 case 0:
269 case 180:
270 break;
271 case 90:
272 case 270:
273 width=source->height;
274 height=source->width;
275 xres=source->yres;
276 yres=source->xres;
277 break;
278 default:
279 throw "Only multiples of 90 degrees are supported\n";
280 break;
281 }
282
283 switch(rotation)
284 {
285 case 0:
286 case 180:
287 Debug[COMMENT] << "Rotate: caching entire image for 180 degree rotation" << endl;
288 this->spanrows=source->height+1;
289 break;
290 case 90:
291 case 270:
292 if(!source->randomaccess)
293 {
294 Debug[COMMENT] << "Rotate: source doesn't support random access - caching entire image" << endl;
295 this->spanrows=source->width+1;
296 }
297 break;
298 }
299
300 spanfirstrow=-this->spanrows-1;
301 samplesperrow=width*samplesperpixel;
302
303 Debug[TRACE] << "Span buffer will be " << this->spanrows << " high" << endl;
304
305 if((rotation==90) || (rotation==270) || (rotation==180))
306 spanbuffer=(ISDataType *)malloc(this->spanrows*(sizeof(ISDataType)*samplesperrow));
307 else
308 MakeRowBuffer();
309 currentrow=-1;
310 if(rotation==0)
311 randomaccess=source->randomaccess;
312 else
313 randomaccess=true;
314 }
315