Exemplo n.º 1
0
/*!
 *  gplotCreate()
 *
 *      Input:  rootname (root for all output files)
 *              outformat (GPLOT_PNG, GPLOT_PS, GPLOT_EPS, GPLOT_X11,
 *                         GPLOT_LATEX)
 *              title  (<optional> overall title)
 *              xlabel (<optional> x axis label)
 *              ylabel (<optional> y axis label)
 *      Return: gplot, or null on error
 *
 *  Notes:
 *      (1) This initializes the plot.
 *      (2) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
 *          double quotes and backquotes, but not single quotes.
 */
GPLOT  *
gplotCreate(const char  *rootname,
            l_int32      outformat,
            const char  *title,
            const char  *xlabel,
            const char  *ylabel)
{
char   *newroot;
char    buf[L_BUF_SIZE];
GPLOT  *gplot;

    PROCNAME("gplotCreate");

    if (!rootname)
        return (GPLOT *)ERROR_PTR("rootname not defined", procName, NULL);
    if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
        outformat != GPLOT_EPS && outformat != GPLOT_X11 &&
        outformat != GPLOT_LATEX)
        return (GPLOT *)ERROR_PTR("outformat invalid", procName, NULL);

    if ((gplot = (GPLOT *)CALLOC(1, sizeof(GPLOT))) == NULL)
        return (GPLOT *)ERROR_PTR("gplot not made", procName, NULL);
    gplot->cmddata = sarrayCreate(0);
    gplot->datanames = sarrayCreate(0);
    gplot->plotdata = sarrayCreate(0);
    gplot->plottitles = sarrayCreate(0);
    gplot->plotstyles = numaCreate(0);

        /* Save title, labels, rootname, outformat, cmdname, outname */
    newroot = genPathname(rootname, NULL);
    gplot->rootname = newroot;
    gplot->outformat = outformat;
    snprintf(buf, L_BUF_SIZE, "%s.cmd", newroot);
    gplot->cmdname = stringNew(buf);
    if (outformat == GPLOT_PNG)
        snprintf(buf, L_BUF_SIZE, "%s.png", newroot);
    else if (outformat == GPLOT_PS)
        snprintf(buf, L_BUF_SIZE, "%s.ps", newroot);
    else if (outformat == GPLOT_EPS)
        snprintf(buf, L_BUF_SIZE, "%s.eps", newroot);
    else if (outformat == GPLOT_LATEX)
        snprintf(buf, L_BUF_SIZE, "%s.tex", newroot);
    else  /* outformat == GPLOT_X11 */
        buf[0] = '\0';
    gplot->outname = stringNew(buf);
    if (title) gplot->title = stringNew(title);
    if (xlabel) gplot->xlabel = stringNew(xlabel);
    if (ylabel) gplot->ylabel = stringNew(ylabel);

    return gplot;
}
/*!
 *  sarraySelectBySubstring()
 *
 *      Input:  sain (input sarray)
 *              substr (<optional> substring for matching; can be NULL)
 *      Return: saout (output sarray, filtered with substring) or null on error
 *
 *  Notes:
 *      (1) This selects all strings in sain that have substr as a substring.
 *          Note that we can't use strncmp() because we're looking for
 *          a match to the substring anywhere within each filename.
 *      (2) If substr == NULL, returns a copy of the sarray.
 */
SARRAY *
sarraySelectBySubstring(SARRAY      *sain,
                        const char  *substr)
{
char    *str;
l_int32  n, i, offset, found;
SARRAY  *saout;

    PROCNAME("sarraySelectBySubstring");

    if (!sain)
        return (SARRAY *)ERROR_PTR("sain not defined", procName, NULL);

    n = sarrayGetCount(sain);
    if (!substr || n == 0)
        return sarrayCopy(sain);

    saout = sarrayCreate(n);
    for (i = 0; i < n; i++) {
        str = sarrayGetString(sain, i, L_NOCOPY);
        arrayFindSequence((l_uint8 *)str, strlen(str), (l_uint8 *)substr,
                          strlen(substr), &offset, &found);
        if (found)
            sarrayAddString(saout, str, L_COPY);
    }

    return saout;
}
/*!
 * \brief   sarraySortByIndex()
 *
 * \param[in]    sain
 * \param[in]    naindex na that maps from the new sarray to the input sarray
 * \return  saout sorted, or NULL on error
 */
SARRAY *
sarraySortByIndex(SARRAY  *sain,
                  NUMA    *naindex)
{
char    *str;
l_int32  i, n, index;
SARRAY  *saout;

    PROCNAME("sarraySortByIndex");

    if (!sain)
        return (SARRAY *)ERROR_PTR("sain not defined", procName, NULL);
    if (!naindex)
        return (SARRAY *)ERROR_PTR("naindex not defined", procName, NULL);

    n = sarrayGetCount(sain);
    saout = sarrayCreate(n);
    for (i = 0; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        str = sarrayGetString(sain, index, L_COPY);
        sarrayAddString(saout, str, L_INSERT);
    }

    return saout;
}
Exemplo n.º 4
0
/*!
 *  strcodeCreate()
 *
 *      Input:  fileno (integer that labels the two output files)
 *      Return: initialized L_StrCode, or null on error
 *
 *  Notes:
 *      (1) This struct exists to build two files containing code for
 *          any number of data objects.  The two files are named
 *             autogen.<fileno>.c
 *             autogen.<fileno>.h
 */
L_STRCODE *
strcodeCreate(l_int32  fileno)
{
L_STRCODE  *strcode;

    PROCNAME("strcodeCreate");

    if ((strcode = (L_STRCODE *)CALLOC(1, sizeof(L_STRCODE))) == NULL)
        return (L_STRCODE *)ERROR_PTR("strcode not made", procName, NULL);

    strcode->fileno = fileno;
    strcode->function = sarrayCreate(0);
    strcode->data = sarrayCreate(0);
    strcode->descr = sarrayCreate(0);
    return strcode;
}
Exemplo n.º 5
0
/*
 *  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;
}
/*!
 * \brief   sarrayRemoveDupsByAset()
 *
 * \param[in]    sas
 * \return  sad with duplicates removed, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) This is O(nlogn), considerably slower than
 *          sarrayRemoveDupsByHash() for large string arrays.
 *      (2) The key for each string is a 64-bit hash.
 *      (3) Build a set, using hashed strings as keys.  As the set is
 *          built, first do a find; if not found, add the key to the
 *          set and add the string to the output sarray.
 * </pre>
 */
SARRAY *
sarrayRemoveDupsByAset(SARRAY  *sas)
{
char     *str;
l_int32   i, n;
l_uint64  hash;
L_ASET   *set;
RB_TYPE   key;
SARRAY   *sad;

    PROCNAME("sarrayRemoveDupsByAset");

    if (!sas)
        return (SARRAY *)ERROR_PTR("sas not defined", procName, NULL);

    set = l_asetCreate(L_UINT_TYPE);
    sad = sarrayCreate(0);
    n = sarrayGetCount(sas);
    for (i = 0; i < n; i++) {
        str = sarrayGetString(sas, i, L_NOCOPY);
        l_hashStringToUint64(str, &hash);
        key.utype = hash;
        if (!l_asetFind(set, key)) {
            sarrayAddString(sad, str, L_COPY);
            l_asetInsert(set, key);
        }
    }

    l_asetDestroy(&set);
    return sad;
}
/*!
 *  sarrayCreateWordsFromString()
 *
 *      Input:  string
 *      Return: sarray, or null on error
 *
 *  Notes:
 *      (1) This finds the number of word substrings, creates an sarray
 *          of this size, and puts copies of each substring into the sarray.
 */
SARRAY *
sarrayCreateWordsFromString(const char  *string)
{
char     separators[] = " \n\t";
l_int32  i, nsub, size, inword;
SARRAY  *sa;

    PROCNAME("sarrayCreateWordsFromString");

    if (!string)
        return (SARRAY *)ERROR_PTR("textstr not defined", procName, NULL);

        /* Find the number of words */
    size = strlen(string);
    nsub = 0;
    inword = FALSE;
    for (i = 0; i < size; i++) {
        if (inword == FALSE &&
           (string[i] != ' ' && string[i] != '\t' && string[i] != '\n')) {
           inword = TRUE;
           nsub++;
        }
        else if (inword == TRUE &&
           (string[i] == ' ' || string[i] == '\t' || string[i] == '\n')) {
           inword = FALSE;
        }
    }

    if ((sa = sarrayCreate(nsub)) == NULL)
        return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);
    sarraySplitString(sa, string, separators);

    return sa;
}
/*!
 *  recogCreate()
 *
 *      Input:  scalew  (scale all widths to this; use 0 for no scaling)
 *              scaleh  (scale all heights to this; use 0 for no scaling)
 *              templ_type (L_USE_AVERAGE or L_USE_ALL)
 *              threshold (for binarization; typically ~128)
 *              maxyshift (from nominal centroid alignment; typically 0 or 1)
 *      Return: recog, or null on error
 *
 *  Notes:
 *      (1) For a set trained on one font, such as numbers in a book,
 *          it is sensible to set scalew = scaleh = 0.
 *      (2) For a mixed training set, scaling to a fixed height,
 *          such as 32 pixels, but leaving the width unscaled, is effective.
 *      (3) The storage for most of the arrays is allocated when training
 *          is finished.
 */
L_RECOG *
recogCreate(l_int32      scalew,
            l_int32      scaleh,
            l_int32      templ_type,
            l_int32      threshold,
            l_int32      maxyshift)
{
L_RECOG  *recog;
PIXA     *pixa;
PIXAA    *paa;

    PROCNAME("recogCreate");

    if (scalew < 0 || scaleh < 0)
        return (L_RECOG *)ERROR_PTR("invalid scalew or scaleh", procName, NULL);
    if (templ_type != L_USE_AVERAGE && templ_type != L_USE_ALL)
        return (L_RECOG *)ERROR_PTR("invalid templ_type flag", procName, NULL);
    if (threshold < 1 || threshold > 255)
        return (L_RECOG *)ERROR_PTR("invalid threshold", procName, NULL);

    if ((recog = (L_RECOG *)CALLOC(1, sizeof(L_RECOG))) == NULL)
        return (L_RECOG *)ERROR_PTR("rec not made", procName, NULL);
    recog->templ_type = templ_type;
    recog->threshold = threshold;
    recog->scalew = scalew;
    recog->scaleh = scaleh;
    recog->maxyshift = maxyshift;
    recog->asperity_fr = DEFAULT_ASPERITY_FRACT;
    recogSetPadParams(recog, NULL, NULL, NULL, -1, -1, -1);
    recog->bmf = bmfCreate(NULL, 6);
    recog->bmf_size = 6;
    recog->maxarraysize = MAX_EXAMPLES_IN_CLASS;
    recog->index = -1;

        /* Generate the LUTs */
    recog->centtab = makePixelCentroidTab8();
    recog->sumtab = makePixelSumTab8();
    recog->sa_text = sarrayCreate(0);
    recog->dna_tochar = l_dnaCreate(0);

        /* Input default values for min component size for splitting.
         * These are overwritten when pixTrainingFinished() is called. */
    recog->min_splitw = 6;
    recog->min_splith = 6;
    recog->max_splith = 60;

        /* Generate the storage for the unscaled training bitmaps */
    paa = pixaaCreate(recog->maxarraysize);
    pixa = pixaCreate(1);
    pixaaInitFull(paa, pixa);
    pixaDestroy(&pixa);
    recog->pixaa_u = paa;

        /* Generate the storage for debugging */
    recog->pixadb_boot = pixaCreate(2);
    recog->pixadb_split = pixaCreate(2);
    return recog;
}
Exemplo n.º 9
0
/*
 *  parseForProtos()
 *
 *      Input:  filein (output of cpp)
 *              prestring (<optional> string that prefaces each decl;
 *                        use NULL to omit)
 *      Return: parsestr (string of function prototypes), or NULL on error
 *
 *  Notes:
 *      (1) We parse the output of cpp:
 *              cpp -ansi <filein> 
 *          Three plans were attempted, with success on the third. 
 *      (2) Plan 1.  A cursory examination of the cpp output indicated that
 *          every function was preceeded by a cpp comment statement.
 *          So we just need to look at statements beginning after comments.
 *          Unfortunately, this is NOT the case.  Some functions start
 *          without cpp comment lines, typically when there are no
 *          comments in the source that immediately precede the function.
 *      (3) Plan 2.  Consider the keywords in the language that start
 *          parts of the cpp file.  Some, like 'typedef', 'enum',
 *          'union' and 'struct', are followed after a while by '{',
 *          and eventually end with '}, plus an optional token and a
 *          final ';'  Others, like 'extern' and 'static', are never
 *          the beginnings of global function definitions.   Function
 *          prototypes have one or more sets of '(' followed eventually
 *          by a ')', and end with ';'.  But function definitions have
 *          tokens, followed by '(', more tokens, ')' and then
 *          immediately a '{'.  We would generate a prototype from this
 *          by adding a ';' to all tokens up to the ')'.  So we use
 *          these special tokens to decide what we are parsing.  And
 *          whenever a function definition is found and the prototype
 *          extracted, we skip through the rest of the function
 *          past the corresponding '}'.  This token ends a line, and
 *          is often on a line of its own.  But as it turns out,
 *          the only keyword we need to consider is 'static'.
 *      (4) Plan 3.  Consider the parentheses and braces for various
 *          declarations.  A struct, enum, or union has a pair of
 *          braces followed by a semicolon.  They cannot have parentheses
 *          before the left brace, but a struct can have lots of parentheses
 *          within the brace set.  A function prototype has no braces.
 *          A function declaration can have sets of left and right
 *          parentheses, but these are followed by a left brace.
 *          So plan 3 looks at the way parentheses and braces are
 *          organized.  Once the beginning of a function definition
 *          is found, the prototype is extracted and we search for
 *          the ending right brace.
 *      (5) To find the ending right brace, it is necessary to do some
 *          careful parsing.  For example, in this file, we have
 *          left and right braces as characters, and these must not
 *          be counted.  Somewhat more tricky, the file fhmtauto.c
 *          generates code, and includes a right brace in a string.
 *          So we must not include braces that are in strings.  But how
 *          do we know if something is inside a string?  Keep state,
 *          starting with not-inside, and every time you hit a double quote
 *          that is not escaped, toggle the condition.  Any brace
 *          found in the state of being within a string is ignored.
 *      (6) When a prototype is extracted, it is put in a canonical
 *          form (i.e., cleaned up).  Finally, we check that it is
 *          not static and save it.  (If static, it is ignored).
 *      (7) The @prestring for unix is NULL; it is included here so that
 *          you can use Microsoft's declaration for importing or
 *          exporting to a dll.  See environ.h for examples of use.
 *          Here, we set: @prestring = "LEPT_DLL ".  Note in particular
 *          the space character that will separate 'LEPT_DLL' from
 *          the standard unix prototype that follows.
 */
char *
parseForProtos(const char *filein,
               const char *prestring)
{
char    *strdata, *str, *newstr, *parsestr, *secondword;
l_int32  nbytes, start, next, stop, charindex, found;
SARRAY  *sa, *saout, *satest;

    PROCNAME("parseForProtos");

    if (!filein)
        return (char *)ERROR_PTR("filein not defined", procName, NULL);

        /* Read in the cpp output into memory, one string for each
         * line in the file, omitting blank lines.  */
    strdata = (char *)arrayRead(filein, &nbytes);
    sa = sarrayCreateLinesFromString(strdata, 0);

    saout = sarrayCreate(0);
    next = 0;
    while (1) {  /* repeat after each non-static prototype is extracted */
        searchForProtoSignature(sa, next, &start, &stop, &charindex, &found);
        if (!found)
            break;
/*        fprintf(stderr, "  start = %d, stop = %d, charindex = %d\n",
                start, stop, charindex); */
        str = captureProtoSignature(sa, start, stop, charindex);

            /* Make sure it is not static.  Note that 'extern' has
             * been prepended to the prototype, so the 'static'
             * keyword, if it exists, would be the second word. */
        satest = sarrayCreateWordsFromString(str);
        secondword = sarrayGetString(satest, 1, 0);
        if (strcmp(secondword, "static")) {  /* not static */
            if (prestring) {  /* prepend it to the prototype */
                newstr = stringJoin(prestring, str);
                sarrayAddString(saout, newstr, L_INSERT);
                FREE(str);
            }
            else
                sarrayAddString(saout, str, L_INSERT);
        }
        else
            FREE(str);
        sarrayDestroy(&satest);

        skipToEndOfFunction(sa, stop, charindex, &next);
        if (next == -1) break;
    }

        /* Flatten into a string with newlines between prototypes */
    parsestr = sarrayToString(saout, 1);
    FREE(strdata);
    sarrayDestroy(&sa);
    sarrayDestroy(&saout);

    return parsestr;
}
Exemplo n.º 10
0
/*!
 *  sarrayCreateLinesFromString()
 *
 *      Input:  string
 *              blankflag  (0 to exclude blank lines; 1 to include)
 *      Return: sarray, or null on error
 *
 *  Notes:
 *      (1) This finds the number of line substrings, creates an sarray of
 *          this size, and puts copies of each substring into the sarray.
 */
SARRAY *
sarrayCreateLinesFromString(char    *string,
                            l_int32  blankflag)
{
l_int32  i, nsub, size, startptr;
char    *cstring, *substring;
SARRAY  *sa;

    PROCNAME("sarrayCreateLinesFromString");

    if (!string)
        return (SARRAY *)ERROR_PTR("textstr not defined", procName, NULL);

        /* find the number of lines */
    size = strlen(string);
    nsub = 0;
    for (i = 0; i < size; i++) {
        if (string[i] == '\n')
            nsub++;
    }

    if ((sa = sarrayCreate(nsub)) == NULL)
        return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);

    if (blankflag) {  /* keep blank lines as null strings */
            /* Make a copy for munging */
        if ((cstring = stringNew(string)) == NULL)
            return (SARRAY *)ERROR_PTR("cstring not made", procName, NULL);
            /* We'll insert nulls like strtok */
        startptr = 0;
        for (i = 0; i < size; i++) {
            if (cstring[i] == '\n') {
                cstring[i] = '\0';
                if ((substring = stringNew(cstring + startptr)) == NULL)
                    return (SARRAY *)ERROR_PTR("substring not made",
                                                procName, NULL);
                sarrayAddString(sa, substring, L_INSERT);
/*                fprintf(stderr, "substring = %s\n", substring); */
                startptr = i + 1;
            }
        }
        if (startptr < size) {  /* no newline at end of last line */
            if ((substring = stringNew(cstring + startptr)) == NULL)
                return (SARRAY *)ERROR_PTR("substring not made",
                                            procName, NULL);
            sarrayAddString(sa, substring, L_INSERT);
/*            fprintf(stderr, "substring = %s\n", substring); */
        }
        FREE(cstring);
    }
    else {  /* remove blank lines; use strtok */
        sarraySplitString(sa, string, "\n");
    }

    return sa;
}
Exemplo n.º 11
0
/*
 *  cleanProtoSignature()
 *
 *      Input:  instr (input prototype string)
 *      Return: cleanstr (clean prototype string), or NULL on error
 *
 *  Notes:
 *      (1) Adds 'extern' at beginning and regularizes spaces
 *          between tokens.
 */
static char *
cleanProtoSignature(char *instr)
{
char    *str, *cleanstr;
char     buf[L_BUF_SIZE];
char     externstring[] = "extern";
l_int32  i, j, nwords, nchars, index, len;
SARRAY  *sa, *saout;

    PROCNAME("cleanProtoSignature");

    if (!instr)
        return (char *)ERROR_PTR("instr not defined", procName, NULL);

    sa = sarrayCreateWordsFromString(instr);
    nwords = sarrayGetCount(sa);
    saout = sarrayCreate(0);
    sarrayAddString(saout, externstring, 1);
    for (i = 0; i < nwords; i++) {
        str = sarrayGetString(sa, i, 0);
        nchars = strlen(str);
        index = 0;
        for (j = 0; j < nchars; j++) {
            if (index > L_BUF_SIZE - 6)
                return (char *)ERROR_PTR("token too large", procName, NULL);
            if (str[j] == '(') {
                buf[index++] = ' ';
                buf[index++] = '(';
                buf[index++] = ' ';
            }
            else if (str[j] == ')') {
                buf[index++] = ' ';
                buf[index++] = ')';
            }
            else 
                buf[index++] = str[j];
        }
        buf[index] = '\0';
        sarrayAddString(saout, buf, 1);
    }

        /* Flatten to a prototype string with spaces added after
         * each word, and remove the last space */
    cleanstr = sarrayToString(saout, 2);
    len = strlen(cleanstr);
    cleanstr[len - 1] = '\0';

    sarrayDestroy(&sa);
    sarrayDestroy(&saout);
    return cleanstr;
}
Exemplo n.º 12
0
/* Build all possible strings, up to a max of 5 roman alphabet characters */
static SARRAY *
BuildShortStrings(l_int32  nchars,  /* 3, 4 or 5 */
                  l_int32  add_dups)
{
    char      buf[64];
    l_int32   i, j, k, l, m;
    l_uint64  hash;
    SARRAY   *sa;

    sa = sarrayCreate(1000);
    for (i = 0; i < 26; i++) {
        sprintf(buf, "%c", i + 0x61);
        sarrayAddString(sa, buf, L_COPY);
        for (j = 0; j < 26; j++) {
            sprintf(buf, "%c%c", i + 0x61, j + 0x61);
            sarrayAddString(sa, buf, L_COPY);
            for (k = 0; k < 26; k++) {
                sprintf(buf, "%c%c%c", i + 0x61, j + 0x61, k + 0x61);
                sarrayAddString(sa, buf, L_COPY);
                if (add_dups && k < 4)  /* add redundant strings */
                    sarrayAddString(sa, buf, L_COPY);
                if (nchars > 3) {
                    for (l = 0; l < 26; l++) {
                        sprintf(buf, "%c%c%c%c", i + 0x61, j + 0x61,
                                k + 0x61, l + 0x61);
                        sarrayAddString(sa, buf, L_COPY);
                        if (add_dups && l < 4)  /* add redundant strings */
                            sarrayAddString(sa, buf, L_COPY);
                        if (nchars > 4) {
                            for (m = 0; m < 26; m++) {
                                sprintf(buf, "%c%c%c%c%c", i + 0x61, j + 0x61,
                                        k + 0x61, l + 0x61, m + 0x61);
                                sarrayAddString(sa, buf, L_COPY);
                                if (!add_dups && i == 17 && j == 12 &&
                                        k == 4 && l == 21) {
                                    l_hashStringToUint64(buf, &hash);
                                    fprintf(stderr, "  %llx\n", hash);
                                }
                                if (add_dups && m < 4)  /* add redundant */
                                    sarrayAddString(sa, buf, L_COPY);
                            }
                        }
                    }
                }
            }
        }
    }

    return sa;
}
Exemplo n.º 13
0
/*!
 * \brief   sarrayIntersectionByHash()
 *
 * \param[in]    sa1, sa2
 * \return  sad intersection of the strings, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) This is faster than sarrayIntersectionByAset(), because the
 *          bucket lookup is O(n).
 * </pre>
 */
SARRAY *
sarrayIntersectionByHash(SARRAY  *sa1,
                         SARRAY  *sa2)
{
char       *str;
l_int32     n1, n2, nsmall, i, index1, index2;
l_uint32    nsize2;
l_uint64    key;
L_DNAHASH  *dahash1, *dahash2;
SARRAY     *sa_small, *sa_big, *sad;

    PROCNAME("sarrayIntersectionByHash");

    if (!sa1)
        return (SARRAY *)ERROR_PTR("sa1 not defined", procName, NULL);
    if (!sa2)
        return (SARRAY *)ERROR_PTR("sa2 not defined", procName, NULL);

        /* Put the elements of the biggest sarray into a dnahash */
    n1 = sarrayGetCount(sa1);
    n2 = sarrayGetCount(sa2);
    sa_small = (n1 < n2) ? sa1 : sa2;   /* do not destroy sa_small */
    sa_big = (n1 < n2) ? sa2 : sa1;   /* do not destroy sa_big */
    dahash1 = l_dnaHashCreateFromSarray(sa_big);

        /* Build up the intersection of strings.  Add to %sad
         * if the string is in sa_big (using dahash1) but hasn't
         * yet been seen in the traversal of sa_small (using dahash2). */
    sad = sarrayCreate(0);
    nsmall = sarrayGetCount(sa_small);
    findNextLargerPrime(nsmall / 20, &nsize2);  /* buckets in hash table */
    dahash2 = l_dnaHashCreate(nsize2, 0);
    for (i = 0; i < nsmall; i++) {
        str = sarrayGetString(sa_small, i, L_NOCOPY);
        sarrayFindStringByHash(sa_big, dahash1, str, &index1);
        if (index1 >= 0) {
            sarrayFindStringByHash(sa_small, dahash2, str, &index2);
            if (index2 == -1) {
                sarrayAddString(sad, str, L_COPY);
                l_hashStringToUint64(str, &key);
                l_dnaHashAdd(dahash2, key, (l_float64)i);
            }
        }
    }

    l_dnaHashDestroy(&dahash1);
    l_dnaHashDestroy(&dahash2);
    return sad;
}
Exemplo n.º 14
0
/*----------------------------------------------------------------------*
 *                      Miscellaneous operations                        *
 *----------------------------------------------------------------------*/
SARRAY *
sarrayGenerateIntegers(l_int32  n)
{
char     buf[32];
l_int32  i;
SARRAY  *sa;

    PROCNAME("sarrayGenerateIntegers");

    if ((sa = sarrayCreate(n)) == NULL)
        return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);
    for (i = 0; i < n; i++) {
        snprintf(buf, sizeof(buf), "%d", i);
        sarrayAddString(sa, buf, L_COPY);
    }
    return sa;
}
Exemplo n.º 15
0
/*!
 *  sarrayReadStream()
 *
 *      Input:  stream
 *      Return: sarray, or null on error
 *
 *  Notes:
 *      (1) We store the size of each string along with the string.
 *      (2) This allows a string to have embedded newlines.  By reading
 *          the entire string, as determined by its size, we are
 *          not affected by any number of embedded newlines.
 */
SARRAY *
sarrayReadStream(FILE  *fp)
{
char    *stringbuf;
l_int32  i, n, size, index, bufsize, ret, version;
SARRAY  *sa;

    PROCNAME("sarrayReadStream");

    if (!fp)
        return (SARRAY *)ERROR_PTR("stream not defined", procName, NULL);

    ret = fscanf(fp, "\nSarray Version %d\n", &version);
    if (ret != 1)
        return (SARRAY *)ERROR_PTR("not an sarray file", procName, NULL);
    if (version != SARRAY_VERSION_NUMBER)
        return (SARRAY *)ERROR_PTR("invalid sarray version", procName, NULL);
    fscanf(fp, "Number of strings = %d\n", &n);

    if ((sa = sarrayCreate(n)) == NULL)
        return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);
    bufsize = L_BUF_SIZE + 1;
    if ((stringbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL)
        return (SARRAY *)ERROR_PTR("stringbuf not made", procName, NULL);

    for (i = 0; i < n; i++) {
	    /* Get the size of the stored string */
        fscanf(fp, "%d[%d]:", &index, &size);
	    /* Expand the string buffer if necessary */
	if (size > bufsize - 5) {
            FREE(stringbuf);
	    bufsize = (l_int32)(1.5 * size);
            stringbuf = (char *)CALLOC(bufsize, sizeof(char));
	}
	    /* Read the stored string, plus leading spaces and trailing \n */
	fread(stringbuf, 1, size + 3, fp);
	    /* Remove the \n that was added by sarrayWriteStream() */
	stringbuf[size + 2] = '\0';
	    /* Copy it in, skipping the 2 leading spaces */
        sarrayAddString(sa, stringbuf + 2, L_COPY);
    }
    fscanf(fp, "\n");

    FREE(stringbuf);
    return sa;
}
Exemplo n.º 16
0
/*!
 *  numaConvertToSarray()
 *
 *      Input:  na
 *              size1 (size of conversion field)
 *              size2 (for float conversion: size of field to the right
 *                     of the decimal point)
 *              addzeros (for integer conversion: to add lead zeros)
 *              type (L_INTEGER_VALUE, L_FLOAT_VALUE)
 *      Return: a sarray of the float values converted to strings
 *              representing either integer or float values; or null on error.
 *
 *  Notes:
 *      (1) For integer conversion, size2 is ignored.
 *          For float conversion, addzeroes is ignored.
 */
SARRAY *
numaConvertToSarray(NUMA    *na,
                    l_int32  size1,
                    l_int32  size2,
                    l_int32  addzeros,
                    l_int32  type)
{
char       fmt[32], strbuf[64];
l_int32    i, n, ival;
l_float32  fval;
SARRAY    *sa;

    PROCNAME("numaConvertToSarray");

    if (!na)
        return (SARRAY *)ERROR_PTR("na not defined", procName, NULL);
    if (type != L_INTEGER_VALUE && type != L_FLOAT_VALUE)
        return (SARRAY *)ERROR_PTR("invalid type", procName, NULL);

    if (type == L_INTEGER_VALUE) {
        if (addzeros)
            snprintf(fmt, sizeof(fmt), "%%0%dd", size1);
        else
            snprintf(fmt, sizeof(fmt), "%%%dd", size1);
    } else {  /* L_FLOAT_VALUE */
        snprintf(fmt, sizeof(fmt), "%%%d.%df", size1, size2);
    }

    n = numaGetCount(na);
    if ((sa = sarrayCreate(n)) == NULL)
        return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);

    for (i = 0; i < n; i++) {
        if (type == L_INTEGER_VALUE) {
            numaGetIValue(na, i, &ival);
            snprintf(strbuf, sizeof(strbuf), fmt, ival);
        } else {  /* L_FLOAT_VALUE */
            numaGetFValue(na, i, &fval);
            snprintf(strbuf, sizeof(strbuf), fmt, fval);
        }
        sarrayAddString(sa, strbuf, L_COPY);
    }

    return sa;
}
Exemplo n.º 17
0
/*!
 * \brief   sarrayRemoveDupsByHash()
 *
 * \param[in]    sas
 * \param[out]   psad unique set of strings; duplicates removed
 * \param[out]   pdahash [optional] dnahash used for lookup
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) Generates a sarray with unique values.
 *      (2) The dnahash is built up with sad to assure uniqueness.
 *          It can be used to find if a string is in the set:
 *              sarrayFindValByHash(sad, dahash, str, \&index)
 *      (3) The hash of the string location is simple and fast.  It scales
 *          up with the number of buckets to insure a fairly random
 *          bucket selection input strings.
 *      (4) This is faster than sarrayRemoveDupsByAset(), because the
 *          bucket lookup is O(n), although there is a double-loop
 *          lookup within the dna in each bucket.
 * </pre>
 */
l_int32
sarrayRemoveDupsByHash(SARRAY      *sas,
                       SARRAY     **psad,
                       L_DNAHASH  **pdahash)
{
char       *str;
l_int32     i, n, index, items;
l_uint32    nsize;
l_uint64    key;
SARRAY     *sad;
L_DNAHASH  *dahash;

    PROCNAME("sarrayRemoveDupsByHash");

    if (pdahash) *pdahash = NULL;
    if (!psad)
        return ERROR_INT("&sad not defined", procName, 1);
    *psad = NULL;
    if (!sas)
        return ERROR_INT("sas not defined", procName, 1);

    n = sarrayGetCount(sas);
    findNextLargerPrime(n / 20, &nsize);  /* buckets in hash table */
    dahash = l_dnaHashCreate(nsize, 8);
    sad = sarrayCreate(n);
    *psad = sad;
    for (i = 0, items = 0; i < n; i++) {
        str = sarrayGetString(sas, i, L_NOCOPY);
        sarrayFindStringByHash(sad, dahash, str, &index);
        if (index < 0) {  /* not found */
            l_hashStringToUint64(str, &key);
            l_dnaHashAdd(dahash, key, (l_float64)items);
            sarrayAddString(sad, str, L_COPY);
            items++;
        }
    }

    if (pdahash)
        *pdahash = dahash;
    else
        l_dnaHashDestroy(&dahash);
    return 0;
}
Exemplo n.º 18
0
/*!
 *  sarrayCopy()
 *
 *      Input:  sarray
 *      Return: copy of sarray, or null on error
 */
SARRAY *
sarrayCopy(SARRAY  *sa)
{
l_int32  i;
SARRAY  *csa;

    PROCNAME("sarrayCopy");

    if (!sa)
        return (SARRAY *)ERROR_PTR("sa not defined", procName, NULL);

    if ((csa = sarrayCreate(sa->nalloc)) == NULL)
        return (SARRAY *)ERROR_PTR("csa not made", procName, NULL);

    for (i = 0; i < sa->n; i++)
        sarrayAddString(csa, sa->array[i], L_COPY);

    return csa;
}
Exemplo n.º 19
0
/*!
 * \brief   sarrayIntersectionByAset()
 *
 * \param[in]    sa1, sa2
 * \return  sad with the intersection of the string set, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) Algorithm: put the smaller sarray into a set, using the string
 *          hashes as the key values.  Then run through the larger sarray,
 *          building an output sarray and a second set from the strings
 *          in the larger array: if a string is in the first set but
 *          not in the second, add the string to the output sarray and hash
 *          it into the second set.  The second set is required to make
 *          sure only one instance of each string is put into the output sarray.
 *          This is O(mlogn), {m,n} = sizes of {smaller,larger} input arrays.
 * </pre>
 */
SARRAY *
sarrayIntersectionByAset(SARRAY  *sa1,
                         SARRAY  *sa2)
{
char     *str;
l_int32   n1, n2, i, n;
l_uint64  hash;
L_ASET   *set1, *set2;
RB_TYPE   key;
SARRAY   *sa_small, *sa_big, *sad;

    PROCNAME("sarrayIntersectionByAset");

    if (!sa1)
        return (SARRAY *)ERROR_PTR("sa1 not defined", procName, NULL);
    if (!sa2)
        return (SARRAY *)ERROR_PTR("sa2 not defined", procName, NULL);

        /* Put the elements of the biggest array into a set */
    n1 = sarrayGetCount(sa1);
    n2 = sarrayGetCount(sa2);
    sa_small = (n1 < n2) ? sa1 : sa2;   /* do not destroy sa_small */
    sa_big = (n1 < n2) ? sa2 : sa1;   /* do not destroy sa_big */
    set1 = l_asetCreateFromSarray(sa_big);

        /* Build up the intersection of strings */
    sad = sarrayCreate(0);
    n = sarrayGetCount(sa_small);
    set2 = l_asetCreate(L_UINT_TYPE);
    for (i = 0; i < n; i++) {
        str = sarrayGetString(sa_small, i, L_NOCOPY);
        l_hashStringToUint64(str, &hash);
        key.utype = hash;
        if (l_asetFind(set1, key) && !l_asetFind(set2, key)) {
            sarrayAddString(sad, str, L_COPY);
            l_asetInsert(set2, key);
        }
    }

    l_asetDestroy(&set1);
    l_asetDestroy(&set2);
    return sad;
}
Exemplo n.º 20
0
/*!
 *  getSortedPathnamesInDirectory()
 *
 *      Input:  directory name
 *              substr (<optional> substring filter on filenames; can be NULL)
 *              firstpage (0-based)
 *              npages (use 0 for all to the end)
 *      Return: sarray of sorted pathnames, or NULL on error
 *
 *  Notes:
 *      (1) If 'substr' is not NULL, only filenames that contain
 *          the substring can be returned.  If 'substr' is NULL,
 *          none of the filenames are filtered out.
 *      (2) The files in the directory, after optional filtering by
 *          the substring, are lexically sorted in increasing order.
 *          The full pathnames are returned for the requested sequence.
 *          If no files are found after filtering, returns an empty sarray.
 */
SARRAY *
getSortedPathnamesInDirectory(const char  *dirname,
                              const char  *substr,
                              l_int32      firstpage,
                              l_int32      npages)
{
char    *fname, *fullname;
l_int32  i, nfiles, lastpage;
SARRAY  *sa, *safiles, *saout;

    PROCNAME("getSortedPathnamesInDirectory");

    if (!dirname)
        return (SARRAY *)ERROR_PTR("dirname not defined", procName, NULL);

    if ((sa = getFilenamesInDirectory(dirname)) == NULL)
        return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);
    safiles = sarraySelectBySubstring(sa, substr);
    sarrayDestroy(&sa);
    nfiles = sarrayGetCount(safiles);
    if (nfiles == 0) {
        L_WARNING("no files found", procName);
        return safiles;
    }

    sarraySort(safiles, safiles, L_SORT_INCREASING);

    firstpage = L_MIN(L_MAX(firstpage, 0), nfiles - 1);
    if (npages == 0)
        npages = nfiles - firstpage;
    lastpage = L_MIN(firstpage + npages - 1, nfiles - 1);

    saout = sarrayCreate(lastpage - firstpage + 1);
    for (i = firstpage; i <= lastpage; i++) {
        fname = sarrayGetString(safiles, i, L_NOCOPY);
        fullname = genPathname(dirname, fname);
        sarrayAddString(saout, fullname, L_INSERT);
    }

    sarrayDestroy(&safiles);
    return saout;
}
Exemplo n.º 21
0
SARRAY *
getFilenamesInDirectory(const char  *dirname)
{
char           *name;
l_int32         len;
SARRAY         *safiles;
DIR            *pdir;
struct dirent  *pdirentry;

    PROCNAME("getFilenamesInDirectory");

    if (!dirname)
        return (SARRAY *)ERROR_PTR("dirname not defined", procName, NULL);

    if ((safiles = sarrayCreate(0)) == NULL)
        return (SARRAY *)ERROR_PTR("safiles not made", procName, NULL);
    if ((pdir = opendir(dirname)) == NULL)
        return (SARRAY *)ERROR_PTR("pdir not opened", procName, NULL);
    while ((pdirentry = readdir(pdir)))  {

        /* It's nice to ignore directories.  For this it is necessary to
         * define _BSD_SOURCE in the CC command, because the DT_DIR
         * flag is non-standard.  */ 
#if !defined(__MINGW32__) && !defined(_CYGWIN_ENVIRON) && !defined(__SOLARIS__)
        if (pdirentry->d_type == DT_DIR)
            continue;
#endif

            /* Filter out "." and ".." if they're passed through */
        name = pdirentry->d_name;
        len = strlen(name);
        if (len == 1 && name[len - 1] == '.') continue;
        if (len == 2 && name[len - 1] == '.' && name[len - 2] == '.') continue;
        sarrayAddString(safiles, name, L_COPY);
    }
    closedir(pdir);

    return safiles;
}
Exemplo n.º 22
0
SARRAY *
getFilenamesInDirectory(const char  *dirname)
{
SARRAY           *safiles;
WIN32_FIND_DATAA  ffd;
size_t            length_of_path;
CHAR              szDir[MAX_PATH];  /* MAX_PATH is defined in stdlib.h */
HANDLE            hFind = INVALID_HANDLE_VALUE;

    PROCNAME("getFilenamesInDirectory");

    if (!dirname)
        return (SARRAY *)ERROR_PTR("dirname not defined", procName, NULL);

    length_of_path = strlen(dirname);
    if (length_of_path > (MAX_PATH - 2))
        return (SARRAY *)ERROR_PTR("dirname is to long", procName, NULL);

    strncpy(szDir, dirname, MAX_PATH);
    szDir[MAX_PATH - 1] = '\0';
    strncat(szDir, TEXT("\\*"), MAX_PATH - strlen(szDir));

    if ((safiles = sarrayCreate(0)) == NULL)
        return (SARRAY *)ERROR_PTR("safiles not made", procName, NULL);
    hFind = FindFirstFileA(szDir, &ffd);
    if (INVALID_HANDLE_VALUE == hFind) {
        sarrayDestroy(&safiles);
        return (SARRAY *)ERROR_PTR("hFind not opened", procName, NULL);
    }

    while (FindNextFileA(hFind, &ffd) != 0) {
        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  /* skip dirs */
            continue;
        sarrayAddString(safiles, ffd.cFileName, L_COPY);
    }

    FindClose(hFind);
    return safiles;
}
Exemplo n.º 23
0
/*!
 *  numaCreateFromString()
 *
 *      Input:  string (of comma-separated numbers)
 *      Return: na, or null on error
 *
 *  Notes:
 *      (1) The numbers can be ints or floats; they will be interpreted
 *          and stored as floats.  To use them as integers (e.g., for
 *          indexing into arrays), use numaGetIValue(...).
 */
NUMA *
numaCreateFromString(const char  *str)
{
char      *substr;
l_int32    i, n, nerrors;
l_float32  val;
NUMA      *na;
SARRAY    *sa;

    PROCNAME("numaCreateFromString");

    if (!str || (strlen(str) == 0))
        return (NUMA *)ERROR_PTR("str not defined or empty", procName, NULL);

    sa = sarrayCreate(0);
    sarraySplitString(sa, str, ",");
    n = sarrayGetCount(sa);
    na = numaCreate(n);
    nerrors = 0;
    for (i = 0; i < n; i++) {
        substr = sarrayGetString(sa, i, L_NOCOPY);
        if (sscanf(substr, "%f", &val) != 1) {
            L_ERROR("substr %d not float\n", procName, i);
            nerrors++;
        } else {
            numaAddNumber(na, val);
        }
    }

    sarrayDestroy(&sa);
    if (nerrors > 0) {
        numaDestroy(&na);
        return (NUMA *)ERROR_PTR("non-floats in string", procName, NULL);
    }

    return na;
}
/*!
 * \brief   l_genDataString()
 *
 * \param[in]    filein input file of serialized data
 * \param[in]    ifunc index into set of functions in output file
 * \return  encoded ascii data string, or NULL on error reading from file
 */
static char *
l_genDataString(const char  *filein,
                l_int32      ifunc)
{
char      buf[80];
char     *cdata1, *cdata2, *cdata3;
l_uint8  *data1, *data2;
l_int32   csize1, csize2;
size_t    size1, size2;
SARRAY   *sa;

    PROCNAME("l_genDataString");

    if (!filein)
        return (char *)ERROR_PTR("filein not defined", procName, NULL);

        /* Read it in, gzip it, encode, and reformat.  We gzip because some
         * serialized data has a significant amount of ascii content. */
    if ((data1 = l_binaryRead(filein, &size1)) == NULL)
        return (char *)ERROR_PTR("bindata not returned", procName, NULL);
    data2 = zlibCompress(data1, size1, &size2);
    cdata1 = encodeBase64(data2, size2, &csize1);
    cdata2 = reformatPacked64(cdata1, csize1, 4, 72, 1, &csize2);
    LEPT_FREE(data1);
    LEPT_FREE(data2);
    LEPT_FREE(cdata1);

        /* Prepend the string declaration signature and put it together */
    sa = sarrayCreate(3);
    snprintf(buf, sizeof(buf), "static const char *l_strdata_%d =\n", ifunc);
    sarrayAddString(sa, buf, L_COPY);
    sarrayAddString(sa, cdata2, L_INSERT);
    sarrayAddString(sa, (char *)";\n", L_COPY);
    cdata3 = sarrayToString(sa, 0);
    sarrayDestroy(&sa);
    return cdata3;
}
Exemplo n.º 25
0
int main(int    argc,
         char **argv)
{
char        *filein, *str, *prestring, *outprotos, *protostr;
const char  *spacestr = " ";
char         buf[L_BUF_SIZE];
l_uint8     *allheaders;
l_int32      i, maxindex, in_line, nflags, protos_added, firstfile, len, ret;
size_t       nbytes;
L_BYTEA     *ba, *ba2;
SARRAY      *sa, *safirst;
static char  mainName[] = "xtractprotos";

    if (argc == 1) {
        fprintf(stderr,
                "xtractprotos [-prestring=<string>] [-protos=<where>] "
                "[list of C files]\n"
                "where the prestring is prepended to each prototype, and \n"
                "protos can be either 'inline' or the name of an output "
                "prototype file\n");
        return 1;
    }

    /* ---------------------------------------------------------------- */
    /* Parse input flags and find prestring and outprotos, if requested */
    /* ---------------------------------------------------------------- */
    prestring = outprotos = NULL;
    in_line = FALSE;
    nflags = 0;
    maxindex = L_MIN(3, argc);
    for (i = 1; i < maxindex; i++) {
        if (argv[i][0] == '-') {
            if (!strncmp(argv[i], "-prestring", 10)) {
                nflags++;
                ret = sscanf(argv[i] + 1, "prestring=%s", buf);
                if (ret != 1) {
                    fprintf(stderr, "parse failure for prestring\n");
                    return 1;
                }
                if ((len = strlen(buf)) > L_BUF_SIZE - 3) {
                    L_WARNING("prestring too large; omitting!\n", mainName);
                } else {
                    buf[len] = ' ';
                    buf[len + 1] = '\0';
                    prestring = stringNew(buf);
                }
            } else if (!strncmp(argv[i], "-protos", 7)) {
                nflags++;
                ret = sscanf(argv[i] + 1, "protos=%s", buf);
                if (ret != 1) {
                    fprintf(stderr, "parse failure for protos\n");
                    return 1;
                }
                outprotos = stringNew(buf);
                if (!strncmp(outprotos, "inline", 7))
                    in_line = TRUE;
            }
        }
    }

    if (argc - nflags < 2) {
        fprintf(stderr, "no files specified!\n");
        return 1;
    }


    /* ---------------------------------------------------------------- */
    /*                   Generate the prototype string                  */
    /* ---------------------------------------------------------------- */
    ba = l_byteaCreate(500);

        /* First the extern C head */
    sa = sarrayCreate(0);
    sarrayAddString(sa, (char *)"/*", 1);
    snprintf(buf, L_BUF_SIZE,
             " *  These prototypes were autogen'd by xtractprotos, v. %s",
             version);
    sarrayAddString(sa, buf, 1);
    sarrayAddString(sa, (char *)" */", 1);
    sarrayAddString(sa, (char *)"#ifdef __cplusplus", 1);
    sarrayAddString(sa, (char *)"extern \"C\" {", 1);
    sarrayAddString(sa, (char *)"#endif  /* __cplusplus */\n", 1);
    str = sarrayToString(sa, 1);
    l_byteaAppendString(ba, str);
    lept_free(str);
    sarrayDestroy(&sa);

        /* Then the prototypes */
    firstfile = 1 + nflags;
    protos_added = FALSE;
    for (i = firstfile; i < argc; i++) {
        filein = argv[i];
	len = strlen(filein);
	if (filein[len - 1] == 'h')  /* skip .h files */
	    continue;
	snprintf(buf, L_BUF_SIZE, "cpp -ansi -DNO_PROTOS %s %s",
	         filein, tempfile);
	ret = system(buf);
	if (ret) {
            fprintf(stderr, "cpp failure for %s; continuing\n", filein);
	    continue;
	}

	if ((str = parseForProtos(tempfile, prestring)) == NULL) {
            fprintf(stderr, "parse failure for %s; continuing\n", filein);
	    continue;
	}
	if (strlen(str) > 1) {  /* strlen(str) == 1 is a file without protos */
            l_byteaAppendString(ba, str);
            protos_added = TRUE;
        }
        lept_free(str);
    }

        /* Lastly the extern C tail */
    sa = sarrayCreate(0);
    sarrayAddString(sa, (char *)"\n#ifdef __cplusplus", 1);
    sarrayAddString(sa, (char *)"}", 1);
    sarrayAddString(sa, (char *)"#endif  /* __cplusplus */", 1);
    str = sarrayToString(sa, 1);
    l_byteaAppendString(ba, str);
    lept_free(str);
    sarrayDestroy(&sa);

    protostr = (char *)l_byteaCopyData(ba, &nbytes);
    l_byteaDestroy(&ba);


    /* ---------------------------------------------------------------- */
    /*                       Generate the output                        */
    /* ---------------------------------------------------------------- */
    if (!outprotos) {  /* just write to stdout */
        fprintf(stderr, "%s\n", protostr);
        lept_free(protostr);
        return 0;
    }

        /* If no protos were found, do nothing further */
    if (!protos_added) {
        fprintf(stderr, "No protos found\n");
        lept_free(protostr);
        return 1;
    }

        /* Make the output files */
    ba = l_byteaInitFromFile("allheaders_top.txt");
    if (!in_line) {
        snprintf(buf, sizeof(buf), "#include \"%s\"\n", outprotos);
        l_byteaAppendString(ba, buf);
        l_binaryWrite(outprotos, "w", protostr, nbytes);
    } else {
        l_byteaAppendString(ba, protostr);
    }
    ba2 = l_byteaInitFromFile("allheaders_bot.txt");
    l_byteaJoin(ba, &ba2);
    l_byteaWrite("allheaders.h", ba, 0, 0);
    l_byteaDestroy(&ba);
    lept_free(protostr);
    return 0;
}
Exemplo n.º 26
0
/*!
 * \brief   recogCreate()
 *
 * \param[in]    scalew  scale all widths to this; use 0 otherwise
 * \param[in]    scaleh  scale all heights to this; use 0 otherwise
 * \param[in]    linew   width of normalized strokes; use 0 to skip
 * \param[in]    threshold for binarization; typically ~128; 0 for default
 * \param[in]    maxyshift from nominal centroid alignment; default is 1
 * \return  recog, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) If %scalew == 0 and %scaleh == 0, no scaling is done.
 *          If one of these is 0 and the other is > 0, scaling is isotropic
 *          to the requested size.  We typically do not set both > 0.
 *      (2) Use linew > 0 to convert the templates to images with fixed
 *          width strokes.  linew == 0 skips the conversion.
 *      (3) The only valid values for %maxyshift are 0, 1 and 2.
 *          It is recommended to use %maxyshift == 1 (default value).
 *          Using %maxyshift == 0 is much faster than %maxyshift == 1, but
 *          it is much less likely to find the template with the best
 *          correlation.  Use of anything but 1 results in a warning.
 *      (4) Scaling is used for finding outliers and for training a
 *          book-adapted recognizer (BAR) from a bootstrap recognizer (BSR).
 *          Scaling the height to a fixed value and scaling the width
 *          accordingly (e.g., %scaleh = 40, %scalew = 0) is recommended.
 *      (5) The storage for most of the arrays is allocated when training
 *          is finished.
 * </pre>
 */
L_RECOG *
recogCreate(l_int32      scalew,
            l_int32      scaleh,
            l_int32      linew,
            l_int32      threshold,
            l_int32      maxyshift)
{
L_RECOG  *recog;

    PROCNAME("recogCreate");

    if (scalew < 0 || scaleh < 0)
        return (L_RECOG *)ERROR_PTR("invalid scalew or scaleh", procName, NULL);
    if (linew > 10)
        return (L_RECOG *)ERROR_PTR("invalid linew > 10", procName, NULL);
    if (threshold == 0) threshold = DEFAULT_THRESHOLD;
    if (threshold < 0 || threshold > 255) {
        L_WARNING("invalid threshold; using default\n", procName);
        threshold = DEFAULT_THRESHOLD;
    }
    if (maxyshift < 0 || maxyshift > 2) {
         L_WARNING("invalid maxyshift; using default value\n", procName);
         maxyshift = DEFAULT_MAXYSHIFT;
    } else if (maxyshift == 0) {
         L_WARNING("Using maxyshift = 0; faster, worse correlation results\n",
                   procName);
    } else if (maxyshift == 2) {
         L_WARNING("Using maxyshift = 2; slower\n", procName);
    }

    if ((recog = (L_RECOG *)LEPT_CALLOC(1, sizeof(L_RECOG))) == NULL)
        return (L_RECOG *)ERROR_PTR("rec not made", procName, NULL);
    recog->templ_use = L_USE_ALL_TEMPLATES;  /* default */
    recog->threshold = threshold;
    recog->scalew = scalew;
    recog->scaleh = scaleh;
    recog->linew = linew;
    recog->maxyshift = maxyshift;
    recogSetParams(recog, 1, -1, -1.0, -1.0);
    recog->bmf = bmfCreate(NULL, 6);
    recog->bmf_size = 6;
    recog->maxarraysize = MAX_EXAMPLES_IN_CLASS;

        /* Generate the LUTs */
    recog->centtab = makePixelCentroidTab8();
    recog->sumtab = makePixelSumTab8();
    recog->sa_text = sarrayCreate(0);
    recog->dna_tochar = l_dnaCreate(0);

        /* Input default values for min component size for splitting.
         * These are overwritten when pixTrainingFinished() is called. */
    recog->min_splitw = 6;
    recog->max_splith = 60;

        /* Allocate the paa for the unscaled training bitmaps */
    recog->pixaa_u = pixaaCreate(recog->maxarraysize);

        /* Generate the storage for debugging */
    recog->pixadb_boot = pixaCreate(2);
    recog->pixadb_split = pixaCreate(2);
    return recog;
}
Exemplo n.º 27
0
/*!
 *  pixMorphCompSequenceDwa()
 *
 *      Input:  pixs
 *              sequence (string specifying sequence)
 *              dispsep (horizontal separation in pixels between
 *                       successive displays; use zero to suppress display)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) This does dwa morphology on binary images, using brick Sels.
 *      (2) This runs a pipeline of operations; no branching is allowed.
 *      (3) It implements all brick Sels that have dimensions up to 63
 *          on each side, using a composite (linear + comb) when useful.
 *      (4) A new image is always produced; the input image is not changed.
 *      (5) This contains an interpreter, allowing sequences to be
 *          generated and run.
 *      (6) See pixMorphSequence() for further information about usage.
 */
PIX *
pixMorphCompSequenceDwa(PIX         *pixs,
                        const char  *sequence,
                        l_int32      dispsep)
{
char    *rawop, *op;
l_int32  nops, i, j, nred, fact, w, h, x, y, border;
l_int32  level[4];
PIX     *pixt1, *pixt2;
SARRAY  *sa;

    PROCNAME("pixMorphCompSequenceDwa");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (!sequence)
        return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);

        /* Split sequence into individual operations */
    sa = sarrayCreate(0);
    sarraySplitString(sa, sequence, "+");
    nops = sarrayGetCount(sa);

    if (!morphSequenceVerify(sa)) {
        sarrayDestroy(&sa);
        return (PIX *)ERROR_PTR("sequence not valid", procName, NULL);
    }

        /* Parse and operate */
    border = 0;
    pixt1 = pixCopy(NULL, pixs);
    pixt2 = NULL;
    x = y = 0;
    for (i = 0; i < nops; i++) {
        rawop = sarrayGetString(sa, i, 0);
        op = stringRemoveChars(rawop, " \n\t");
        switch (op[0])
        {
        case 'd':
        case 'D':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixDilateCompBrickDwa(NULL, pixt1, w, h);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'e':
        case 'E':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixErodeCompBrickDwa(NULL, pixt1, w, h);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'o':
        case 'O':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixOpenCompBrickDwa(pixt1, pixt1, w, h);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'c':
        case 'C':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixCloseCompBrickDwa(pixt1, pixt1, w, h);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'r':
        case 'R':
            nred = strlen(op) - 1;
            for (j = 0; j < nred; j++)
                level[j] = op[j + 1] - '0';
            for (j = nred; j < 4; j++)
                level[j] = 0;
            pixt2 = pixReduceRankBinaryCascade(pixt1, level[0], level[1],
                                               level[2], level[3]);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'x':
        case 'X':
            sscanf(&op[1], "%d", &fact);
            pixt2 = pixExpandReplicate(pixt1, fact);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'b':
        case 'B':
            sscanf(&op[1], "%d", &border);
            pixt2 = pixAddBorder(pixt1, border, 0);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        default:
            /* All invalid ops are caught in the first pass */
            break;
        }
        FREE(op);
    }
    if (border > 0) {
        pixt2 = pixRemoveBorder(pixt1, border);
        pixDestroy(&pixt1);
        pixt1 = pixClone(pixt2);
        pixDestroy(&pixt2);
    }

    sarrayDestroy(&sa);
    return pixt1;
}
Exemplo n.º 28
0
/*!
 *  gplotAddPlot()
 *
 *      Input:  gplot
 *              nax (<optional> numa: set to null for Y_VS_I;
 *                   required for Y_VS_X)
 *              nay (numa: required for both Y_VS_I and Y_VS_X)
 *              plotstyle (GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES,
 *                         GPLOT_LINESPOINTS, GPLOT_DOTS)
 *              plottitle  (<optional> title for individual plot)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) There are 2 options for (x,y) values:
 *            o  To plot an array vs a linear function of the
 *               index, set nax = NULL.
 *            o  To plot one array vs another, use both nax and nay.
 *      (2) If nax is NULL, the x value corresponding to the i-th
 *          value of nay is found from the startx and delx fields
 *          in nay:
 *               x = startx + i * delx
 *          These are set with numaSetParameters().  Their default
 *          values are startx = 0.0, delx = 1.0.
 *      (3) If nax is defined, it must be the same size as nay.
 *      (4) The 'plottitle' string can have spaces, double
 *          quotes and backquotes, but not single quotes.
 */
l_int32
gplotAddPlot(GPLOT       *gplot,
             NUMA        *nax,
             NUMA        *nay,
             l_int32      plotstyle,
             const char  *plottitle)
{
char       buf[L_BUF_SIZE];
char       emptystring[] = "";
char      *datastr, *title;
l_int32    n, i;
l_float32  valx, valy, startx, delx;
SARRAY    *sa;

    PROCNAME("gplotAddPlot");

    if (!gplot)
        return ERROR_INT("gplot not defined", procName, 1);
    if (!nay)
        return ERROR_INT("nay not defined", procName, 1);
    if (plotstyle != GPLOT_LINES && plotstyle != GPLOT_POINTS &&
        plotstyle != GPLOT_IMPULSES && plotstyle != GPLOT_LINESPOINTS &&
        plotstyle != GPLOT_DOTS)
        return ERROR_INT("invalid plotstyle", procName, 1);

    n = numaGetCount(nay);
    numaGetParameters(nay, &startx, &delx);
    if (nax) {
        if (n != numaGetCount(nax))
            return ERROR_INT("nax and nay sizes differ", procName, 1);
    }

        /* Save plotstyle and plottitle */
    numaAddNumber(gplot->plotstyles, plotstyle);
    if (plottitle) {
        title = stringNew(plottitle);
        sarrayAddString(gplot->plottitles, title, L_INSERT);
    } else {
        sarrayAddString(gplot->plottitles, emptystring, L_COPY);
    }

        /* Generate and save data filename */
    gplot->nplots++;
    snprintf(buf, L_BUF_SIZE, "%s.data.%d", gplot->rootname, gplot->nplots);
    sarrayAddString(gplot->datanames, buf, L_COPY);

        /* Generate data and save as a string */
    sa = sarrayCreate(n);
    for (i = 0; i < n; i++) {
        if (nax)
            numaGetFValue(nax, i, &valx);
        else
            valx = startx + i * delx;
        numaGetFValue(nay, i, &valy);
        snprintf(buf, L_BUF_SIZE, "%f %f\n", valx, valy);
        sarrayAddString(sa, buf, L_COPY);
    }
    datastr = sarrayToString(sa, 0);
    sarrayAddString(gplot->plotdata, datastr, L_INSERT);
    sarrayDestroy(&sa);

    return 0;
}
Exemplo n.º 29
0
/*!
 *  pixGrayMorphSequence()
 *
 *      Input:  pixs
 *              sequence (string specifying sequence)
 *              dispsep (horizontal separation in pixels between
 *                       successive displays; use zero to suppress display)
 *              dispy (if dispsep != 0, this gives the y-value of the
 *                     UL corner for display; otherwise it is ignored)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) This works on 8 bpp grayscale images.
 *      (2) This runs a pipeline of operations; no branching is allowed.
 *      (3) This only uses brick SELs.
 *      (4) A new image is always produced; the input image is not changed.
 *      (5) This contains an interpreter, allowing sequences to be
 *          generated and run.
 *      (6) The format of the sequence string is defined below.
 *      (7) In addition to morphological operations, the composite
 *          morph/subtract tophat can be performed.
 *      (8) Sel sizes (width, height) must each be odd numbers.
 *      (9) Intermediate results can optionally be displayed
 *      (10) The sequence string is formatted as follows:
 *            - An arbitrary number of operations,  each separated
 *              by a '+' character.  White space is ignored.
 *            - Each operation begins with a case-independent character
 *              specifying the operation:
 *                 d or D  (dilation)
 *                 e or E  (erosion)
 *                 o or O  (opening)
 *                 c or C  (closing)
 *                 t or T  (tophat)
 *            - The args to the morphological operations are bricks of hits,
 *              and are formatted as a.b, where a and b are horizontal and
 *              vertical dimensions, rsp. (each must be an odd number)
 *            - The args to the tophat are w or W (for white tophat)
 *              or b or B (for black tophat), followed by a.b as for
 *              the dilation, erosion, opening and closing.
 *           Example valid sequences are:
 *             "c5.3 + o7.5"
 *             "c9.9 + tw9.9"
 */
PIX *
pixGrayMorphSequence(PIX         *pixs,
                     const char  *sequence,
                     l_int32      dispsep,
                     l_int32      dispy)
{
char    *rawop, *op;
l_int32  nops, i, valid, w, h, x;
PIX     *pixt1, *pixt2;
SARRAY  *sa;

    PROCNAME("pixGrayMorphSequence");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (!sequence)
        return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);

        /* Split sequence into individual operations */
    sa = sarrayCreate(0);
    sarraySplitString(sa, sequence, "+");
    nops = sarrayGetCount(sa);

        /* Verify that the operation sequence is valid */
    valid = TRUE;
    for (i = 0; i < nops; i++) {
        rawop = sarrayGetString(sa, i, 0);
        op = stringRemoveChars(rawop, " \n\t");
        switch (op[0])
        {
        case 'd':
        case 'D':
        case 'e':
        case 'E':
        case 'o':
        case 'O':
        case 'c':
        case 'C':
            if (sscanf(&op[1], "%d.%d", &w, &h) != 2) {
                fprintf(stderr, "*** op: %s invalid\n", op);
                valid = FALSE;
                break;
            }
            if (w < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
                fprintf(stderr,
                        "*** op: %s; w = %d, h = %d; must both be odd\n",
                        op, w, h);
                valid = FALSE;
                break;
            }
/*            fprintf(stderr, "op = %s; w = %d, h = %d\n", op, w, h); */
            break;
        case 't':
        case 'T':
            if (op[1] != 'w' && op[1] != 'W' &&
                op[1] != 'b' && op[1] != 'B') {
                fprintf(stderr,
                        "*** op = %s; arg %c must be 'w' or 'b'\n", op, op[1]);
                valid = FALSE;
                break;
            }
            sscanf(&op[2], "%d.%d", &w, &h);
            if (w < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
                fprintf(stderr,
                        "*** op: %s; w = %d, h = %d; must both be odd\n",
                        op, w, h);
                valid = FALSE;
                break;
            }
/*            fprintf(stderr, "op = %s", op); */
            break;
        default:
            fprintf(stderr, "*** nonexistent op = %s\n", op);
            valid = FALSE;
        }
        FREE(op);
    }
    if (!valid) {
        sarrayDestroy(&sa);
        return (PIX *)ERROR_PTR("sequence invalid", procName, NULL);
    }

        /* Parse and operate */
    pixt1 = pixCopy(NULL, pixs);
    pixt2 = NULL;
    x = 0;
    for (i = 0; i < nops; i++) {
        rawop = sarrayGetString(sa, i, 0);
        op = stringRemoveChars(rawop, " \n\t");
        switch (op[0])
        {
        case 'd':
        case 'D':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixDilateGray(pixt1, w, h);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, dispy);
                x += dispsep;
            }
            break;
        case 'e':
        case 'E':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixErodeGray(pixt1, w, h);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, dispy);
                x += dispsep;
            }
            break;
        case 'o':
        case 'O':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixOpenGray(pixt1, w, h);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, dispy);
                x += dispsep;
            }
            break;
        case 'c':
        case 'C':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixCloseGray(pixt1, w, h);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, dispy);
                x += dispsep;
            }
            break;
        case 't':
        case 'T':
            sscanf(&op[2], "%d.%d", &w, &h);
            if (op[1] == 'w' || op[1] == 'W')
                pixt2 = pixTophat(pixt1, w, h, L_TOPHAT_WHITE);
            else   /* 'b' or 'B' */
                pixt2 = pixTophat(pixt1, w, h, L_TOPHAT_BLACK);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, dispy);
                x += dispsep;
            }
            break;
        default:
            /* All invalid ops are caught in the first pass */
            break;
        }
        FREE(op);
    }

    sarrayDestroy(&sa);
    return pixt1;
}
Exemplo n.º 30
0
main(int    argc,
     char **argv)
{
char        *errorstr;
l_int32      same, error;
PIX         *pixs1, *pixs2, *pixs4, *pixs8, *pixs16, *pixs32,  *pixd;
PIX         *pixc2, *pixc4, *pixc8;
PIX         *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6;
PIXCMAP     *cmap;
SARRAY      *sa;
static char  mainName[] = "convert_reg";

    if (argc != 1)
        exit(ERROR_INT(" Syntax:  convert_rt", mainName, 1));

    if ((pixs1 = pixRead("test1.png")) == NULL)
	exit(ERROR_INT("pixs1 not made", mainName, 1));
    if ((pixs2 = pixRead("dreyfus2.png")) == NULL)
	exit(ERROR_INT("pixs2 not made", mainName, 1));
    if ((pixc2 = pixRead("weasel2.4c.png")) == NULL)
	exit(ERROR_INT("pixc2 not made", mainName, 1));
    if ((pixs4 = pixRead("weasel4.16g.png")) == NULL)
	exit(ERROR_INT("pixs4 not made", mainName, 1));
    if ((pixc4 = pixRead("weasel4.11c.png")) == NULL)
	exit(ERROR_INT("pixc4 not made", mainName, 1));
    if ((pixs8 = pixRead("karen8.jpg")) == NULL)
	exit(ERROR_INT("pixs8 not made", mainName, 1));
    if ((pixc8 = pixRead("weasel8.240c.png")) == NULL)
	exit(ERROR_INT("pixc8 not made", mainName, 1));
    if ((pixs16 = pixRead("test16.tif")) == NULL)
	exit(ERROR_INT("pixs16 not made", mainName, 1));
    if ((pixs32 = pixRead("marge.jpg")) == NULL)
	exit(ERROR_INT("pixs32 not made", mainName, 1));
    error = FALSE;
    sa = sarrayCreate(0);

        /* Conversion: 1 bpp --> 8 bpp --> 1 bpp */
    pixt1 = pixConvertTo8(pixs1, FALSE);
    pixt2 = pixThreshold8(pixt1, 1, 0, 0);
    pixEqual(pixs1, pixt2, &same);
    if (!same) {
        pixDisplayWithTitle(pixs1, 100, 100, "1 bpp, no cmap", DFLAG);
        pixDisplayWithTitle(pixt2, 500, 100, "1 bpp, no cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 1 bpp <==> 8 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 1 bpp <==> 8 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

        /* Conversion: 2 bpp --> 8 bpp --> 2 bpp */
        /* Conversion: 2 bpp cmap --> 8 bpp cmap --> 2 bpp cmap */
    pixt1 = pixRemoveColormap(pixs2, REMOVE_CMAP_TO_GRAYSCALE);
    pixt2 = pixThreshold8(pixt1, 2, 4, 0);
    pixt3 = pixConvertTo8(pixt2, FALSE);
    pixt4 = pixThreshold8(pixt3, 2, 4, 0);
    pixEqual(pixt2, pixt4, &same);
    if (!same) {
        pixDisplayWithTitle(pixt2, 100, 100, "2 bpp, no cmap", DFLAG);
        pixDisplayWithTitle(pixt4, 500, 100, "2 bpp, no cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 2 bpp <==> 8 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 2 bpp <==> 8 bpp\n");
    pixt5 = pixConvertTo8(pixs2, TRUE);
    pixt6 = pixThreshold8(pixt5, 2, 4, 1);
    pixEqual(pixs2, pixt6, &same);
    if (!same) {
        pixDisplayWithTitle(pixs2, 100, 100, "2 bpp, cmap", DFLAG);
        pixDisplayWithTitle(pixt6, 500, 100, "2 bpp, cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 2 bpp <==> 8 bpp; cmap",
                        L_COPY);
    } else
        fprintf(stderr, "OK: conversion 2 bpp <==> 8 bpp; cmap\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    pixDestroy(&pixt6);

        /* Conversion: 4 bpp --> 8 bpp --> 4 bpp */
        /* Conversion: 4 bpp cmap --> 8 bpp cmap --> 4 bpp cmap */
    pixt1 = pixRemoveColormap(pixs4, REMOVE_CMAP_TO_GRAYSCALE);
    pixt2 = pixThreshold8(pixt1, 4, 16, 0);
    pixt3 = pixConvertTo8(pixt2, FALSE);
    pixt4 = pixThreshold8(pixt3, 4, 16, 0);
    pixEqual(pixt2, pixt4, &same);
    if (!same) {
        pixDisplayWithTitle(pixt2, 100, 100, "4 bpp, no cmap", DFLAG);
        pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, no cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 4 bpp <==> 8 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 4 bpp <==> 8 bpp\n");
    pixt5 = pixConvertTo8(pixs4, TRUE);
    pixt6 = pixThreshold8(pixt5, 4, 16, 1);
    pixEqual(pixs4, pixt6, &same);
    if (!same) {
        pixDisplayWithTitle(pixs4, 100, 100, "4 bpp, cmap", DFLAG);
        pixDisplayWithTitle(pixt6, 500, 100, "4 bpp, cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 4 bpp <==> 8 bpp, cmap",
                        L_COPY);
    } else
        fprintf(stderr, "OK: conversion 4 bpp <==> 8 bpp; cmap\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    pixDestroy(&pixt6);

        /* Conversion: 2 bpp cmap --> 2 bpp --> 2 bpp cmap --> 2 bpp */
    pixt1 = pixRemoveColormap(pixs2, REMOVE_CMAP_TO_GRAYSCALE);
    pixt2 = pixConvertGrayToColormap(pixt1);
    pixt3 = pixRemoveColormap(pixt2, REMOVE_CMAP_TO_GRAYSCALE);
    pixt4 = pixThresholdTo2bpp(pixt3, 4, 1);
    pixEqual(pixt1, pixt4, &same);
    if (!same) {
        pixDisplayWithTitle(pixs2, 100, 100, "2 bpp, cmap", DFLAG);
        pixDisplayWithTitle(pixt4, 500, 100, "2 bpp, cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 2 bpp <==> 2 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 2 bpp <==> 2 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);

        /* Conversion: 4 bpp cmap --> 4 bpp --> 4 bpp cmap --> 4 bpp */
    pixt1 = pixRemoveColormap(pixs4, REMOVE_CMAP_TO_GRAYSCALE);
    pixt2 = pixConvertGrayToColormap(pixt1);
    pixt3 = pixRemoveColormap(pixt2, REMOVE_CMAP_TO_GRAYSCALE);
    pixt4 = pixThresholdTo4bpp(pixt3, 16, 1);
    pixEqual(pixt1, pixt4, &same);
    if (!same) {
        pixDisplayWithTitle(pixs4, 100, 100, "4 bpp, cmap", DFLAG);
        pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 4 bpp <==> 4 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 4 bpp <==> 4 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);


        /* Conversion: 8 bpp --> 8 bpp cmap --> 8 bpp */
    pixt1 = pixConvertTo8(pixs8, TRUE);
    pixt2 = pixConvertTo8(pixt1, FALSE);
    pixEqual(pixs8, pixt2, &same);
    if (!same) {
        pixDisplayWithTitle(pixt1, 100, 100, "8 bpp, cmap", DFLAG);
        pixDisplayWithTitle(pixt2, 500, 100, "8 bpp, no cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 8 bpp <==> 8 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 8 bpp <==> 8 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

        /* Conversion: 2 bpp cmap --> 32 bpp --> 2 bpp cmap */
    pixt1 = pixConvertTo8(pixc2, TRUE);
    pixt2 = pixConvertTo32(pixt1);
    pixt3 = pixConvertTo32(pixc2);
    pixEqual(pixt2, pixt3, &same);
    if (!same) {
        pixDisplayWithTitle(pixt2, 100, 100, "32 bpp", DFLAG);
        pixDisplayWithTitle(pixt3, 500, 100, "32 bpp", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 2 bpp ==> 32 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 2 bpp <==> 32 bpp\n");
    cmap = pixGetColormap(pixc2);
    pixt4 = pixOctcubeQuantFromCmap(pixt3, cmap, 2, 4, L_EUCLIDEAN_DISTANCE);
    pixEqual(pixc2, pixt4, &same);
    if (!same) {
        pixDisplayWithTitle(pixc2, 100, 100, "4 bpp, cmap", DFLAG);
        pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 2 bpp <==> 32 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 2 bpp <==> 32 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);

        /* Conversion: 4 bpp cmap --> 32 bpp --> 4 bpp cmap */
    pixt1 = pixConvertTo8(pixc4, TRUE);
    pixt2 = pixConvertTo32(pixt1);
    pixt3 = pixConvertTo32(pixc4);
    pixEqual(pixt2, pixt3, &same);
    if (!same) {
        pixDisplayWithTitle(pixt2, 100, 100, "32 bpp", DFLAG);
        pixDisplayWithTitle(pixt3, 500, 100, "32 bpp", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 4 bpp ==> 32 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 4 bpp <==> 32 bpp\n");
    cmap = pixGetColormap(pixc4);
    pixt4 = pixOctcubeQuantFromCmap(pixt3, cmap, 2, 4, L_EUCLIDEAN_DISTANCE);
    pixEqual(pixc4, pixt4, &same);
    if (!same) {
        pixDisplayWithTitle(pixc4, 100, 100, "4 bpp, cmap", DFLAG);
        pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 4 bpp <==> 32 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 4 bpp <==> 32 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);

        /* Conversion: 8 bpp --> 32 bpp --> 8 bpp */
    pixt1 = pixConvertTo32(pixs8);
    pixt2 = pixConvertTo8(pixt1, FALSE);
    pixEqual(pixs8, pixt2, &same);
    if (!same) {
        pixDisplayWithTitle(pixs8, 100, 100, "8 bpp", DFLAG);
        pixDisplayWithTitle(pixt2, 500, 100, "8 bpp", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 8 bpp <==> 32 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 8 bpp <==> 32 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

        /* Conversion: 8 bpp --> 16 bpp --> 8 bpp */
    pixt1 = pixConvert8To16(pixs8, 8);
    pixt2 = pixConvertTo8(pixt1, FALSE);
    pixEqual(pixs8, pixt2, &same);
    if (!same) {
        pixDisplayWithTitle(pixs8, 100, 100, "8 bpp", DFLAG);
        pixDisplayWithTitle(pixt2, 500, 100, "8 bpp", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 8 bpp <==> 16 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 8 bpp <==> 16 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

        /* Conversion: 16 bpp --> 8 bpp --> 16 bpp */
    pixt1 = pixConvert16To8(pixs16, 1);
    pixt2 = pixConvertTo16(pixt1);
    pixWrite("/tmp/junkpix.png", pixt2, IFF_PNG);
    pixEqual(pixs16, pixt2, &same);
    if (!same) {
        pixDisplayWithTitle(pixs16, 100, 100, "16 bpp", DFLAG);
        pixDisplayWithTitle(pixt2, 500, 100, "16 bpp", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 16 bpp <==> 8 bpp", L_COPY);
    } else
        fprintf(stderr, "OK: conversion 16 bpp <==> 8 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

        /* Conversion: 8 bpp cmap --> 32 bpp --> 8 bpp cmap */
        /* Required to go to level 6 of octcube to get identical result */
    pixt1 = pixConvertTo32(pixc8);
    cmap = pixGetColormap(pixc8);
    pixt2 = pixOctcubeQuantFromCmap(pixt1, cmap, 2, 6, L_EUCLIDEAN_DISTANCE);
    pixEqual(pixc8, pixt2, &same);
    if (!same) {
        pixDisplayWithTitle(pixc8, 100, 100, "8 bpp cmap", DFLAG);
        pixDisplayWithTitle(pixt2, 500, 100, "8 bpp cmap", DFLAG);
        error = TRUE;
        sarrayAddString(sa, (char *)"conversion 8 bpp cmap <==> 32 bpp cmap",
                        L_COPY);
    } else
        fprintf(stderr, "OK: conversion 8 bpp <==> 32 bpp\n");
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

        /* Summarize results */
    if (error == FALSE)
        fprintf(stderr, "No errors found\n");
    else {
        errorstr = sarrayToString(sa, 1);
        fprintf(stderr, "Errors in the following:\n %s", errorstr);
        lept_free(errorstr);
    }

    sarrayDestroy(&sa);
    pixDestroy(&pixs1);
    pixDestroy(&pixs2);
    pixDestroy(&pixs4);
    pixDestroy(&pixc2);
    pixDestroy(&pixc4);
    pixDestroy(&pixs8);
    pixDestroy(&pixc8);
    pixDestroy(&pixs16);
    pixDestroy(&pixs32);
    return 0;
}