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