/*! * 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; }
/* * fgetJp2kResolution() * * Input: stream (opened for read) * &xres, &yres (<return> resolution in ppi) * Return: 0 if OK; 1 on error * * Notes: * (1) If the capture resolution field is not set, this is not an error; * the returned resolution values are 0 (designating 'unknown'). * (2) Side-effect: this rewinds the stream. * (3) The capture resolution box is optional in the jp2 spec, and * it is usually not written. * (4) The big-endian data fields that follow the 4 bytes of 'resc' are: * ynum: 2 bytes * ydenom: 2 bytes * xnum: 2 bytes * xdenom: 2 bytes * yexp: 1 byte * xexp: 1 byte */ l_int32 fgetJp2kResolution(FILE *fp, l_int32 *pxres, l_int32 *pyres) { l_uint8 xexp, yexp; l_uint8 *data; l_uint16 xnum, ynum, xdenom, ydenom; /* these jp2k fields are 2-byte */ l_int32 loc, found; l_uint8 resc[4] = {0x72, 0x65, 0x73, 0x63}; /* 'resc' */ size_t nbytes; l_float64 xres, yres; PROCNAME("fgetJp2kResolution"); if (pxres) *pxres = 0; if (pyres) *pyres = 0; if (!pxres || !pyres) return ERROR_INT("&xres and &yres not both defined", procName, 1); if (!fp) return ERROR_INT("stream not opened", procName, 1); rewind(fp); data = l_binaryReadStream(fp, &nbytes); rewind(fp); /* Search for the start of the first capture resolution box: 'resc' */ arrayFindSequence(data, nbytes, resc, 4, &loc, &found); if (!found) { L_WARNING("image resolution not found\n", procName); FREE(data); return 0; } /* Extract the fields and calculate the resolution in pixels/meter. * See section 1.5.3.7.1 of JPEG 2000 ISO/IEC 15444-1 spec. */ ynum = data[loc + 5] << 8 | data[loc + 4]; ynum = convertOnLittleEnd16(ynum); ydenom = data[loc + 7] << 8 | data[loc + 6]; ydenom = convertOnLittleEnd16(ydenom); xnum = data[loc + 9] << 8 | data[loc + 8]; xnum = convertOnLittleEnd16(xnum); xdenom = data[loc + 11] << 8 | data[loc + 10]; xdenom = convertOnLittleEnd16(xdenom); yexp = data[loc + 12]; xexp = data[loc + 13]; yres = ((l_float64)ynum / (l_float64)ydenom) * pow(10.0, (l_float64)yexp); xres = ((l_float64)xnum / (l_float64)xdenom) * pow(10.0, (l_float64)xexp); /* Convert from pixels/meter to ppi */ yres *= (300.0 / 11811.0); xres *= (300.0 / 11811.0); *pyres = (l_int32)(yres + 0.5); *pxres = (l_int32)(xres + 0.5); FREE(data); return 0; }
/*! * readHeaderMemJp2k() * * Input: data * size (at least 80) * &w (<optional return>) * &h (<optional return>) * &bps (<optional return>, bits/sample) * &spp (<optional return>, samples/pixel) * Return: 0 if OK, 1 on error * * Notes: * (1) The ISO/IEC reference for jpeg2000 is * http://www.jpeg.org/public/15444-1annexi.pdf * and the file format syntax begins at page 127. * (2) The Image Header Box begins with 'ihdr' = 0x69686472 in * big-endian order. This typically, but not always, starts * byte 44, with the big-endian data fields beginning at byte 48: * h: 4 bytes * w: 4 bytes * spp: 2 bytes * bps: 1 byte (contains bps - 1) */ l_int32 readHeaderMemJp2k(const l_uint8 *data, size_t size, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp) { l_int32 format, val, w, h, bps, spp, loc, found, windex; l_uint8 ihdr[4] = {0x69, 0x68, 0x64, 0x72}; /* 'ihdr' */ PROCNAME("readHeaderMemJp2k"); if (pw) *pw = 0; if (ph) *ph = 0; if (pbps) *pbps = 0; if (pspp) *pspp = 0; if (!data) return ERROR_INT("data not defined", procName, 1); if (size < 80) return ERROR_INT("size < 80", procName, 1); findFileFormatBuffer(data, &format); if (format != IFF_JP2) return ERROR_INT("not jp2 file", procName, 1); /* Search for beginning of the Image Header Box: 'ihdr' */ arrayFindSequence(data, size, ihdr, 4, &loc, &found); if (!found) return ERROR_INT("image parameters not found", procName, 1); if (loc != 44) L_INFO("Beginning of ihdr is at byte %d\n", procName, loc); windex = loc / 4 + 1; val = *((l_uint32 *)data + windex); h = convertOnLittleEnd32(val); val = *((l_uint32 *)data + windex + 1); w = convertOnLittleEnd32(val); val = *((l_uint16 *)data + 2 * (windex + 2)); spp = convertOnLittleEnd16(val); bps = *(data + 4 * (windex + 2) + 2) + 1; if (w > MAX_JP2K_WIDTH || h > MAX_JP2K_HEIGHT) return ERROR_INT("unrealistically large sizes", procName, 1); if (pw) *pw = w; if (ph) *ph = h; if (pbps) *pbps = bps; if (pspp) *pspp = spp; return 0; }
/*! * sarrayParseRange() * * Input: sa (input sarray) * start (index to start range search) * &actualstart (<return> index of actual start; may be > 'start') * &end (<return> index of end) * &newstart (<return> index of start of next range) * substr (substring for matching at beginning of string) * loc (byte offset within the string for the pattern; use * -1 if the location does not matter); * Return: 0 if valid range found; 1 otherwise * * Notes: * (1) This finds the range of the next set of strings in SA, * beginning the search at 'start', that does NOT have * the substring 'substr' either at the indicated location * in the string or anywhere in the string. The input * variable 'loc' is the specified offset within the string; * use -1 to indicate 'anywhere in the string'. * (2) Always check the return value to verify that a valid range * was found. * (3) If a valid range is not found, the values of actstart, * end and newstart are all set to the size of sa. * (4) If this is the last valid range, newstart returns the value n. * In use, this should be tested before calling the function. * (5) Usage example. To find all the valid ranges in a file * where the invalid lines begin with two dashes, copy each * line in the file to a string in an sarray, and do: * start = 0; * while (!sarrayParseRange(sa, start, &actstart, &end, &start, * "--", 0)) * fprintf(stderr, "start = %d, end = %d\n", actstart, end); */ l_int32 sarrayParseRange(SARRAY *sa, l_int32 start, l_int32 *pactualstart, l_int32 *pend, l_int32 *pnewstart, const char *substr, l_int32 loc) { char *str; l_int32 n, i, offset, found; PROCNAME("sarrayParseRange"); if (!sa) return ERROR_INT("sa not defined", procName, 1); if (!pactualstart || !pend || !pnewstart) return ERROR_INT("not all range addresses defined", procName, 1); n = sarrayGetCount(sa); *pactualstart = *pend = *pnewstart = n; if (!substr) return ERROR_INT("substr not defined", procName, 1); /* Look for the first string without the marker */ if (start < 0 || start >= n) return 1; for (i = start; i < n; i++) { str = sarrayGetString(sa, i, L_NOCOPY); arrayFindSequence((l_uint8 *)str, strlen(str), (l_uint8 *)substr, strlen(substr), &offset, &found); if (loc < 0) { if (!found) break; } else { if (!found || offset != loc) break; } } start = i; if (i == n) /* couldn't get started */ return 1; /* Look for the last string without the marker */ *pactualstart = start; for (i = start + 1; i < n; i++) { str = sarrayGetString(sa, i, L_NOCOPY); arrayFindSequence((l_uint8 *)str, strlen(str), (l_uint8 *)substr, strlen(substr), &offset, &found); if (loc < 0) { if (found) break; } else { if (found && offset == loc) break; } } *pend = i - 1; start = i; if (i == n) /* no further range */ return 0; /* Look for the first string after *pend without the marker. * This will start the next run of strings, if it exists. */ for (i = start; i < n; i++) { str = sarrayGetString(sa, i, L_NOCOPY); arrayFindSequence((l_uint8 *)str, strlen(str), (l_uint8 *)substr, strlen(substr), &offset, &found); if (loc < 0) { if (!found) break; } else { if (!found || offset != loc) break; } } if (i < n) *pnewstart = i; return 0; }