/*! * \brief getRootNameFromArgv0() * * \param[in] argv0 * \return root name without the '_reg', or NULL on error * * <pre> * Notes: * (1) For example, from psioseg_reg, we want to extract * just 'psioseg' as the root. * (2) In unix with autotools, the executable is not X, * but ./.libs/lt-X. So in addition to stripping out the * last 4 characters of the tail, we have to check for * the '-' and strip out the "lt-" prefix if we find it. * </pre> */ static char * getRootNameFromArgv0(const char *argv0) { l_int32 len; char *root; PROCNAME("getRootNameFromArgv0"); splitPathAtDirectory(argv0, NULL, &root); if ((len = strlen(root)) <= 4) { LEPT_FREE(root); return (char *)ERROR_PTR("invalid argv0; too small", procName, NULL); } #ifndef _WIN32 { char *newroot; l_int32 loc; if (stringFindSubstr(root, "-", &loc)) { newroot = stringNew(root + loc + 1); /* strip out "lt-" */ LEPT_FREE(root); root = newroot; len = strlen(root); } } #else if (strstr(root, ".exe") != NULL) len -= 4; #endif /* ! _WIN32 */ root[len - 4] = '\0'; /* remove the suffix */ return root; }
/*! * barcodeDecode39() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Code39 * http://morovia.com/education/symbology/code39.asp * (2) Each symbol has 5 black and 4 white bars. * The start and stop codes are 121121211 (the asterisk) * (3) This decoder was contributed by Roger Hyde. */ static char * barcodeDecode39(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[10]; l_int32 valid, reverse, i, j, len, error, nsymb, start, found; PROCNAME("barcodeDecode39"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODE39, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in code39 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len + 1) % 10 != 0) return (char *)ERROR_PTR("size+1 not divisible by 10: invalid code 39", procName, NULL); /* Decode the symbols */ nsymb = (len - 19) / 10; data = (char *)LEPT_CALLOC(nsymb + 1, sizeof(char)); memset(code, 0, 10); error = FALSE; for (i = 0; i < nsymb; i++) { start = 10 + 10 * i; for (j = 0; j < 9; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < C39_START; j++) { if (!strcmp(code, Code39[j])) { data[i] = Code39Val[j]; found = TRUE; break; } } if (!found) error = TRUE; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; }
/*! * \brief lqueueDestroy() * * \param[in,out] plq to be nulled * \param[in] freeflag TRUE to free each remaining struct in the array * \return void * * <pre> * Notes: * (1) If freeflag is TRUE, frees each struct in the array. * (2) If freeflag is FALSE but there are elements on the array, * gives a warning and destroys the array. This will * cause a memory leak of all the items that were on the queue. * So if the items require their own destroy function, they * must be destroyed before the queue. The same applies to the * auxiliary stack, if it is used. * (3) To destroy the L_Queue, we destroy the ptr array, then * the lqueue, and then null the contents of the input ptr. * </pre> */ void lqueueDestroy(L_QUEUE **plq, l_int32 freeflag) { void *item; L_QUEUE *lq; PROCNAME("lqueueDestroy"); if (plq == NULL) { L_WARNING("ptr address is NULL\n", procName); return; } if ((lq = *plq) == NULL) return; if (freeflag) { while(lq->nelem > 0) { item = lqueueRemove(lq); LEPT_FREE(item); } } else if (lq->nelem > 0) { L_WARNING("memory leak of %d items in lqueue!\n", procName, lq->nelem); } if (lq->array) LEPT_FREE(lq->array); if (lq->stack) lstackDestroy(&lq->stack, freeflag); LEPT_FREE(lq); *plq = NULL; return; }
/*! * \brief parseStringForNumbers() * * \param[in] str string containing numbers; not changed * \param[in] seps string of characters that can be used between ints * \return numa of numbers found, or NULL on error * * <pre> * Notes: * (1) The numbers can be ints or floats. * </pre> */ NUMA * parseStringForNumbers(const char *str, const char *seps) { char *newstr, *head, *tail; l_float32 val; NUMA *na; PROCNAME("parseStringForNumbers"); if (!str) return (NUMA *)ERROR_PTR("str not defined", procName, NULL); newstr = stringNew(str); /* to enforce const-ness of str */ na = numaCreate(0); head = strtokSafe(newstr, seps, &tail); val = atof(head); numaAddNumber(na, val); LEPT_FREE(head); while ((head = strtokSafe(NULL, seps, &tail)) != NULL) { val = atof(head); numaAddNumber(na, val); LEPT_FREE(head); } LEPT_FREE(newstr); return na; }
/* * captureProtoSignature() * * Input: sa (output from cpp, by line) * start (starting index to search; never a comment line) * stop (index of line on which pattern is completed) * charindex (char index of completing ')' character) * Return: cleanstr (prototype string), or NULL on error * * Notes: * (1) Return all characters, ending with a ';' after the ')' */ static char * captureProtoSignature(SARRAY *sa, l_int32 start, l_int32 stop, l_int32 charindex) { char *str, *newstr, *protostr, *cleanstr; SARRAY *sap; l_int32 i; PROCNAME("captureProtoSignature"); if (!sa) return (char *)ERROR_PTR("sa not defined", procName, NULL); sap = sarrayCreate(0); for (i = start; i < stop; i++) { str = sarrayGetString(sa, i, L_COPY); sarrayAddString(sap, str, L_INSERT); } str = sarrayGetString(sa, stop, L_COPY); str[charindex + 1] = '\0'; newstr = stringJoin(str, ";"); sarrayAddString(sap, newstr, L_INSERT); LEPT_FREE(str); protostr = sarrayToString(sap, 2); sarrayDestroy(&sap); cleanstr = cleanProtoSignature(protostr); LEPT_FREE(protostr); return cleanstr; }
/*! * numaDestroy() * * Input: &na (<to be nulled if it exists>) * Return: void * * Notes: * (1) Decrements the ref count and, if 0, destroys the numa. * (2) Always nulls the input ptr. */ void numaDestroy(NUMA **pna) { NUMA *na; PROCNAME("numaDestroy"); if (pna == NULL) { L_WARNING("ptr address is NULL\n", procName); return; } if ((na = *pna) == NULL) return; /* Decrement the ref count. If it is 0, destroy the numa. */ numaChangeRefcount(na, -1); if (numaGetRefcount(na) <= 0) { if (na->array) LEPT_FREE(na->array); LEPT_FREE(na); } *pna = NULL; return; }
/*! * recogaDestroy() * * Input: &recoga (<will be set to null before returning>) * Return: void * * Notes: * (1) If a recog has a parent, the parent owns it. To destroy * a recog, it must first be "orphaned". */ void recogaDestroy(L_RECOGA **precoga) { l_int32 i; L_RECOG *recog; L_RECOGA *recoga; PROCNAME("recogaDestroy"); if (precoga == NULL) { L_WARNING("ptr address is null!\n", procName); return; } if ((recoga = *precoga) == NULL) return; rchaDestroy(&recoga->rcha); for (i = 0; i < recoga->n; i++) { if ((recog = recoga->recog[i]) == NULL) { L_ERROR("recog not found for index %d\n", procName, i); continue; } recog->parent = NULL; /* orphan it */ recogDestroy(&recog); } LEPT_FREE(recoga->recog); LEPT_FREE(recoga); *precoga = NULL; return; }
/*! * \brief boxaaQuadtreeRegions() * * \param[in] w, h size of pix that is being quadtree-ized * \param[in] nlevels number of levels in quadtree * \return baa for quadtree regions at each level, or NULL on error * * <pre> * Notes: * (1) The returned boxaa has %nlevels of boxa, each containing * the set of rectangles at that level. The rectangle at * level 0 is the entire region; at level 1 the region is * divided into 4 rectangles, and at level n there are n^4 * rectangles. * (2) At each level, the rectangles in the boxa are in "raster" * order, with LR (fast scan) and TB (slow scan). * </pre> */ BOXAA * boxaaQuadtreeRegions(l_int32 w, l_int32 h, l_int32 nlevels) { l_int32 i, j, k, maxpts, nside, nbox, bw, bh; l_int32 *xstart, *xend, *ystart, *yend; BOX *box; BOXA *boxa; BOXAA *baa; PROCNAME("boxaaQuadtreeRegions"); if (nlevels < 1) return (BOXAA *)ERROR_PTR("nlevels must be >= 1", procName, NULL); if (w < (1 << (nlevels - 1))) return (BOXAA *)ERROR_PTR("w doesn't support nlevels", procName, NULL); if (h < (1 << (nlevels - 1))) return (BOXAA *)ERROR_PTR("h doesn't support nlevels", procName, NULL); baa = boxaaCreate(nlevels); maxpts = 1 << (nlevels - 1); xstart = (l_int32 *)LEPT_CALLOC(maxpts, sizeof(l_int32)); xend = (l_int32 *)LEPT_CALLOC(maxpts, sizeof(l_int32)); ystart = (l_int32 *)LEPT_CALLOC(maxpts, sizeof(l_int32)); yend = (l_int32 *)LEPT_CALLOC(maxpts, sizeof(l_int32)); for (k = 0; k < nlevels; k++) { nside = 1 << k; /* number of boxes in each direction */ for (i = 0; i < nside; i++) { xstart[i] = (w - 1) * i / nside; if (i > 0) xstart[i]++; xend[i] = (w - 1) * (i + 1) / nside; ystart[i] = (h - 1) * i / nside; if (i > 0) ystart[i]++; yend[i] = (h - 1) * (i + 1) / nside; #if DEBUG_BOXES fprintf(stderr, "k = %d, xs[%d] = %d, xe[%d] = %d, ys[%d] = %d, ye[%d] = %d\n", k, i, xstart[i], i, xend[i], i, ystart[i], i, yend[i]); #endif /* DEBUG_BOXES */ } nbox = 1 << (2 * k); boxa = boxaCreate(nbox); for (i = 0; i < nside; i++) { bh = yend[i] - ystart[i] + 1; for (j = 0; j < nside; j++) { bw = xend[j] - xstart[j] + 1; box = boxCreate(xstart[j], ystart[i], bw, bh); boxaAddBox(boxa, box, L_INSERT); } } boxaaAddBoxa(baa, boxa, L_INSERT); } LEPT_FREE(xstart); LEPT_FREE(xend); LEPT_FREE(ystart); LEPT_FREE(yend); return baa; }
/*! * \brief pixWriteStreamGif() * * \param[in] fp file stream opened for writing * \param[in] pix 1, 2, 4, 8, 16 or 32 bpp * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) All output gif have colormaps. If the pix is 32 bpp rgb, * this quantizes the colors and writes out 8 bpp. * If the pix is 16 bpp grayscale, it converts to 8 bpp first. * </pre> */ l_int32 pixWriteStreamGif(FILE *fp, PIX *pix) { l_uint8 *filedata; size_t filebytes, nbytes; PROCNAME("pixWriteStreamGif"); if (!fp) return ERROR_INT("stream not open", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); pixSetPadBits(pix, 0); if (pixWriteMemGif(&filedata, &filebytes, pix) != 0) { LEPT_FREE(filedata); return ERROR_INT("failure to gif encode pix", procName, 1); } rewind(fp); nbytes = fwrite(filedata, 1, filebytes, fp); LEPT_FREE(filedata); if (nbytes != filebytes) return ERROR_INT("write error", procName, 1); return 0; }
/*! * ptraaDestroy() * * Input: &paa (<to be nulled>) * freeflag (TRUE to free each remaining item in each ptra) * warnflag (TRUE to warn if any remaining items are not destroyed) * Return: void * * Notes: * (1) See ptraDestroy() for use of @freeflag and @warnflag. * (2) To destroy the ptraa, we destroy each ptra, then the ptr array, * then the ptraa, and then null the contents of the input ptr. */ void ptraaDestroy(L_PTRAA **ppaa, l_int32 freeflag, l_int32 warnflag) { l_int32 i, n; L_PTRA *pa; L_PTRAA *paa; PROCNAME("ptraaDestroy"); if (ppaa == NULL) { L_WARNING("ptr address is NULL\n", procName); return; } if ((paa = *ppaa) == NULL) return; ptraaGetSize(paa, &n); for (i = 0; i < n; i++) { pa = ptraaGetPtra(paa, i, L_REMOVE); ptraDestroy(&pa, freeflag, warnflag); } LEPT_FREE(paa->ptra); LEPT_FREE(paa); *ppaa = NULL; return; }
/*! * \brief pmsDestroy() * * <pre> * Notes: * (1) Important: call this function at the end of the program, after * the last pix has been destroyed. * </pre> */ void pmsDestroy() { L_PIX_MEM_STORE *pms; if ((pms = CustomPMS) == NULL) return; ptraaDestroy(&pms->paa, FALSE, FALSE); /* don't touch the ptrs */ LEPT_FREE(pms->baseptr); /* free the memory */ if (pms->logfile) { pmsLogInfo(); LEPT_FREE(pms->logfile); LEPT_FREE(pms->memused); LEPT_FREE(pms->meminuse); LEPT_FREE(pms->memmax); LEPT_FREE(pms->memempty); } LEPT_FREE(pms->sizes); LEPT_FREE(pms->allocarray); LEPT_FREE(pms->firstptr); LEPT_FREE(pms); CustomPMS = NULL; return; }
/*! * \brief l_byteaDestroy() * * \param[in,out] pba will be set to null before returning * \return void * * <pre> * Notes: * (1) Decrements the ref count and, if 0, destroys the lba. * (2) Always nulls the input ptr. * (3) If the data has been previously removed, the lba will * have been nulled, so this will do nothing. * </pre> */ void l_byteaDestroy(L_BYTEA **pba) { L_BYTEA *ba; PROCNAME("l_byteaDestroy"); if (pba == NULL) { L_WARNING("ptr address is null!\n", procName); return; } if ((ba = *pba) == NULL) return; /* Decrement the ref count. If it is 0, destroy the lba. */ ba->refcount--; if (ba->refcount <= 0) { if (ba->data) LEPT_FREE(ba->data); LEPT_FREE(ba); } *pba = NULL; return; }
/*! * lstackDestroy() * * Input: &lstack (<to be nulled>) * freeflag (TRUE to free each remaining struct in the array) * Return: void * * Notes: * (1) If freeflag is TRUE, frees each struct in the array. * (2) If freeflag is FALSE but there are elements on the array, * gives a warning and destroys the array. This will * cause a memory leak of all the items that were on the lstack. * So if the items require their own destroy function, they * must be destroyed before the lstack. * (3) To destroy the lstack, we destroy the ptr array, then * the lstack, and then null the contents of the input ptr. */ void lstackDestroy(L_STACK **plstack, l_int32 freeflag) { void *item; L_STACK *lstack; PROCNAME("lstackDestroy"); if (plstack == NULL) { L_WARNING("ptr address is NULL\n", procName); return; } if ((lstack = *plstack) == NULL) return; if (freeflag) { while(lstack->n > 0) { item = lstackRemove(lstack); LEPT_FREE(item); } } else if (lstack->n > 0) { L_WARNING("memory leak of %d items in lstack\n", procName, lstack->n); } if (lstack->auxstack) lstackDestroy(&lstack->auxstack, freeflag); if (lstack->array) LEPT_FREE(lstack->array); LEPT_FREE(lstack); *plstack = NULL; }
/*! * barcodeDecode2of5() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Two-out-of-five_code (Note: * the codes given here are wrong!) * http://morovia.com/education/symbology/code25.asp * (2) This is a very low density encoding for the 10 digits. * Each digit is encoded with 5 black bars, of which 2 are wide * and 3 are narrow. No information is carried in the spaces * between the bars, which are all equal in width, represented by * a "1" in our encoding. * (3) The mapping from the sequence of five bar widths to the * digit is identical to the mapping used by the interleaved * 2 of 5 code. The start code is 21211, representing two * wide bars and a narrow bar, and the interleaved "1" spaces * are explicit. The stop code is 21112. For all codes * (including start and stop), the trailing space "1" is * implicit -- there is no reason to represent it in the * Code2of5[] array. */ static char * barcodeDecode2of5(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[10]; l_int32 valid, reverse, i, j, len, error, ndigits, start, found; PROCNAME("barcodeDecodeI2of5"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODE2OF5, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in 2of5 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len - 11) % 10 != 0) return (char *)ERROR_PTR("size not divisible by 10: invalid 2of5 code", procName, NULL); error = FALSE; ndigits = (len - 11) / 10; data = (char *)LEPT_CALLOC(ndigits + 1, sizeof(char)); memset(code, 0, 10); for (i = 0; i < ndigits; i++) { start = 6 + 10 * i; for (j = 0; j < 9; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code, Code2of5[j])) { data[i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; }
/* * pixWriteMixedToPS() * * Input: pixb (<optionall> 1 bpp "mask"; typically for text) * pixc (<optional> 8 or 32 bpp image regions) * scale (relative scale factor for rendering pixb * relative to pixc; typ. 4.0) * pageno (page number in set; use 1 for new output file) * fileout (output ps file) * Return: 0 if OK, 1 on error * * Notes: * (1) This low level function generates the PS string for a mixed * text/image page, and adds it to an existing file if * %pageno > 1. * (2) The two images (pixb and pixc) are typically generated at the * resolution that they will be rendered in the PS file. * (3) pixb is the text component. In the PostScript world, we think of * it as a mask through which we paint black. * (4) pixc is the (typically halftone) image component. It is * white in the rest of the page. To minimize the size of the * PS file, it should be rendered at a resolution that is at * least equal to its actual resolution. * (5) %scale gives the ratio of resolution of pixb to pixc. * Typical resolutions are: 600 ppi for pixb, 150 ppi for pixc; * so %scale = 4.0. If one of the images is not defined, * the value of %scale is ignored. * (6) We write pixc with DCT compression (jpeg). This is followed * by painting the text as black through the mask pixb. If * pixc doesn't exist (alltext), we write the text with the * PS "image" operator instead of the "imagemask" operator, * because ghostscript's ps2pdf is flaky when the latter is used. * (7) The actual output resolution is determined by fitting the * result to a letter-size (8.5 x 11 inch) page. */ l_int32 pixWriteMixedToPS(PIX *pixb, PIX *pixc, l_float32 scale, l_int32 pageno, const char *fileout) { char *tname; const char *op; l_int32 resb, resc, endpage, maskop, ret; PROCNAME("pixWriteMixedToPS"); if (!pixb && !pixc) return ERROR_INT("pixb and pixc both undefined", procName, 1); if (!fileout) return ERROR_INT("fileout not defined", procName, 1); /* Compute the resolution that fills a letter-size page. */ if (!pixc) { resb = getResLetterPage(pixGetWidth(pixb), pixGetHeight(pixb), 0); } else { resc = getResLetterPage(pixGetWidth(pixc), pixGetHeight(pixc), 0); if (pixb) resb = (l_int32)(scale * resc); } /* Write the jpeg image first */ if (pixc) { tname = l_makeTempFilename(NULL); pixWrite(tname, pixc, IFF_JFIF_JPEG); endpage = (pixb) ? FALSE : TRUE; op = (pageno <= 1) ? "w" : "a"; ret = convertJpegToPS(tname, fileout, op, 0, 0, resc, 1.0, pageno, endpage); lept_rmfile(tname); LEPT_FREE(tname); if (ret) return ERROR_INT("jpeg data not written", procName, 1); } /* Write the binary data, either directly or, if there is * a jpeg image on the page, through the mask. */ if (pixb) { tname = l_makeTempFilename(NULL); pixWrite(tname, pixb, IFF_TIFF_G4); op = (pageno <= 1 && !pixc) ? "w" : "a"; maskop = (pixc) ? 1 : 0; ret = convertG4ToPS(tname, fileout, op, 0, 0, resb, 1.0, pageno, maskop, 1); lept_rmfile(tname); LEPT_FREE(tname); if (ret) return ERROR_INT("tiff data not written", procName, 1); } return 0; }
/*! * \brief pixaFindStrokeWidth() * * \param[in] pixa of 1 bpp images * \param[in] thresh fractional count threshold relative to distance 1 * \param[in] tab8 [optional] table for counting fg pixels; can be NULL * \param[in] debug 1 for debug output; 0 to skip * \return na array of stroke widths for each pix in %pixa; NULL on error * * <pre> * Notes: * (1) See pixFindStrokeWidth() for details. * </pre> */ NUMA * pixaFindStrokeWidth(PIXA *pixa, l_float32 thresh, l_int32 *tab8, l_int32 debug) { l_int32 i, n, same, maxd; l_int32 *tab; l_float32 width; NUMA *na; PIX *pix; PROCNAME("pixaFindStrokeWidth"); if (!pixa) return (NUMA *)ERROR_PTR("pixa not defined", procName, NULL); pixaVerifyDepth(pixa, &same, &maxd); if (maxd > 1) return (NUMA *)ERROR_PTR("pix not all 1 bpp", procName, NULL); tab = (tab8) ? tab8 : makePixelSumTab8(); n = pixaGetCount(pixa); na = numaCreate(n); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa, i, L_CLONE); pixFindStrokeWidth(pix, thresh, tab8, &width, NULL); numaAddNumber(na, width); pixDestroy(&pix); } if (!tab8) LEPT_FREE(tab); return na; }
/*! * \brief recogStringToIndex() * * \param[in] recog * \param[in] text text string for some class * \param[out] pindex index for that class; -1 if not found * \return 0 if OK, 1 on error not finding the string is an error */ l_int32 recogStringToIndex(L_RECOG *recog, char *text, l_int32 *pindex) { char *charstr; l_int32 i, n, diff; PROCNAME("recogStringtoIndex"); if (!pindex) return ERROR_INT("&index not defined", procName, 1); *pindex = -1; if (!recog) return ERROR_INT("recog not defined", procName, 1); if (!text) return ERROR_INT("text not defined", procName, 1); /* Search existing characters */ n = recog->setsize; for (i = 0; i < n; i++) { recogGetClassString(recog, i, &charstr); if (!charstr) { L_ERROR("string not found for index %d\n", procName, i); continue; } diff = strcmp(text, charstr); LEPT_FREE(charstr); if (diff) continue; *pindex = i; return 0; } return 1; /* not found */ }
/*! * \brief pixFindStrokeLength() * * \param[in] pixs 1 bpp * \param[in] tab8 [optional] table for counting fg pixels; can be NULL * \param[out] *plength estimated length of the strokes * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) Returns half the number of fg boundary pixels. * </pre> */ l_int32 pixFindStrokeLength(PIX *pixs, l_int32 *tab8, l_int32 *plength) { l_int32 n; l_int32 *tab; PIX *pix1; PROCNAME("pixFindStrokeLength"); if (!plength) return ERROR_INT("&length not defined", procName, 1); *plength = 0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); pix1 = pixExtractBoundary(pixs, 1); tab = (tab8) ? tab8 : makePixelSumTab8(); pixCountPixels(pix1, &n, tab); *plength = n / 2; if (!tab8) LEPT_FREE(tab); pixDestroy(&pix1); return 0; }
/*! * ptraReplace() * * Input: ptra * index (element to be replaced) * item (new generic ptr to a struct; can be null) * freeflag (TRUE to free old item; FALSE to return it) * Return: item (old item, if it exists and is not freed), * or null on error */ void * ptraReplace(L_PTRA *pa, l_int32 index, void *item, l_int32 freeflag) { l_int32 imax; void *olditem; PROCNAME("ptraReplace"); if (!pa) return (void *)ERROR_PTR("pa not defined", procName, NULL); ptraGetMaxIndex(pa, &imax); if (index < 0 || index > imax) return (void *)ERROR_PTR("index not in [0 ... imax]", procName, NULL); olditem = pa->array[index]; pa->array[index] = item; if (!item && olditem) pa->nactual--; else if (item && !olditem) pa->nactual++; if (freeflag == FALSE) return olditem; if (olditem) LEPT_FREE(olditem); return NULL; }
/*! * \brief pmsCustomDealloc() * * \param[in] data to be freed or returned to the storage * \return void */ void pmsCustomDealloc(void *data) { l_int32 level; L_PIX_MEM_STORE *pms; L_PTRA *pa; PROCNAME("pmsCustomDealloc"); if ((pms = CustomPMS) == NULL) { L_ERROR("pms not defined\n", procName); return; } if (pmsGetLevelForDealloc(data, &level) == 1) { L_ERROR("level not found\n", procName); return; } if (level < 0) { /* no logging; just free the data */ LEPT_FREE(data); } else { /* return the data to the store */ pa = ptraaGetPtra(pms->paa, level, L_HANDLE_ONLY); ptraAdd(pa, data); if (pms->logfile) pms->meminuse[level]--; } return; }
/*! * numaCreateFromFArray() * * Input: farray (float) * size (of the array) * copyflag (L_INSERT or L_COPY) * Return: na, or null on error * * Notes: * (1) With L_INSERT, ownership of the input array is transferred * to the returned numa, and all @size elements are considered * to be valid. */ NUMA * numaCreateFromFArray(l_float32 *farray, l_int32 size, l_int32 copyflag) { l_int32 i; NUMA *na; PROCNAME("numaCreateFromFArray"); if (!farray) return (NUMA *)ERROR_PTR("farray not defined", procName, NULL); if (size <= 0) return (NUMA *)ERROR_PTR("size must be > 0", procName, NULL); if (copyflag != L_INSERT && copyflag != L_COPY) return (NUMA *)ERROR_PTR("invalid copyflag", procName, NULL); na = numaCreate(size); if (copyflag == L_INSERT) { if (na->array) LEPT_FREE(na->array); na->array = farray; na->n = size; } else { /* just copy the contents */ for (i = 0; i < size; i++) numaAddNumber(na, farray[i]); } return na; }
/*! * \brief gplotMakeOutput() * * \param[in] gplot * \return 0 if OK; 1 on error * * <pre> * Notes: * (1) This uses gplot and the new arrays to add a plot * to the output, by writing a new data file and appending * the appropriate plot commands to the command file. * (2) This is the only function in this file that requires the * gnuplot executable, to actually generate the plot. * (3) The command file name for unix is canonical (i.e., directory /tmp) * but the temp filename paths in the command file must be correct. * (4) The gnuplot program for windows is wgnuplot.exe. * </pre> */ l_int32 gplotMakeOutput(GPLOT *gplot) { char buf[L_BUF_SIZE]; char *cmdname; l_int32 ignore; PROCNAME("gplotMakeOutput"); if (!gplot) return ERROR_INT("gplot not defined", procName, 1); gplotGenCommandFile(gplot); gplotGenDataFiles(gplot); cmdname = genPathname(gplot->cmdname, NULL); #ifndef _WIN32 snprintf(buf, L_BUF_SIZE, "gnuplot %s", cmdname); #else snprintf(buf, L_BUF_SIZE, "wgnuplot %s", cmdname); #endif /* _WIN32 */ ignore = system(buf); /* gnuplot || wgnuplot */ LEPT_FREE(cmdname); return 0; }
/*! * \brief pixReadMemJpeg() * * \param[in] data const; jpeg-encoded * \param[in] size of data * \param[in] cmflag colormap flag 0 means return RGB image if color; * 1 means create a colormap and return * an 8 bpp colormapped image if color * \param[in] reduction scaling factor: 1, 2, 4 or 8 * \param[out] pnwarn [optional] number of warnings * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default * \return pix, or NULL on error * * <pre> * Notes: * (1) The %size byte of %data must be a null character. * (2) The only hint flag so far is L_JPEG_READ_LUMINANCE, * given in the enum in imageio.h. * (3) See pixReadJpeg() for usage. * </pre> */ PIX * pixReadMemJpeg(const l_uint8 *data, size_t size, l_int32 cmflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint) { l_int32 ret; l_uint8 *comment; FILE *fp; PIX *pix; PROCNAME("pixReadMemJpeg"); if (pnwarn) *pnwarn = 0; if (!data) return (PIX *)ERROR_PTR("data not defined", procName, NULL); if ((fp = fopenReadFromMemory(data, size)) == NULL) return (PIX *)ERROR_PTR("stream not opened", procName, NULL); pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint); if (pix) { ret = fgetJpegComment(fp, &comment); if (!ret && comment) { pixSetText(pix, (char *)comment); LEPT_FREE(comment); } } fclose(fp); if (!pix) L_ERROR("pix not read\n", procName); return pix; }
/*! * \brief bbufferCreate() * * \param[in] indata address in memory [optional] * \param[in] nalloc size of byte array to be alloc'd 0 for default * \return bbuffer, or NULL on error * * <pre> * Notes: * (1) If a buffer address is given, you should read all the data in. * (2) Allocates a bbuffer with associated byte array of * the given size. If a buffer address is given, * it then reads the number of bytes into the byte array. * </pre> */ L_BBUFFER * bbufferCreate(l_uint8 *indata, l_int32 nalloc) { L_BBUFFER *bb; PROCNAME("bbufferCreate"); if (nalloc <= 0) nalloc = INITIAL_BUFFER_ARRAYSIZE; if ((bb = (L_BBUFFER *)LEPT_CALLOC(1, sizeof(L_BBUFFER))) == NULL) return (L_BBUFFER *)ERROR_PTR("bb not made", procName, NULL); if ((bb->array = (l_uint8 *)LEPT_CALLOC(nalloc, sizeof(l_uint8))) == NULL) { LEPT_FREE(bb); return (L_BBUFFER *)ERROR_PTR("byte array not made", procName, NULL); } bb->nalloc = nalloc; bb->nwritten = 0; if (indata) { memcpy((l_uint8 *)bb->array, indata, nalloc); bb->n = nalloc; } else { bb->n = 0; } return bb; }
/*! * \brief l_productMat4() * * \param[in] mat1 square matrix, as a 1-dimensional size^2 array * \param[in] mat2 square matrix, as a 1-dimensional size^2 array * \param[in] mat3 square matrix, as a 1-dimensional size^2 array * \param[in] mat4 square matrix, as a 1-dimensional size^2 array * \param[in] matd square matrix; product stored here * \param[in] size of matrices * \return 0 if OK, 1 on error */ l_int32 l_productMat4(l_float32 *mat1, l_float32 *mat2, l_float32 *mat3, l_float32 *mat4, l_float32 *matd, l_int32 size) { l_float32 *matt; PROCNAME("l_productMat4"); if (!mat1) return ERROR_INT("matrix 1 not defined", procName, 1); if (!mat2) return ERROR_INT("matrix 2 not defined", procName, 1); if (!mat3) return ERROR_INT("matrix 3 not defined", procName, 1); if (!matd) return ERROR_INT("result matrix not defined", procName, 1); if ((matt = (l_float32 *)LEPT_CALLOC(size * size, sizeof(l_float32))) == NULL) return ERROR_INT("matt not made", procName, 1); l_productMat3(mat1, mat2, mat3, matt, size); l_productMat2(matt, mat4, matd, size); LEPT_FREE(matt); return 0; }
/*! * \brief pixWriteTempfile() * * \param[in] dir directory name; use '.' for local dir; no trailing '/' * \param[in] tail [optional] tailname, including extension if any * \param[in] pix * \param[in] format * \param[in] &filename [optional] return actual filename used; use * null to skip * \return 0 if OK; 1 on error * * <pre> * Notes: * (1) This generates a temp filename, writes the pix to it, * and optionally returns the temp filename. * (2) If the filename is returned to a windows program from a DLL, * use lept_free() to free it. * (3) See genTempFilename() for details. We omit the time and pid * here. * </pre> */ l_int32 pixWriteTempfile(const char *dir, const char *tail, PIX *pix, l_int32 format, char **pfilename) { char *filename; l_int32 ret; PROCNAME("pixWriteTempfile"); if (!dir) return ERROR_INT("filename not defined", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); if ((filename = genTempFilename(dir, tail, 0, 0)) == NULL) return ERROR_INT("temp filename not made", procName, 1); ret = pixWrite(filename, pix, format); if (pfilename) *pfilename = filename; else LEPT_FREE(filename); return ret; }
/*! * \brief sudokuCompareState() * * \param[in] sud1, sud2 * \param[in] quads rotation of sud2 input with respect to sud1, * in units of 90 degrees cw * \param[out] psame 1 if all 4 results are identical; 0 otherwise * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) The input to sud2 has been rotated by %quads relative to the * input to sud1. Therefore, we must rotate the solution to * sud1 by the same amount before comparing it to the * solution to sud2. * </pre> */ static l_int32 sudokuCompareState(L_SUDOKU *sud1, L_SUDOKU *sud2, l_int32 quads, l_int32 *psame) { l_int32 i, same; l_int32 *array; PROCNAME("sudokuCompareState"); if (!psame) return ERROR_INT("&same not defined", procName, 1); *psame = 0; if (!sud1) return ERROR_INT("sud1 not defined", procName, 1); if (!sud2) return ERROR_INT("sud1 not defined", procName, 1); if (quads < 1 || quads > 3) return ERROR_INT("valid quads in {1,2,3}", procName, 1); same = TRUE; if ((array = sudokuRotateArray(sud1->state, quads)) == NULL) return ERROR_INT("array not made", procName, 1); for (i = 0; i < 81; i++) { if (array[i] != sud2->state[i]) { same = FALSE; break; } } *psame = same; LEPT_FREE(array); return 0; }
/* postorder DFS */ static void destroy_helper(node *n) { if (!n) return; destroy_helper(n->left); destroy_helper(n->right); LEPT_FREE(n); }
/*! * \brief pixWriteMemGif() * * \param[out] pdata data of gif compressed image * \param[out] psize size of returned data * \param[in] pix * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) See comments in pixReadMemGif() * (2) For Giflib version >= 5.1, this uses the EGifOpen() buffer * interface. No temp files are required. * </pre> */ l_int32 pixWriteMemGif(l_uint8 **pdata, size_t *psize, PIX *pix) { #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 int giferr; l_int32 result; GifFileType *gif; L_BBUFFER *buffer; #else char *fname; #endif /* 5.1 and beyond */ PROCNAME("pixWriteMemGif"); if (!pdata) return ERROR_INT("&data not defined", procName, 1 ); *pdata = NULL; if (!psize) return ERROR_INT("&size not defined", procName, 1 ); *psize = 0; if (!pix) return ERROR_INT("&pix not defined", procName, 1 ); #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 if((buffer = bbufferCreate(NULL, 0)) == NULL) { return ERROR_INT("failed to create buffer", procName, 1); } if ((gif = EGifOpen((void*)buffer, gifWriteFunc, NULL)) == NULL) { bbufferDestroy(&buffer); return ERROR_INT("failed to create GIF image handle", procName, 1); } result = pixToGif(pix, gif); EGifCloseFile(gif, &giferr); if(result == 0) { *pdata = bbufferDestroyAndSaveData(&buffer, psize); } else { bbufferDestroy(&buffer); } return result; #else L_INFO("writing to a temp file, not directly to memory\n", procName); /* Write to a temp file */ fname = l_makeTempFilename(NULL); pixWrite(fname, pix, IFF_GIF); /* Read back into memory */ *pdata = l_binaryRead(fname, psize); lept_rmfile(fname); LEPT_FREE(fname); return 0; #endif }
/*! * \brief recogDestroy() * * \param[in,out] precog will be set to null before returning * \return void */ void recogDestroy(L_RECOG **precog) { L_RECOG *recog; PROCNAME("recogDestroy"); if (!precog) { L_WARNING("ptr address is null\n", procName); return; } if ((recog = *precog) == NULL) return; LEPT_FREE(recog->centtab); LEPT_FREE(recog->sumtab); sarrayDestroy(&recog->sa_text); l_dnaDestroy(&recog->dna_tochar); pixaaDestroy(&recog->pixaa_u); pixaDestroy(&recog->pixa_u); ptaaDestroy(&recog->ptaa_u); ptaDestroy(&recog->pta_u); numaDestroy(&recog->nasum_u); numaaDestroy(&recog->naasum_u); pixaaDestroy(&recog->pixaa); pixaDestroy(&recog->pixa); ptaaDestroy(&recog->ptaa); ptaDestroy(&recog->pta); numaDestroy(&recog->nasum); numaaDestroy(&recog->naasum); pixaDestroy(&recog->pixa_tr); pixaDestroy(&recog->pixadb_ave); pixaDestroy(&recog->pixa_id); pixDestroy(&recog->pixdb_ave); pixDestroy(&recog->pixdb_range); pixaDestroy(&recog->pixadb_boot); pixaDestroy(&recog->pixadb_split); bmfDestroy(&recog->bmf); rchDestroy(&recog->rch); rchaDestroy(&recog->rcha); recogDestroyDid(recog); LEPT_FREE(recog); *precog = NULL; return; }