1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <string.h>
5
6 #include "readers.h"
7 #include "op.h"
8 #include "filter.h"
9
10 /* ----------------------------------------------------------------------- */
11 /* functions */
12
13 static char op_none_data;
14
15 static void
op_flip_vert(struct ida_image * src,struct ida_rect * rect,unsigned char * dst,int line,void * data)16 op_flip_vert(struct ida_image *src, struct ida_rect *rect,
17 unsigned char *dst, int line, void *data)
18 {
19 char *scanline;
20
21 scanline = ida_image_scanline(src, src->i.height - line - 1);
22 memcpy(dst, scanline, ida_image_stride(src));
23 }
24
25 static void
op_flip_horz(struct ida_image * src,struct ida_rect * rect,unsigned char * dst,int line,void * data)26 op_flip_horz(struct ida_image *src, struct ida_rect *rect,
27 unsigned char *dst, int line, void *data)
28 {
29 char *scanline;
30 unsigned int i, bpp;
31
32 bpp = ida_image_bpp(src);
33 scanline = ida_image_scanline(src, line);
34 scanline += src->i.width * bpp;
35 for (i = 0; i < src->i.width; i++) {
36 scanline -= bpp;
37 memcpy(dst, scanline, bpp);
38 dst += bpp;
39 }
40 }
41
42 static void*
op_rotate_init(struct ida_image * src,struct ida_rect * rect,struct ida_image_info * i,void * parm)43 op_rotate_init(struct ida_image *src, struct ida_rect *rect,
44 struct ida_image_info *i, void *parm)
45 {
46 *i = src->i;
47 i->height = src->i.width;
48 i->width = src->i.height;
49 i->dpi = src->i.dpi;
50 return &op_none_data;
51 }
52
53 static void
op_rotate_cw(struct ida_image * src,struct ida_rect * rect,unsigned char * dst,int line,void * data)54 op_rotate_cw(struct ida_image *src, struct ida_rect *rect,
55 unsigned char *dst, int line, void *data)
56 {
57 char *pix;
58 unsigned int i, bpp;
59
60 bpp = ida_image_bpp(src);
61 pix = ida_image_scanline(src, src->i.height) + line * bpp;
62 for (i = 0; i < src->i.height; i++) {
63 pix -= ida_image_stride(src);
64 memcpy(dst, pix, bpp);
65 dst += bpp;
66 }
67 }
68
69 static void
op_rotate_ccw(struct ida_image * src,struct ida_rect * rect,unsigned char * dst,int line,void * data)70 op_rotate_ccw(struct ida_image *src, struct ida_rect *rect,
71 unsigned char *dst, int line, void *data)
72 {
73 char *pix;
74 unsigned int i, bpp;
75
76 bpp = ida_image_bpp(src);
77 pix = ida_image_scanline(src, 0) + (src->i.width-line-1) * bpp;
78 for (i = 0; i < src->i.height; i++) {
79 memcpy(dst, pix, bpp);
80 pix += ida_image_stride(src);
81 dst += bpp;
82 }
83 }
84
85 static void
op_invert(struct ida_image * src,struct ida_rect * rect,unsigned char * dst,int line,void * data)86 op_invert(struct ida_image *src, struct ida_rect *rect,
87 unsigned char *dst, int line, void *data)
88 {
89 unsigned char *scanline;
90 int i, bpp;
91
92 bpp = ida_image_bpp(src);
93 scanline = ida_image_scanline(src, line);
94 memcpy(dst, scanline, ida_image_stride(src));
95 if (line < rect->y1 || line >= rect->y2)
96 return;
97 dst += bpp*rect->x1;
98 scanline += bpp*rect->x1;
99 for (i = rect->x1; i < rect->x2; i++) {
100
101 /* FIXME for bpp != 3 */
102 dst[0] = 255-scanline[0];
103 dst[1] = 255-scanline[1];
104 dst[2] = 255-scanline[2];
105
106 scanline += bpp;
107 dst += bpp;
108 }
109 }
110
111 static void*
op_crop_init(struct ida_image * src,struct ida_rect * rect,struct ida_image_info * i,void * parm)112 op_crop_init(struct ida_image *src, struct ida_rect *rect,
113 struct ida_image_info *i, void *parm)
114 {
115 if (rect->x2 - rect->x1 == src->i.width &&
116 rect->y2 - rect->y1 == src->i.height)
117 return NULL;
118 *i = src->i;
119 i->width = rect->x2 - rect->x1;
120 i->height = rect->y2 - rect->y1;
121 return &op_none_data;
122 }
123
124 static void
op_crop_work(struct ida_image * src,struct ida_rect * rect,unsigned char * dst,int line,void * data)125 op_crop_work(struct ida_image *src, struct ida_rect *rect,
126 unsigned char *dst, int line, void *data)
127 {
128 unsigned char *scanline;
129 int i;
130
131 scanline = ida_image_scanline(src, line+rect->y1) + rect->x1 * 3;
132 for (i = rect->x1; i < rect->x2; i++) {
133 dst[0] = scanline[0];
134 dst[1] = scanline[1];
135 dst[2] = scanline[2];
136 scanline += 3;
137 dst += 3;
138 }
139 }
140
141 static void*
op_autocrop_init(struct ida_image * src,struct ida_rect * unused,struct ida_image_info * i,void * parm)142 op_autocrop_init(struct ida_image *src, struct ida_rect *unused,
143 struct ida_image_info *i, void *parm)
144 {
145 static struct op_3x3_parm filter = {
146 f1: { -1, -1, -1 },
147 f2: { -1, 8, -1 },
148 f3: { -1, -1, -1 },
149 };
150 struct ida_rect rect;
151 struct ida_image img;
152 int x,y,limit;
153 unsigned char *line;
154 void *data;
155
156 /* detect edges */
157 rect.x1 = 0;
158 rect.x2 = src->i.width;
159 rect.y1 = 0;
160 rect.y2 = src->i.height;
161 memset(&img, 0, sizeof(img));
162 data = desc_3x3.init(src, &rect, &img.i, &filter);
163
164 ida_image_alloc(&img);
165 for (y = 0; y < (int)img.i.height; y++)
166 desc_3x3.work(src, &rect, ida_image_scanline(&img, y), y, data);
167 desc_3x3.done(data);
168 limit = 64;
169
170 /* y border */
171 for (y = 0; y < (int)img.i.height; y++) {
172 line = ida_image_scanline(&img, y);
173 for (x = 0; x < (int)img.i.width; x++)
174 if (line[3*x+0] > limit ||
175 line[3*x+1] > limit ||
176 line[3*x+2] > limit)
177 break;
178 if (x != (int)img.i.width)
179 break;
180 }
181 rect.y1 = y;
182 for (y = (int)img.i.height-1; y > rect.y1; y--) {
183 line = ida_image_scanline(&img, y);
184 for (x = 0; x < (int)img.i.width; x++)
185 if (line[3*x+0] > limit ||
186 line[3*x+1] > limit ||
187 line[3*x+2] > limit)
188 break;
189 if (x != (int)img.i.width)
190 break;
191 }
192 rect.y2 = y+1;
193
194 /* x border */
195 for (x = 0; x < (int)img.i.width; x++) {
196 for (y = 0; y < (int)img.i.height; y++) {
197 line = ida_image_scanline(&img, y) + x * 3;
198 if (line[0] > limit ||
199 line[1] > limit ||
200 line[2] > limit)
201 break;
202 }
203 if (y != (int)img.i.height)
204 break;
205 }
206 rect.x1 = x;
207 for (x = (int)img.i.width-1; x > rect.x1; x--) {
208 for (y = 0; y < (int)img.i.height; y++) {
209 line = ida_image_scanline(&img, y) + x * 3;
210 if (line[0] > limit ||
211 line[1] > limit ||
212 line[2] > limit)
213 break;
214 }
215 if (y != (int)img.i.height)
216 break;
217 }
218 rect.x2 = x+1;
219
220 ida_image_free(&img);
221 if (debug)
222 fprintf(stderr,"y: %d-%d/%u -- x: %d-%d/%u\n",
223 rect.y1, rect.y2, img.i.height,
224 rect.x1, rect.x2, img.i.width);
225
226 if (0 == rect.x2 - rect.x1 || 0 == rect.y2 - rect.y1)
227 return NULL;
228
229 *unused = rect;
230 *i = src->i;
231 i->width = rect.x2 - rect.x1;
232 i->height = rect.y2 - rect.y1;
233 return &op_none_data;
234 }
235
236 /* ----------------------------------------------------------------------- */
237
238 static char op_none_data;
239
op_none_init(struct ida_image * src,struct ida_rect * sel,struct ida_image_info * i,void * parm)240 void* op_none_init(struct ida_image *src, struct ida_rect *sel,
241 struct ida_image_info *i, void *parm)
242 {
243 *i = src->i;
244 return &op_none_data;
245 }
246
op_none_done(void * data)247 void op_none_done(void *data) {}
op_free_done(void * data)248 void op_free_done(void *data) { free(data); }
249
250 /* ----------------------------------------------------------------------- */
251
252 struct ida_op desc_flip_vert = {
253 name: "flip-vert",
254 init: op_none_init,
255 work: op_flip_vert,
256 done: op_none_done,
257 };
258 struct ida_op desc_flip_horz = {
259 name: "flip-horz",
260 init: op_none_init,
261 work: op_flip_horz,
262 done: op_none_done,
263 };
264 struct ida_op desc_rotate_cw = {
265 name: "rotate-cw",
266 init: op_rotate_init,
267 work: op_rotate_cw,
268 done: op_none_done,
269 };
270 struct ida_op desc_rotate_ccw = {
271 name: "rotate-ccw",
272 init: op_rotate_init,
273 work: op_rotate_ccw,
274 done: op_none_done,
275 };
276 struct ida_op desc_invert = {
277 name: "invert",
278 init: op_none_init,
279 work: op_invert,
280 done: op_none_done,
281 };
282 struct ida_op desc_crop = {
283 name: "crop",
284 init: op_crop_init,
285 work: op_crop_work,
286 done: op_none_done,
287 };
288 struct ida_op desc_autocrop = {
289 name: "autocrop",
290 init: op_autocrop_init,
291 work: op_crop_work,
292 done: op_none_done,
293 };
294