comparison mupdf-source/thirdparty/leptonica/src/fmorphauto.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27
28 /*!
29 * \file fmorphauto.c
30 * <pre>
31 *
32 * Main function calls:
33 * l_int32 fmorphautogen()
34 * l_int32 fmorphautogen1()
35 * l_int32 fmorphautogen2()
36 *
37 * Static helpers:
38 * static SARRAY *sarrayMakeWplsCode()
39 * static SARRAY *sarrayMakeInnerLoopDWACode()
40 * static char *makeBarrelshiftString()
41 *
42 *
43 * This automatically generates dwa code for erosion and dilation.
44 * Here's a road map for how it all works.
45 *
46 * (1) You generate an array (a SELA) of structuring elements (SELs).
47 * This can be done in several ways, including
48 * (a) calling the function selaAddBasic() for
49 * pre-compiled SELs
50 * (b) generating the SELA in code in line
51 * (c) reading in a SELA from file, using selaRead() or
52 * various other formats.
53 *
54 * (2) You call fmorphautogen() on this SELA. This in turn calls
55 * fmorphautogen1() and fmorphautogen2(), which use the text
56 * files morphtemplate1.txt and morphtemplate2.txt, respectively,
57 * for building up the source code. See the file
58 * prog/fmorphautogen.c for an example of how this is done.
59 * The output is written to files named fmorphgen.*.c
60 * and fmorphgenlow.*.c, where "*" is an integer that you
61 * input to this function. That integer labels both
62 * the output files, as well as all the functions that
63 * are generated. That way, using different integers,
64 * you can invoke fmorphautogen() any number of times
65 * to get functions that all have different names so that
66 * they can be linked into one program.
67 *
68 * (3) You copy the generated source files back to your src
69 * directory for compilation. Put their names in the
70 * Makefile, regenerate the allheaders.h prototype file,
71 * and recompile the library. Look at the Makefile to see how
72 * morphgen.1.c and fmorphgenlow.1.c are included. These files
73 * provide the single high-level interface for erosion, dilation,
74 * opening and closing, and the lower-level functions to
75 * do the actual work, for all 58 SELs in the SEL array.
76 *
77 * (4) In an application, you now use this interface. Again
78 * for the example files in the library, using integer "1":
79 *
80 * PIX *pixMorphDwa_1(PIX *pixd, PIX, *pixs,
81 * l_int32 operation, char *selname);
82 *
83 * where the operation is one of {L_MORPH_DILATE, L_MORPH_ERODE.
84 * L_MORPH_OPEN, L_MORPH_CLOSE}, and the selname is one
85 * of the set that were defined as the name field of sels.
86 * This set is listed at the beginning of the file fmorphgen.1.c.
87 *
88 * N.B. Although pixFMorphopGen_1() is global, you must NOT
89 * use it, because it assumes that 32 or 64 border pixels
90 * have been added to each side, and it will crash without those
91 * added pixels.
92 *
93 * For examples of use, see the file prog/binmorph_reg1.c, which
94 * verifies the consistency of the various implementations by
95 * comparing the dwa result with that of full-image rasterops.
96 * </pre>
97 */
98
99 #ifdef HAVE_CONFIG_H
100 #include <config_auto.h>
101 #endif /* HAVE_CONFIG_H */
102
103 #include <string.h>
104 #include "allheaders.h"
105
106 #define OUTROOT "fmorphgen"
107 #define TEMPLATE1 "morphtemplate1.txt"
108 #define TEMPLATE2 "morphtemplate2.txt"
109
110 #define PROTOARGS "(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *, l_int32);"
111
112 #define L_BUF_SIZE 512
113
114 static char * makeBarrelshiftString(l_int32 delx, l_int32 dely);
115 static SARRAY * sarrayMakeInnerLoopDWACode(SEL *sel, l_int32 index);
116 static SARRAY * sarrayMakeWplsCode(SEL *sel);
117
118 static char wpldecls[][53] = {
119 "l_int32 wpls2;",
120 "l_int32 wpls2, wpls3;",
121 "l_int32 wpls2, wpls3, wpls4;",
122 "l_int32 wpls5;",
123 "l_int32 wpls5, wpls6;",
124 "l_int32 wpls5, wpls6, wpls7;",
125 "l_int32 wpls5, wpls6, wpls7, wpls8;",
126 "l_int32 wpls9;",
127 "l_int32 wpls9, wpls10;",
128 "l_int32 wpls9, wpls10, wpls11;",
129 "l_int32 wpls9, wpls10, wpls11, wpls12;",
130 "l_int32 wpls13;",
131 "l_int32 wpls13, wpls14;",
132 "l_int32 wpls13, wpls14, wpls15;",
133 "l_int32 wpls13, wpls14, wpls15, wpls16;",
134 "l_int32 wpls17;",
135 "l_int32 wpls17, wpls18;",
136 "l_int32 wpls17, wpls18, wpls19;",
137 "l_int32 wpls17, wpls18, wpls19, wpls20;",
138 "l_int32 wpls21;",
139 "l_int32 wpls21, wpls22;",
140 "l_int32 wpls21, wpls22, wpls23;",
141 "l_int32 wpls21, wpls22, wpls23, wpls24;",
142 "l_int32 wpls25;",
143 "l_int32 wpls25, wpls26;",
144 "l_int32 wpls25, wpls26, wpls27;",
145 "l_int32 wpls25, wpls26, wpls27, wpls28;",
146 "l_int32 wpls29;",
147 "l_int32 wpls29, wpls30;",
148 "l_int32 wpls29, wpls30, wpls31;"};
149
150 static char wplgendecls[][30] = {
151 "l_int32 wpls2;",
152 "l_int32 wpls3;",
153 "l_int32 wpls4;",
154 "l_int32 wpls5;",
155 "l_int32 wpls6;",
156 "l_int32 wpls7;",
157 "l_int32 wpls8;",
158 "l_int32 wpls9;",
159 "l_int32 wpls10;",
160 "l_int32 wpls11;",
161 "l_int32 wpls12;",
162 "l_int32 wpls13;",
163 "l_int32 wpls14;",
164 "l_int32 wpls15;",
165 "l_int32 wpls16;",
166 "l_int32 wpls17;",
167 "l_int32 wpls18;",
168 "l_int32 wpls19;",
169 "l_int32 wpls20;",
170 "l_int32 wpls21;",
171 "l_int32 wpls22;",
172 "l_int32 wpls23;",
173 "l_int32 wpls24;",
174 "l_int32 wpls25;",
175 "l_int32 wpls26;",
176 "l_int32 wpls27;",
177 "l_int32 wpls28;",
178 "l_int32 wpls29;",
179 "l_int32 wpls30;",
180 "l_int32 wpls31;"};
181
182 static char wpldefs[][25] = {
183 " wpls2 = 2 * wpls;",
184 " wpls3 = 3 * wpls;",
185 " wpls4 = 4 * wpls;",
186 " wpls5 = 5 * wpls;",
187 " wpls6 = 6 * wpls;",
188 " wpls7 = 7 * wpls;",
189 " wpls8 = 8 * wpls;",
190 " wpls9 = 9 * wpls;",
191 " wpls10 = 10 * wpls;",
192 " wpls11 = 11 * wpls;",
193 " wpls12 = 12 * wpls;",
194 " wpls13 = 13 * wpls;",
195 " wpls14 = 14 * wpls;",
196 " wpls15 = 15 * wpls;",
197 " wpls16 = 16 * wpls;",
198 " wpls17 = 17 * wpls;",
199 " wpls18 = 18 * wpls;",
200 " wpls19 = 19 * wpls;",
201 " wpls20 = 20 * wpls;",
202 " wpls21 = 21 * wpls;",
203 " wpls22 = 22 * wpls;",
204 " wpls23 = 23 * wpls;",
205 " wpls24 = 24 * wpls;",
206 " wpls25 = 25 * wpls;",
207 " wpls26 = 26 * wpls;",
208 " wpls27 = 27 * wpls;",
209 " wpls28 = 28 * wpls;",
210 " wpls29 = 29 * wpls;",
211 " wpls30 = 30 * wpls;",
212 " wpls31 = 31 * wpls;"};
213
214 static char wplstrp[][10] = {"+ wpls", "+ wpls2", "+ wpls3", "+ wpls4",
215 "+ wpls5", "+ wpls6", "+ wpls7", "+ wpls8",
216 "+ wpls9", "+ wpls10", "+ wpls11", "+ wpls12",
217 "+ wpls13", "+ wpls14", "+ wpls15", "+ wpls16",
218 "+ wpls17", "+ wpls18", "+ wpls19", "+ wpls20",
219 "+ wpls21", "+ wpls22", "+ wpls23", "+ wpls24",
220 "+ wpls25", "+ wpls26", "+ wpls27", "+ wpls28",
221 "+ wpls29", "+ wpls30", "+ wpls31"};
222
223 static char wplstrm[][10] = {"- wpls", "- wpls2", "- wpls3", "- wpls4",
224 "- wpls5", "- wpls6", "- wpls7", "- wpls8",
225 "- wpls9", "- wpls10", "- wpls11", "- wpls12",
226 "- wpls13", "- wpls14", "- wpls15", "- wpls16",
227 "- wpls17", "- wpls18", "- wpls19", "- wpls20",
228 "- wpls21", "- wpls22", "- wpls23", "- wpls24",
229 "- wpls25", "- wpls26", "- wpls27", "- wpls28",
230 "- wpls29", "- wpls30", "- wpls31"};
231
232
233 /*!
234 * \brief fmorphautogen()
235 *
236 * \param[in] sela
237 * \param[in] fileindex
238 * \param[in] filename [optional]; can be null
239 * \return 0 if OK; 1 on error
240 *
241 * <pre>
242 * Notes:
243 * (1) This function generates all the code for implementing
244 * dwa morphological operations using all the sels in the sela.
245 * (2) See fmorphautogen1() and fmorphautogen2() for details.
246 * </pre>
247 */
248 l_ok
249 fmorphautogen(SELA *sela,
250 l_int32 fileindex,
251 const char *filename)
252 {
253 l_int32 ret1, ret2;
254
255 if (!sela)
256 return ERROR_INT("sela not defined", __func__, 1);
257 ret1 = fmorphautogen1(sela, fileindex, filename);
258 ret2 = fmorphautogen2(sela, fileindex, filename);
259 if (ret1 || ret2)
260 return ERROR_INT("code generation problem", __func__, 1);
261 return 0;
262 }
263
264
265 /*!
266 * \brief fmorphautogen1()
267 *
268 * \param[in] sela
269 * \param[in] fileindex
270 * \param[in] filename [optional]; can be null
271 * \return 0 if OK; 1 on error
272 *
273 * <pre>
274 * Notes:
275 * (1) This function uses morphtemplate1.txt to create a
276 * top-level file that contains two functions. These
277 * functions will carry out dilation, erosion,
278 * opening or closing for any of the sels in the input sela.
279 * (2) The fileindex parameter is inserted into the output
280 * filename, as described below.
281 * (3) If filename == NULL, the output file is fmorphgen.[n].c,
282 * where [n] is equal to the %fileindex parameter.
283 * (4) If filename != NULL, the output file is [%filename].[n].c.
284 * </pre>
285 */
286 l_ok
287 fmorphautogen1(SELA *sela,
288 l_int32 fileindex,
289 const char *filename)
290 {
291 char *filestr;
292 char *str_proto1, *str_proto2, *str_proto3;
293 char *str_doc1, *str_doc2, *str_doc3, *str_doc4;
294 char *str_def1, *str_def2, *str_proc1, *str_proc2;
295 char *str_dwa1, *str_low_dt, *str_low_ds, *str_low_ts;
296 char *str_low_tsp1, *str_low_dtp1;
297 char bigbuf[L_BUF_SIZE];
298 l_int32 i, nsels, nbytes, actstart, end, newstart;
299 size_t size;
300 SARRAY *sa1, *sa2, *sa3;
301
302 if (!sela)
303 return ERROR_INT("sela not defined", __func__, 1);
304 if (fileindex < 0)
305 fileindex = 0;
306 if ((nsels = selaGetCount(sela)) == 0)
307 return ERROR_INT("no sels in sela", __func__, 1);
308
309 /* Make array of textlines from morphtemplate1.txt */
310 if ((filestr = (char *)l_binaryRead(TEMPLATE1, &size)) == NULL)
311 return ERROR_INT("filestr not made", __func__, 1);
312 sa2 = sarrayCreateLinesFromString(filestr, 1);
313 LEPT_FREE(filestr);
314 if (!sa2)
315 return ERROR_INT("sa2 not made", __func__, 1);
316
317 /* Make array of sel names */
318 sa1 = selaGetSelnames(sela);
319
320 /* Make strings containing function call names */
321 sprintf(bigbuf, "PIX *pixMorphDwa_%d(PIX *pixd, PIX *pixs, "
322 "l_int32 operation, char *selname);", fileindex);
323 str_proto1 = stringNew(bigbuf);
324 sprintf(bigbuf, "PIX *pixFMorphopGen_%d(PIX *pixd, PIX *pixs, "
325 "l_int32 operation, char *selname);", fileindex);
326 str_proto2 = stringNew(bigbuf);
327 sprintf(bigbuf, "l_int32 fmorphopgen_low_%d(l_uint32 *datad, l_int32 w,\n"
328 " l_int32 h, l_int32 wpld,\n"
329 " l_uint32 *datas, l_int32 wpls,\n"
330 " l_int32 index);", fileindex);
331 str_proto3 = stringNew(bigbuf);
332 sprintf(bigbuf, " * PIX *pixMorphDwa_%d()", fileindex);
333 str_doc1 = stringNew(bigbuf);
334 sprintf(bigbuf, " * PIX *pixFMorphopGen_%d()", fileindex);
335 str_doc2 = stringNew(bigbuf);
336 sprintf(bigbuf, " * \\brief pixMorphDwa_%d()", fileindex);
337 str_doc3 = stringNew(bigbuf);
338 sprintf(bigbuf, " * \\brief pixFMorphopGen_%d()", fileindex);
339 str_doc4 = stringNew(bigbuf);
340 sprintf(bigbuf, "pixMorphDwa_%d(PIX *pixd,", fileindex);
341 str_def1 = stringNew(bigbuf);
342 sprintf(bigbuf, "pixFMorphopGen_%d(PIX *pixd,", fileindex);
343 str_def2 = stringNew(bigbuf);
344 sprintf(bigbuf, " PROCNAME(\"pixMorphDwa_%d\");", fileindex);
345 str_proc1 = stringNew(bigbuf);
346 sprintf(bigbuf, " PROCNAME(\"pixFMorphopGen_%d\");", fileindex);
347 str_proc2 = stringNew(bigbuf);
348 sprintf(bigbuf,
349 " pixt2 = pixFMorphopGen_%d(NULL, pixt1, operation, selname);",
350 fileindex);
351 str_dwa1 = stringNew(bigbuf);
352 sprintf(bigbuf,
353 " fmorphopgen_low_%d(datad, w, h, wpld, datat, wpls, index);",
354 fileindex);
355 str_low_dt = stringNew(bigbuf);
356 sprintf(bigbuf,
357 " fmorphopgen_low_%d(datad, w, h, wpld, datas, wpls, index);",
358 fileindex);
359 str_low_ds = stringNew(bigbuf);
360 sprintf(bigbuf,
361 " fmorphopgen_low_%d(datat, w, h, wpls, datas, wpls, index+1);",
362 fileindex);
363 str_low_tsp1 = stringNew(bigbuf);
364 sprintf(bigbuf,
365 " fmorphopgen_low_%d(datat, w, h, wpls, datas, wpls, index);",
366 fileindex);
367 str_low_ts = stringNew(bigbuf);
368 sprintf(bigbuf,
369 " fmorphopgen_low_%d(datad, w, h, wpld, datat, wpls, index+1);",
370 fileindex);
371 str_low_dtp1 = stringNew(bigbuf);
372
373 /* Make the output sa */
374 sa3 = sarrayCreate(0);
375
376 /* Copyright notice and info header */
377 sarrayParseRange(sa2, 0, &actstart, &end, &newstart, "--", 0);
378 sarrayAppendRange(sa3, sa2, actstart, end);
379
380 /* Insert function names as documentation */
381 sarrayAddString(sa3, str_doc1, L_INSERT);
382 sarrayAddString(sa3, str_doc2, L_INSERT);
383
384 /* Add '#include's */
385 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
386 sarrayAppendRange(sa3, sa2, actstart, end);
387
388 /* Insert function prototypes */
389 sarrayAddString(sa3, str_proto1, L_INSERT);
390 sarrayAddString(sa3, str_proto2, L_INSERT);
391 sarrayAddString(sa3, str_proto3, L_INSERT);
392
393 /* Add static globals */
394 sprintf(bigbuf, "\nstatic l_int32 NUM_SELS_GENERATED = %d;", nsels);
395 sarrayAddString(sa3, bigbuf, L_COPY);
396 sprintf(bigbuf, "static char SEL_NAMES[][80] = {");
397 sarrayAddString(sa3, bigbuf, L_COPY);
398 for (i = 0; i < nsels - 1; i++) {
399 sprintf(bigbuf, " \"%s\",",
400 sarrayGetString(sa1, i, L_NOCOPY));
401 sarrayAddString(sa3, bigbuf, L_COPY);
402 }
403 sprintf(bigbuf, " \"%s\"};",
404 sarrayGetString(sa1, i, L_NOCOPY));
405 sarrayAddString(sa3, bigbuf, L_COPY);
406
407 /* Start pixMorphDwa_*() function description */
408 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
409 sarrayAppendRange(sa3, sa2, actstart, end);
410 sarrayAddString(sa3, str_doc3, L_INSERT);
411 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
412 sarrayAppendRange(sa3, sa2, actstart, end);
413
414 /* Finish pixMorphDwa_*() function definition */
415 sarrayAddString(sa3, str_def1, L_INSERT);
416 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
417 sarrayAppendRange(sa3, sa2, actstart, end);
418 sarrayAddString(sa3, str_proc1, L_INSERT);
419 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
420 sarrayAppendRange(sa3, sa2, actstart, end);
421 sarrayAddString(sa3, str_dwa1, L_INSERT);
422 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
423 sarrayAppendRange(sa3, sa2, actstart, end);
424
425 /* Start pixFMorphopGen_*() function description */
426 sarrayAddString(sa3, str_doc4, L_INSERT);
427 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
428 sarrayAppendRange(sa3, sa2, actstart, end);
429
430 /* Finish pixFMorphopGen_*() function definition */
431 sarrayAddString(sa3, str_def2, L_INSERT);
432 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
433 sarrayAppendRange(sa3, sa2, actstart, end);
434 sarrayAddString(sa3, str_proc2, L_INSERT);
435 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
436 sarrayAppendRange(sa3, sa2, actstart, end);
437 sarrayAddString(sa3, str_low_dt, L_COPY);
438 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
439 sarrayAppendRange(sa3, sa2, actstart, end);
440 sarrayAddString(sa3, str_low_ds, L_INSERT);
441 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
442 sarrayAppendRange(sa3, sa2, actstart, end);
443 sarrayAddString(sa3, str_low_tsp1, L_INSERT);
444 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
445 sarrayAppendRange(sa3, sa2, actstart, end);
446 sarrayAddString(sa3, str_low_dt, L_INSERT);
447 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
448 sarrayAppendRange(sa3, sa2, actstart, end);
449 sarrayAddString(sa3, str_low_ts, L_INSERT);
450 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
451 sarrayAppendRange(sa3, sa2, actstart, end);
452 sarrayAddString(sa3, str_low_dtp1, L_INSERT);
453 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
454 sarrayAppendRange(sa3, sa2, actstart, end);
455
456 /* Output to file */
457 filestr = sarrayToString(sa3, 1);
458 nbytes = strlen(filestr);
459 if (filename)
460 snprintf(bigbuf, L_BUF_SIZE, "%s.%d.c", filename, fileindex);
461 else
462 sprintf(bigbuf, "%s.%d.c", OUTROOT, fileindex);
463 l_binaryWrite(bigbuf, "w", filestr, nbytes);
464 sarrayDestroy(&sa1);
465 sarrayDestroy(&sa2);
466 sarrayDestroy(&sa3);
467 LEPT_FREE(filestr);
468 return 0;
469 }
470
471
472 /*
473 * fmorphautogen2()
474 *
475 * Input: sela
476 * fileindex
477 * filename (<optional>; can be null)
478 * Return: 0 if OK; 1 on error
479 *
480 * Notes:
481 * (1) This function uses morphtemplate2.txt to create a
482 * low-level file that contains the low-level functions for
483 * implementing dilation and erosion for every sel
484 * in the input sela.
485 * (2) The fileindex parameter is inserted into the output
486 * filename, as described below.
487 * (3) If filename == NULL, the output file is fmorphgenlow.[n].c,
488 * where [n] is equal to the 'fileindex' parameter.
489 * (4) If filename != NULL, the output file is [filename]low.[n].c.
490 */
491 l_int32
492 fmorphautogen2(SELA *sela,
493 l_int32 fileindex,
494 const char *filename)
495 {
496 char *filestr, *linestr, *fname;
497 char *str_doc1, *str_doc2, *str_doc3, *str_doc4, *str_def1;
498 char bigbuf[L_BUF_SIZE];
499 char breakstring[] = " break;";
500 char staticstring[] = "static void";
501 l_int32 i, nsels, nbytes, actstart, end, newstart;
502 l_int32 argstart, argend, loopstart, loopend, finalstart, finalend;
503 size_t size;
504 SARRAY *sa1, *sa2, *sa3, *sa4, *sa5, *sa6;
505 SEL *sel;
506
507 if (!sela)
508 return ERROR_INT("sela not defined", __func__, 1);
509 if (fileindex < 0)
510 fileindex = 0;
511 if ((nsels = selaGetCount(sela)) == 0)
512 return ERROR_INT("no sels in sela", __func__, 1);
513
514 /* Make the array of textlines from morphtemplate2.txt */
515 if ((filestr = (char *)l_binaryRead(TEMPLATE2, &size)) == NULL)
516 return ERROR_INT("filestr not made", __func__, 1);
517 sa1 = sarrayCreateLinesFromString(filestr, 1);
518 LEPT_FREE(filestr);
519 if (!sa1)
520 return ERROR_INT("sa1 not made", __func__, 1);
521
522 /* Make the array of static function names */
523 if ((sa2 = sarrayCreate(2 * nsels)) == NULL) {
524 sarrayDestroy(&sa1);
525 return ERROR_INT("sa2 not made", __func__, 1);
526 }
527 for (i = 0; i < nsels; i++) {
528 sprintf(bigbuf, "fdilate_%d_%d", fileindex, i);
529 sarrayAddString(sa2, bigbuf, L_COPY);
530 sprintf(bigbuf, "ferode_%d_%d", fileindex, i);
531 sarrayAddString(sa2, bigbuf, L_COPY);
532 }
533
534 /* Make the static prototype strings */
535 sa3 = sarrayCreate(2 * nsels); /* should be ok */
536 for (i = 0; i < 2 * nsels; i++) {
537 fname = sarrayGetString(sa2, i, L_NOCOPY);
538 sprintf(bigbuf, "static void %s%s", fname, PROTOARGS);
539 sarrayAddString(sa3, bigbuf, L_COPY);
540 }
541
542 /* Make strings containing function names */
543 sprintf(bigbuf, " * l_int32 fmorphopgen_low_%d()",
544 fileindex);
545 str_doc1 = stringNew(bigbuf);
546 sprintf(bigbuf, " * void fdilate_%d_*()", fileindex);
547 str_doc2 = stringNew(bigbuf);
548 sprintf(bigbuf, " * void ferode_%d_*()", fileindex);
549 str_doc3 = stringNew(bigbuf);
550
551 /* Output to this sa */
552 sa4 = sarrayCreate(0);
553
554 /* Copyright notice and info header */
555 sarrayParseRange(sa1, 0, &actstart, &end, &newstart, "--", 0);
556 sarrayAppendRange(sa4, sa1, actstart, end);
557
558 /* Insert function names as documentation */
559 sarrayAddString(sa4, str_doc1, L_INSERT);
560 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
561 sarrayAppendRange(sa4, sa1, actstart, end);
562 sarrayAddString(sa4, str_doc2, L_INSERT);
563 sarrayAddString(sa4, str_doc3, L_INSERT);
564 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
565 sarrayAppendRange(sa4, sa1, actstart, end);
566
567 /* Insert static protos */
568 for (i = 0; i < 2 * nsels; i++) {
569 if ((linestr = sarrayGetString(sa3, i, L_COPY)) == NULL) {
570 sarrayDestroy(&sa1);
571 sarrayDestroy(&sa2);
572 sarrayDestroy(&sa3);
573 sarrayDestroy(&sa4);
574 return ERROR_INT("linestr not retrieved", __func__, 1);
575 }
576 sarrayAddString(sa4, linestr, L_INSERT);
577 }
578
579 /* More strings with function names */
580 sprintf(bigbuf, " * fmorphopgen_low_%d()", fileindex);
581 str_doc4 = stringNew(bigbuf);
582 sprintf(bigbuf, "fmorphopgen_low_%d(l_uint32 *datad,", fileindex);
583 str_def1 = stringNew(bigbuf);
584
585 /* Insert function header */
586 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
587 sarrayAppendRange(sa4, sa1, actstart, end);
588 sarrayAddString(sa4, str_doc4, L_INSERT);
589 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
590 sarrayAppendRange(sa4, sa1, actstart, end);
591 sarrayAddString(sa4, str_def1, L_INSERT);
592 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
593 sarrayAppendRange(sa4, sa1, actstart, end);
594
595 /* Generate and insert the dispatcher code */
596 for (i = 0; i < 2 * nsels; i++) {
597 sprintf(bigbuf, " case %d:", i);
598 sarrayAddString(sa4, bigbuf, L_COPY);
599 sprintf(bigbuf, " %s(datad, w, h, wpld, datas, wpls);",
600 sarrayGetString(sa2, i, L_NOCOPY));
601 sarrayAddString(sa4, bigbuf, L_COPY);
602 sarrayAddString(sa4, breakstring, L_COPY);
603 }
604
605 /* Finish the dispatcher and introduce the low-level code */
606 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
607 sarrayAppendRange(sa4, sa1, actstart, end);
608
609 /* Get the range for the args common to all functions */
610 sarrayParseRange(sa1, newstart, &argstart, &argend, &newstart, "--", 0);
611
612 /* Get the range for the loop code common to all functions */
613 sarrayParseRange(sa1, newstart, &loopstart, &loopend, &newstart, "--", 0);
614
615 /* Get the range for the ending code common to all functions */
616 sarrayParseRange(sa1, newstart, &finalstart, &finalend, &newstart, "--", 0);
617
618 /* Do all the static functions */
619 for (i = 0; i < 2 * nsels; i++) {
620 /* Generate the function header and add the common args */
621 sarrayAddString(sa4, staticstring, L_COPY);
622 fname = sarrayGetString(sa2, i, L_NOCOPY);
623 sprintf(bigbuf, "%s(l_uint32 *datad,", fname);
624 sarrayAddString(sa4, bigbuf, L_COPY);
625 sarrayAppendRange(sa4, sa1, argstart, argend);
626
627 /* Declare and define wplsN args, as necessary */
628 if ((sel = selaGetSel(sela, i/2)) == NULL) {
629 sarrayDestroy(&sa1);
630 sarrayDestroy(&sa2);
631 sarrayDestroy(&sa3);
632 sarrayDestroy(&sa4);
633 return ERROR_INT("sel not returned", __func__, 1);
634 }
635 sa5 = sarrayMakeWplsCode(sel);
636 sarrayJoin(sa4, sa5);
637 sarrayDestroy(&sa5);
638
639 /* Add the function loop code */
640 sarrayAppendRange(sa4, sa1, loopstart, loopend);
641
642 /* Insert barrel-op code for *dptr */
643 sa6 = sarrayMakeInnerLoopDWACode(sel, i);
644 sarrayJoin(sa4, sa6);
645 sarrayDestroy(&sa6);
646
647 /* Finish the function code */
648 sarrayAppendRange(sa4, sa1, finalstart, finalend);
649 }
650
651 /* Output to file */
652 filestr = sarrayToString(sa4, 1);
653 nbytes = strlen(filestr);
654 if (filename)
655 snprintf(bigbuf, L_BUF_SIZE, "%slow.%d.c", filename, fileindex);
656 else
657 sprintf(bigbuf, "%slow.%d.c", OUTROOT, fileindex);
658 l_binaryWrite(bigbuf, "w", filestr, nbytes);
659 sarrayDestroy(&sa1);
660 sarrayDestroy(&sa2);
661 sarrayDestroy(&sa3);
662 sarrayDestroy(&sa4);
663 LEPT_FREE(filestr);
664 return 0;
665 }
666
667
668 /*--------------------------------------------------------------------------*
669 * Helper code for sel *
670 *--------------------------------------------------------------------------*/
671 /*!
672 * \brief sarrayMakeWplsCode()
673 */
674 static SARRAY *
675 sarrayMakeWplsCode(SEL *sel)
676 {
677 char emptystring[] = "";
678 l_int32 i, j, ymax, dely, allvshifts;
679 l_int32 vshift[32];
680 SARRAY *sa;
681
682 if (!sel)
683 return (SARRAY *)ERROR_PTR("sel not defined", __func__, NULL);
684
685 for (i = 0; i < 32; i++)
686 vshift[i] = 0;
687 ymax = 0;
688 for (i = 0; i < sel->sy; i++) {
689 for (j = 0; j < sel->sx; j++) {
690 if (sel->data[i][j] == 1) {
691 dely = L_ABS(i - sel->cy);
692 if (dely < 32)
693 vshift[dely] = 1;
694 ymax = L_MAX(ymax, dely);
695 }
696 }
697 }
698 if (ymax > 31) {
699 L_WARNING("ymax > 31; truncating to 31\n", __func__);
700 ymax = 31;
701 }
702
703 /* Test if this is a vertical brick */
704 allvshifts = TRUE;
705 for (i = 0; i < ymax; i++) {
706 if (vshift[i] == 0) {
707 allvshifts = FALSE;
708 break;
709 }
710 }
711
712 sa = sarrayCreate(0);
713
714 /* Add declarations */
715 if (allvshifts == TRUE) { /* packs them as well as possible */
716 if (ymax > 4)
717 sarrayAddString(sa, wpldecls[2], L_COPY);
718 if (ymax > 8)
719 sarrayAddString(sa, wpldecls[6], L_COPY);
720 if (ymax > 12)
721 sarrayAddString(sa, wpldecls[10], L_COPY);
722 if (ymax > 16)
723 sarrayAddString(sa, wpldecls[14], L_COPY);
724 if (ymax > 20)
725 sarrayAddString(sa, wpldecls[18], L_COPY);
726 if (ymax > 24)
727 sarrayAddString(sa, wpldecls[22], L_COPY);
728 if (ymax > 28)
729 sarrayAddString(sa, wpldecls[26], L_COPY);
730 if (ymax > 1)
731 sarrayAddString(sa, wpldecls[ymax - 2], L_COPY);
732 } else { /* puts them one/line */
733 for (i = 2; i <= ymax; i++) {
734 if (vshift[i])
735 sarrayAddString(sa, wplgendecls[i - 2], L_COPY);
736 }
737 }
738
739 sarrayAddString(sa, emptystring, L_COPY);
740
741 /* Add definitions */
742 for (i = 2; i <= ymax; i++) {
743 if (vshift[i])
744 sarrayAddString(sa, wpldefs[i - 2], L_COPY);
745 }
746
747 return sa;
748 }
749
750
751 /*!
752 * \brief sarrayMakeInnerLoopDWACode()
753 */
754 static SARRAY *
755 sarrayMakeInnerLoopDWACode(SEL *sel,
756 l_int32 index)
757 {
758 char *tstr, *string;
759 char logicalor[] = "|";
760 char logicaland[] = "&";
761 char bigbuf[L_BUF_SIZE];
762 l_int32 i, j, optype, count, nfound, delx, dely;
763 SARRAY *sa;
764
765 if (!sel)
766 return (SARRAY *)ERROR_PTR("sel not defined", __func__, NULL);
767
768 if (index % 2 == 0) {
769 optype = L_MORPH_DILATE;
770 tstr = logicalor;
771 } else {
772 optype = L_MORPH_ERODE;
773 tstr = logicaland;
774 }
775
776 count = 0;
777 for (i = 0; i < sel->sy; i++) {
778 for (j = 0; j < sel->sx; j++) {
779 if (sel->data[i][j] == 1)
780 count++;
781 }
782 }
783
784 sa = sarrayCreate(0);
785 if (count == 0) {
786 L_WARNING("no hits in Sel %d\n", __func__, index);
787 return sa; /* no code inside! */
788 }
789
790 nfound = 0;
791 for (i = 0; i < sel->sy; i++) {
792 for (j = 0; j < sel->sx; j++) {
793 if (sel->data[i][j] == 1) {
794 nfound++;
795 if (optype == L_MORPH_DILATE) {
796 dely = sel->cy - i;
797 delx = sel->cx - j;
798 } else { /* optype == L_MORPH_ERODE */
799 dely = i - sel->cy;
800 delx = j - sel->cx;
801 }
802 if ((string = makeBarrelshiftString(delx, dely)) == NULL) {
803 L_WARNING("barrel shift string not made\n", __func__);
804 continue;
805 }
806 if (count == 1) /* just one item */
807 sprintf(bigbuf, " *dptr = %s;", string);
808 else if (nfound == 1)
809 sprintf(bigbuf, " *dptr = %s %s", string, tstr);
810 else if (nfound < count)
811 sprintf(bigbuf, " %s %s", string, tstr);
812 else /* nfound == count */
813 sprintf(bigbuf, " %s;", string);
814 sarrayAddString(sa, bigbuf, L_COPY);
815 LEPT_FREE(string);
816 }
817 }
818 }
819
820 return sa;
821 }
822
823
824 /*!
825 * \brief makeBarrelshiftString()
826 */
827 static char *
828 makeBarrelshiftString(l_int32 delx, /* j - cx */
829 l_int32 dely) /* i - cy */
830 {
831 l_int32 absx, absy;
832 char bigbuf[L_BUF_SIZE];
833
834 if (delx < -31 || delx > 31)
835 return (char *)ERROR_PTR("delx out of bounds", __func__, NULL);
836 if (dely < -31 || dely > 31)
837 return (char *)ERROR_PTR("dely out of bounds", __func__, NULL);
838 absx = L_ABS(delx);
839 absy = L_ABS(dely);
840
841 if ((delx == 0) && (dely == 0))
842 sprintf(bigbuf, "(*sptr)");
843 else if ((delx == 0) && (dely < 0))
844 sprintf(bigbuf, "(*(sptr %s))", wplstrm[absy - 1]);
845 else if ((delx == 0) && (dely > 0))
846 sprintf(bigbuf, "(*(sptr %s))", wplstrp[absy - 1]);
847 else if ((delx < 0) && (dely == 0))
848 sprintf(bigbuf, "((*(sptr) >> %d) | (*(sptr - 1) << %d))",
849 absx, 32 - absx);
850 else if ((delx > 0) && (dely == 0))
851 sprintf(bigbuf, "((*(sptr) << %d) | (*(sptr + 1) >> %d))",
852 absx, 32 - absx);
853 else if ((delx < 0) && (dely < 0))
854 sprintf(bigbuf, "((*(sptr %s) >> %d) | (*(sptr %s - 1) << %d))",
855 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
856 else if ((delx > 0) && (dely < 0))
857 sprintf(bigbuf, "((*(sptr %s) << %d) | (*(sptr %s + 1) >> %d))",
858 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
859 else if ((delx < 0) && (dely > 0))
860 sprintf(bigbuf, "((*(sptr %s) >> %d) | (*(sptr %s - 1) << %d))",
861 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
862 else /* ((delx > 0) && (dely > 0)) */
863 sprintf(bigbuf, "((*(sptr %s) << %d) | (*(sptr %s + 1) >> %d))",
864 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
865
866 return stringNew(bigbuf);
867 }