Mercurial > hgrepos > Python2 > PyMuPDF
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 } |
