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