first working version from Android Studio

This commit is contained in:
Vincent KHERBACHE
2015-01-29 23:47:56 +01:00
commit e55edb3754
5195 changed files with 1523796 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Image adaptive mapping methods.
*
* @author alanv@google.com (Alan Viverette)
*/
public class AdaptiveMap {
static {
System.loadLibrary("lept");
}
// Background normalization constants
/** Image reduction value; possible values are 1, 2, 4, 8 */
private final static int NORM_REDUCTION = 16;
/** Desired tile size; actual size may vary */
private final static int NORM_SIZE = 3;
/** Background brightness value; values over 200 may result in clipping */
private final static int NORM_BG_VALUE = 200;
/**
* Normalizes an image's background using default parameters.
*
* @param pixs A source pix image.
* @return the source pix image with a normalized background
*/
public static Pix backgroundNormMorph(Pix pixs) {
return backgroundNormMorph(pixs, NORM_REDUCTION, NORM_SIZE, NORM_BG_VALUE);
}
/**
* Normalizes an image's background to a specified value.
* <p>
* Notes:
* <ol>
* <li>This is a top-level interface for normalizing the image intensity by
* mapping the image so that the background is near the input value 'bgval'.
* <li>The input image is either grayscale or rgb.
* <li>For each component in the input image, the background value is
* estimated using a grayscale closing; hence the 'Morph' in the function
* name.
* <li>An optional binary mask can be specified, with the foreground pixels
* typically over image regions. The resulting background map values will be
* determined by surrounding pixels that are not under the mask foreground.
* The origin (0,0) of this mask is assumed to be aligned with the origin of
* the input image. This binary mask must not fully cover pixs, because then
* there will be no pixels in the input image available to compute the
* background.
* <li>The map is computed at reduced size (given by 'reduction') from the
* input pixs and optional pixim. At this scale, pixs is closed to remove
* the background, using a square Sel of odd dimension. The product of
* reduction * size should be large enough to remove most of the text
* foreground.
* <li>No convolutional smoothing needs to be done on the map before
* inverting it.
* <li>A 'bgval' target background value for the normalized image. This
* should be at least 128. If set too close to 255, some clipping will occur
* in the result.
* </ol>
*
* @param pixs A source pix image.
* @param normReduction Reduction at which morphological closings are done.
* @param normSize Size of square Sel for the closing.
* @param normBgValue Target background value.
* @return the source pix image with a normalized background
*/
public static Pix backgroundNormMorph(
Pix pixs, int normReduction, int normSize, int normBgValue) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
long nativePix = nativeBackgroundNormMorph(
pixs.mNativePix, normReduction, normSize, normBgValue);
if (nativePix == 0)
throw new RuntimeException("Failed to normalize image background");
return new Pix(nativePix);
}
/**
* Adaptively attempts to expand the contrast to the full dynamic range in
* each tile.
* <p>
* Notes:
* <ol>
* <li>If the contrast in a tile is smaller than minDiff, it uses the min
* and max pixel values from neighboring tiles. It also can use
* convolution to smooth the min and max values from neighboring tiles.
* After all that processing, it is possible that the actual pixel values
* in the tile are outside the computed [min ... max] range for local
* contrast normalization. Such pixels are taken to be at either 0 (if
* below the min) or 255 (if above the max).
* <li>sizeX and sizeY give the tile size; they are typically at least 20.
* <li>minDiff is used to eliminate results for tiles where it is likely
* that either fg or bg is missing. A value around 50 or more is
* reasonable.
* <li>The full width and height of the convolution kernel are (2 * smoothx
* + 1) and (2 * smoothy + 1). Some smoothing is typically useful, and we
* limit the smoothing half-widths to the range from 0 to 8. Use 0 for no
* smoothing.
* <li>A linear TRC (gamma = 1.0) is applied to increase the contrast in
* each tile. The result can subsequently be globally corrected, by
* applying pixGammaTRC() with arbitrary values of gamma and the 0 and 255
* points of the mapping.
* </ol>
*
* @param pixs A source pix image
* @param sizeX Tile width
* @param sizeY Tile height
* @param minDiff Minimum difference to accept as valid
* @param smoothX Half-width of convolution kernel applied to min and max
* arrays
* @param smoothY Half-height of convolution kernel applied to min and max
* arrays
*/
public static Pix pixContrastNorm(
Pix pixs, int sizeX, int sizeY, int minDiff, int smoothX, int smoothY) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
long nativePix = nativePixContrastNorm(
pixs.mNativePix, sizeX, sizeY, minDiff, smoothX, smoothY);
if (nativePix == 0)
throw new RuntimeException("Failed to normalize image contrast");
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativeBackgroundNormMorph(
long nativePix, int reduction, int size, int bgval);
private static native long nativePixContrastNorm(
long nativePix, int sizeX, int sizeY, int minDiff, int smoothX, int smoothY);
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Image binarization methods.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Binarize {
static {
System.loadLibrary("lept");
}
// Otsu thresholding constants
/** Desired tile X dimension; actual size may vary */
public final static int OTSU_SIZE_X = 32;
/** Desired tile Y dimension; actual size may vary */
public final static int OTSU_SIZE_Y = 32;
/** Desired X smoothing value */
public final static int OTSU_SMOOTH_X = 2;
/** Desired Y smoothing value */
public final static int OTSU_SMOOTH_Y = 2;
/** Fraction of the max Otsu score, typically 0.1 */
public final static float OTSU_SCORE_FRACTION = 0.1f;
/**
* Performs locally-adaptive Otsu threshold binarization with default
* parameters.
*
* @param pixs An 8 bpp PIX source image.
* @return A 1 bpp thresholded PIX image.
*/
public static Pix otsuAdaptiveThreshold(Pix pixs) {
return otsuAdaptiveThreshold(
pixs, OTSU_SIZE_X, OTSU_SIZE_Y, OTSU_SMOOTH_X, OTSU_SMOOTH_Y, OTSU_SCORE_FRACTION);
}
/**
* Performs locally-adaptive Otsu threshold binarization.
* <p>
* Notes:
* <ol>
* <li>The Otsu method finds a single global threshold for an image. This
* function allows a locally adapted threshold to be found for each tile
* into which the image is broken up.
* <li>The array of threshold values, one for each tile, constitutes a
* highly downscaled image. This array is optionally smoothed using a
* convolution. The full width and height of the convolution kernel are (2 *
* smoothX + 1) and (2 * smoothY + 1).
* <li>The minimum tile dimension allowed is 16. If such small tiles are
* used, it is recommended to use smoothing, because without smoothing, each
* small tile determines the splitting threshold independently. A tile that
* is entirely in the image bg will then hallucinate fg, resulting in a very
* noisy binarization. The smoothing should be large enough that no tile is
* only influenced by one type (fg or bg) of pixels, because it will force a
* split of its pixels.
* <li>To get a single global threshold for the entire image, use input
* values of sizeX and sizeY that are larger than the image. For this
* situation, the smoothing parameters are ignored.
* <li>The threshold values partition the image pixels into two classes: one
* whose values are less than the threshold and another whose values are
* greater than or equal to the threshold. This is the same use of
* 'threshold' as in pixThresholdToBinary().
* <li>The scorefract is the fraction of the maximum Otsu score, which is
* used to determine the range over which the histogram minimum is searched.
* See numaSplitDistribution() for details on the underlying method of
* choosing a threshold.
* <li>This uses enables a modified version of the Otsu criterion for
* splitting the distribution of pixels in each tile into a fg and bg part.
* The modification consists of searching for a minimum in the histogram
* over a range of pixel values where the Otsu score is within a defined
* fraction, scoreFraction, of the max score. To get the original Otsu
* algorithm, set scoreFraction == 0.
* </ol>
*
* @param pixs An 8 bpp PIX source image.
* @param sizeX Desired tile X dimension; actual size may vary.
* @param sizeY Desired tile Y dimension; actual size may vary.
* @param smoothX Half-width of convolution kernel applied to threshold
* array: use 0 for no smoothing.
* @param smoothY Half-height of convolution kernel applied to threshold
* array: use 0 for no smoothing.
* @param scoreFraction Fraction of the max Otsu score; typ. 0.1 (use 0.0
* for standard Otsu).
* @return A 1 bpp thresholded PIX image.
*/
public static Pix otsuAdaptiveThreshold(
Pix pixs, int sizeX, int sizeY, int smoothX, int smoothY, float scoreFraction) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (pixs.getDepth() != 8)
throw new IllegalArgumentException("Source pix depth must be 8bpp");
long nativePix = nativeOtsuAdaptiveThreshold(
pixs.mNativePix, sizeX, sizeY, smoothX, smoothY, scoreFraction);
if (nativePix == 0)
throw new RuntimeException("Failed to perform Otsu adaptive threshold on image");
return new Pix(nativePix);
}
/**
* Performs Sauvola binarization.
* <p>
* Notes:
* <ol>
* <li> The window width and height are 2 * whsize + 1. The minimum
* value for whsize is 2; typically it is >= 7.
* <li> For nx == ny == 1, this defaults to pixSauvolaBinarize().
* <li> Why a tiled version?
* (a) Because the mean value accumulator is a uint32, overflow
* can occur for an image with more than 16M pixels.
* (b) The mean value accumulator array for 16M pixels is 64 MB.
* The mean square accumulator array for 16M pixels is 128 MB.
* Using tiles reduces the size of these arrays.
* (c) Each tile can be processed independently, in parallel,
* on a multicore processor.
* <li> The Sauvola threshold is determined from the formula:
* t = m * (1 - k * (1 - s / 128))
* where:
* t = local threshold
* m = local mean
* k = @factor (>= 0) [ typ. 0.35 ]
* s = local standard deviation, which is maximized at
* 127.5 when half the samples are 0 and half are 255.
* <li> The basic idea of Niblack and Sauvola binarization is that
* the local threshold should be less than the median value, and the larger
* the variance, the closer to the median it should be chosen. Typical
* values for k are between 0.2 and 0.5.
* </ol>
*
* @param pixs An 8 bpp PIX source image.
* @param whsize Window half-width for measuring local statistics
* @param factor Factor for reducing threshold due to variance; >= 0
* @param nx Subdivision into tiles; >= 1
* @param ny Subdivision into tiles; >= 1
* @return A 1 bpp thresholded PIX image.
*/
public static Pix sauvolaBinarizeTiled(Pix pixs, int whsize, float factor, int nx, int ny) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (pixs.getDepth() != 8)
throw new IllegalArgumentException("Source pix depth must be 8bpp");
long nativePix = nativeSauvolaBinarizeTiled(pixs.mNativePix, whsize, factor, nx, ny);
if (nativePix == 0)
throw new RuntimeException("Failed to perform Otsu adaptive threshold on image");
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativeOtsuAdaptiveThreshold(
long nativePix, int sizeX, int sizeY, int smoothX, int smoothY, float scoreFract);
private static native long nativeSauvolaBinarizeTiled(
long nativePix, int whsize, float factor, int nx, int ny);
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Wrapper for Leptonica's native BOX.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Box {
static {
System.loadLibrary("lept");
}
/** The index of the X coordinate within the geometry array. */
public static final int INDEX_X = 0;
/** The index of the Y coordinate within the geometry array. */
public static final int INDEX_Y = 1;
/** The index of the width within the geometry array. */
public static final int INDEX_W = 2;
/** The index of the height within the geometry array. */
public static final int INDEX_H = 3;
/**
* A pointer to the native Box object. This is used internally by native
* code.
*/
final long mNativeBox;
private boolean mRecycled = false;
/**
* Creates a new Box wrapper for the specified native BOX.
*
* @param nativeBox A pointer to the native BOX.
*/
Box(long nativeBox) {
mNativeBox = nativeBox;
mRecycled = false;
}
/**
* Creates a box with the specified geometry. All dimensions should be
* non-negative and specified in pixels.
*
* @param x X-coordinate of the top-left corner of the box.
* @param y Y-coordinate of the top-left corner of the box.
* @param w Width of the box.
* @param h Height of the box.
*/
public Box(int x, int y, int w, int h) {
if (x < 0 || y < 0 || w < 0 || h < 0) {
throw new IllegalArgumentException("All box dimensions must be non-negative");
}
long nativeBox = nativeCreate(x, y, w, h);
if (nativeBox == 0) {
throw new OutOfMemoryError();
}
mNativeBox = nativeBox;
mRecycled = false;
}
/**
* Returns the box's x-coordinate in pixels.
*
* @return The box's x-coordinate in pixels.
*/
public int getX() {
return nativeGetX(mNativeBox);
}
/**
* Returns the box's y-coordinate in pixels.
*
* @return The box's y-coordinate in pixels.
*/
public int getY() {
return nativeGetY(mNativeBox);
}
/**
* Returns the box's width in pixels.
*
* @return The box's width in pixels.
*/
public int getWidth() {
return nativeGetWidth(mNativeBox);
}
/**
* Returns the box's height in pixels.
*
* @return The box's height in pixels.
*/
public int getHeight() {
return nativeGetHeight(mNativeBox);
}
/**
* Returns an array containing the coordinates of this box. See INDEX_*
* constants for indices.
*
* @return an array of box oordinates
*/
public int[] getGeometry() {
int[] geometry = new int[4];
if (getGeometry(geometry)) {
return geometry;
}
return null;
}
/**
* Fills an array containing the coordinates of this box. See INDEX_*
* constants for indices.
*
* @param geometry A 4+ element integer array to fill with coordinates.
* @return <code>true</code> on success
*/
public boolean getGeometry(int[] geometry) {
if (geometry.length < 4) {
throw new IllegalArgumentException("Geometry array must be at least 4 elements long");
}
return nativeGetGeometry(mNativeBox, geometry);
}
/**
* Releases resources and frees any memory associated with this Box.
*/
public void recycle() {
if (!mRecycled) {
nativeDestroy(mNativeBox);
mRecycled = true;
}
}
@Override
protected void finalize() throws Throwable {
recycle();
super.finalize();
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativeCreate(int x, int y, int w, int h);
private static native int nativeGetX(long nativeBox);
private static native int nativeGetY(long nativeBox);
private static native int nativeGetWidth(long nativeBox);
private static native int nativeGetHeight(long nativeBox);
private static native void nativeDestroy(long nativeBox);
private static native boolean nativeGetGeometry(long nativeBox, int[] geometry);
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2014 Robert Theis
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Extract rectangular regions.
*/
public class Clip {
static {
System.loadLibrary("lept");
}
/**
* Extract a region from a Pix.
* <p>
* Notes:
* <p>
* This should be simple, but there are choices to be made. The box is
* defined relative to the pix coordinates. However, if the box is not
* contained within the pix, we have two choices:
* <p>
* <p> (1) clip the box to the pix
* <p> (2) make a new pix equal to the full box dimensions,
* but let rasterop do the clipping and positioning
* of the src with respect to the dest
* <p>
* Choice (2) immediately brings up the problem of what pixel values
* to use that were not taken from the src. For example, on a grayscale
* image, do you want the pixels not taken from the src to be black
* or white or something else? To implement choice 2, one needs to
* specify the color of these extra pixels.
* <p>
* So we adopt (1), and clip the box first, if necessary,
* before making the dest pix and doing the rasterop. But there
* is another issue to consider. If you want to paste the
* clipped pix back into pixs, it must be properly aligned, and
* it is necessary to use the clipped box for alignment.
*
* @param source Source pix
* @param box Requested clipping region
* @return clipped pix, or null if rectangle doesn't intersect source pix
*/
public static Pix clipRectangle(Pix source, Box box) {
int result = nativeClipRectangle(source.getNativePix(), box.mNativeBox);
if (result != 0) {
return new Pix(result);
}
return null;
}
// ***************
// * NATIVE CODE *
// ***************
private static native int nativeClipRectangle(long nativePix, long nativeBox);
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Leptonica constants.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Constants {
/*-------------------------------------------------------------------------*
* Access and storage flags *
*-------------------------------------------------------------------------*/
/*
* For Pix, Box, Pta and Numa, there are 3 standard methods for handling the
* retrieval or insertion of a struct: (1) direct insertion (Don't do this
* if there is another handle somewhere to this same struct!) (2) copy
* (Always safe, sets up a refcount of 1 on the new object. Can be
* undesirable if very large, such as an image or an array of images.) (3)
* clone (Makes another handle to the same struct, and bumps the refcount up
* by 1. Safe to do unless you're changing data through one of the handles
* but don't want those changes to be seen by the other handle.) For Pixa
* and Boxa, which are structs that hold an array of clonable structs, there
* is an additional method: (4) copy-clone (Makes a new higher-level struct
* with a refcount of 1, but clones all the structs in the array.) Unlike
* the other structs, when retrieving a string from an Sarray, you are
* allowed to get a handle without a copy or clone (i.e., that you don't
* own!). You must not free or insert such a string! Specifically, for an
* Sarray, the copyflag for retrieval is either: TRUE (or 1 or L_COPY) or
* FALSE (or 0 or L_NOCOPY) For insertion, the copyflag is either: TRUE (or
* 1 or L_COPY) or FALSE (or 0 or L_INSERT) Note that L_COPY is always 1,
* and L_INSERT and L_NOCOPY are always 0.
*/
/* Stuff it in; no copy, clone or copy-clone */
public static final int L_INSERT = 0;
/* Make/use a copy of the object */
public static final int L_COPY = 1;
/* Make/use clone (ref count) of the object */
public static final int L_CLONE = 2;
/*
* Make a new object and fill with with clones of each object in the
* array(s)
*/
public static final int L_COPY_CLONE = 3;
/*--------------------------------------------------------------------------*
* Sort flags *
*--------------------------------------------------------------------------*/
/* Sort in increasing order */
public static final int L_SORT_INCREASING = 1;
/* Sort in decreasing order */
public static final int L_SORT_DECREASING = 2;
/* Sort box or c.c. by horiz location */
public static final int L_SORT_BY_X = 3;
/* Sort box or c.c. by vert location */
public static final int L_SORT_BY_Y = 4;
/* Sort box or c.c. by width */
public static final int L_SORT_BY_WIDTH = 5;
/* Sort box or c.c. by height */
public static final int L_SORT_BY_HEIGHT = 6;
/* Sort box or c.c. by min dimension */
public static final int L_SORT_BY_MIN_DIMENSION = 7;
/* Sort box or c.c. by max dimension */
public static final int L_SORT_BY_MAX_DIMENSION = 8;
/* Sort box or c.c. by perimeter */
public static final int L_SORT_BY_PERIMETER = 9;
/* Sort box or c.c. by area */
public static final int L_SORT_BY_AREA = 10;
/* Sort box or c.c. by width/height ratio */
public static final int L_SORT_BY_ASPECT_RATIO = 11;
/* ------------------ Image file format types -------------- */
/*
* The IFF_DEFAULT flag is used to write the file out in the same (input)
* file format that the pix was read from. If the pix was not read from
* file, the input format field will be IFF_UNKNOWN and the output file
* format will be chosen to be compressed and lossless; namely, IFF_TIFF_G4
* for d = 1 and IFF_PNG for everything else. IFF_JP2 is for jpeg2000, which
* is not supported in leptonica.
*/
public static final int IFF_UNKNOWN = 0;
public static final int IFF_BMP = 1;
public static final int IFF_JFIF_JPEG = 2;
public static final int IFF_PNG = 3;
public static final int IFF_TIFF = 4;
public static final int IFF_TIFF_PACKBITS = 5;
public static final int IFF_TIFF_RLE = 6;
public static final int IFF_TIFF_G3 = 7;
public static final int IFF_TIFF_G4 = 8;
public static final int IFF_TIFF_LZW = 9;
public static final int IFF_TIFF_ZIP = 10;
public static final int IFF_PNM = 11;
public static final int IFF_PS = 12;
public static final int IFF_GIF = 13;
public static final int IFF_JP2 = 14;
public static final int IFF_DEFAULT = 15;
public static final int IFF_SPIX = 16;
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Image bit-depth conversion methods.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Convert {
static {
System.loadLibrary("lept");
}
/**
* Converts an image of any bit depth to 8-bit grayscale.
*
* @param pixs Source pix of any bit-depth.
* @return a new Pix image or <code>null</code> on error
*/
public static Pix convertTo8(Pix pixs) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
long nativePix = nativeConvertTo8(pixs.mNativePix);
if (nativePix == 0)
throw new RuntimeException("Failed to natively convert pix");
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativeConvertTo8(long nativePix);
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2014 Robert Theis
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Edge detection.
*/
public class Edge {
static {
System.loadLibrary("lept");
}
// Edge orientation flags
/** Filters for horizontal edges */
public static final int L_HORIZONTAL_EDGES = 0;
/** Filters for vertical edges */
public static final int L_VERTICAL_EDGES = 1;
/** Filters for all edges */
public static final int L_ALL_EDGES = 2;
/**
* Performs a Sobel edge detecting filter.
* <p>
* To use both the vertical and horizontal filters, set the orientation
* flag to L_ALL_EDGES; this sums the abs. value of their outputs,
* clipped to 255.
* <p>
* Notes:
* <ol>
* <li> Invert pixd to see larger gradients as darker (grayscale).
* <li> To generate a binary image of the edges, threshold the result
* using pixThresholdToBinary(). If the high edge values are to be fg (1),
* invert after running pixThresholdToBinary().
* <li> Label the pixels as follows:
* <p>
* <p> 1 4 7
* <p> 2 5 8
* <p> 3 6 9
* <p>
* Read the data incrementally across the image and unroll the loop.
* <li> This runs at about 45 Mpix/sec on a 3 GHz processor.
* </ol>
*
* @param pixs Source pix (8 bpp; no colormap)
* @param orientFlag Edge orientation flag (L_HORIZONTAL_EDGES,
* L_VERTICAL_EDGES, L_ALL_EDGES)
* @return a new Pix image (8bpp, edges are brighter), or null on error
*/
public static Pix pixSobelEdgeFilter(Pix pixs, int orientFlag) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (pixs.getDepth() != 8)
throw new IllegalArgumentException("Source pix depth must be 8bpp");
if (orientFlag < 0 || orientFlag > 2)
throw new IllegalArgumentException("Invalid orientation flag");
long nativePix = nativePixSobelEdgeFilter(pixs.mNativePix, orientFlag);
if (nativePix == 0)
throw new RuntimeException("Failed to perform Sobel edge filter on image");
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativePixSobelEdgeFilter(long nativePix, int orientFlag);
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Image sharpening methods.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Enhance {
static {
System.loadLibrary("lept");
}
/**
* Performs unsharp masking (edge enhancement).
* <p>
* Notes:
* <ul>
* <li>We use symmetric smoothing filters of odd dimension, typically use
* sizes of 3, 5, 7, etc. The <code>halfwidth</code> parameter for these is
* (size - 1)/2; i.e., 1, 2, 3, etc.</li>
* <li>The <code>fract</code> parameter is typically taken in the range: 0.2
* &lt; <code>fract</code> &lt; 0.7</li>
* </ul>
*
* @param halfwidth The half-width of the smoothing filter.
* @param fraction The fraction of edge to be added back into the source
* image.
* @return an edge-enhanced Pix image or copy if no enhancement requested
*/
public static Pix unsharpMasking(Pix pixs, int halfwidth, float fraction) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
long nativePix = nativeUnsharpMasking(pixs.mNativePix, halfwidth, fraction);
if (nativePix == 0) {
throw new OutOfMemoryError();
}
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativeUnsharpMasking(long nativePix, int halfwidth, float fract);
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2014 Robert Theis
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
public class GrayQuant {
static {
System.loadLibrary("lept");
}
/**
* Perform simple (pixelwise) binarization with fixed threshold
* <p>
* Notes:
* <ol>
* <li> If the source pixel is less than the threshold value, the dest will
* be 1; otherwise, it will be 0
* </ol>
*
* @param pixs Source pix (4 or 8 bpp)
* @param thresh Threshold value
* @return a new Pix image, 1 bpp
*/
public static Pix pixThresholdToBinary(Pix pixs, int thresh) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
int depth = pixs.getDepth();
if (depth != 4 && depth != 8)
throw new IllegalArgumentException("Source pix depth must be 4 or 8 bpp");
if (depth == 4 && thresh > 16)
throw new IllegalArgumentException("4 bpp thresh not in {0-16}");
if (depth == 8 && thresh > 256)
throw new IllegalArgumentException("8 bpp thresh not in {0-256}");
long nativePix = nativePixThresholdToBinary(pixs.mNativePix, thresh);
if (nativePix == 0)
throw new RuntimeException("Failed to perform binarization");
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativePixThresholdToBinary(long nativePix, int thresh);
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* JPEG input and output methods.
*
* @author alanv@google.com (Alan Viverette)
*/
public class JpegIO {
static {
System.loadLibrary("lept");
}
/** Default quality is 85%, which is reasonably good. */
public static final int DEFAULT_QUALITY = 85;
/** Progressive encoding is disabled by default to increase compatibility. */
public static final boolean DEFAULT_PROGRESSIVE = false;
/**
* Returns a compressed JPEG byte representation of this Pix using default
* parameters.
*
* @param pixs
* @return a compressed JPEG byte array representation of the Pix
*/
public static byte[] compressToJpeg(Pix pixs) {
return compressToJpeg(pixs, DEFAULT_QUALITY, DEFAULT_PROGRESSIVE);
}
/**
* Returns a compressed JPEG byte representation of this Pix.
*
* @param pixs A source pix image.
* @param quality The quality of the compressed image. Valid range is 0-100.
* @param progressive Whether to use progressive compression.
* @return a compressed JPEG byte array representation of the Pix
*/
public static byte[] compressToJpeg(Pix pixs, int quality, boolean progressive) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (quality < 0 || quality > 100)
throw new IllegalArgumentException("Quality must be between 0 and 100 (inclusive)");
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
final Bitmap bmp = WriteFile.writeBitmap(pixs);
bmp.compress(CompressFormat.JPEG, quality, byteStream);
bmp.recycle();
final byte[] encodedData = byteStream.toByteArray();
try {
byteStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return encodedData;
}
// ***************
// * NATIVE CODE *
// ***************
private static native byte[] nativeCompressToJpeg(
long nativePix, int quality, boolean progressive);
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2014 Robert Theis
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Composite image processing operations.
*/
public class MorphApp {
static {
System.loadLibrary("lept");
}
// Morphological tophat flags
public static final int L_TOPHAT_WHITE = 0;
public static final int L_TOPHAT_BLACK = 1;
/**
* Performs a tophat transform.
* <p>
* Notes:
* <ol>
* <li> Sel is a brick with all elements being hits
* <li> If hsize = vsize = 1, returns an image with all 0 data.
* <li> The L_TOPHAT_WHITE flag emphasizes small bright regions, whereas
* the L_TOPHAT_BLACK flag emphasizes small dark regions. The L_TOPHAT_WHITE
* tophat can be accomplished by doing a L_TOPHAT_BLACK tophat on the
* inverse, or v.v.
* </ol>
*
* @param pixs Source pix (8bpp)
* @param hsize (of Sel; must be odd; origin implicitly in center)
* @param vsize (ditto)
* @param type L_TOPHAT_WHITE: image - opening or L_TOPHAT_BLACK: closing - image
* @return a new Pix image
*/
public static Pix pixTophat(Pix pixs, int hsize, int vsize, int type) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (pixs.getDepth() != 8)
throw new IllegalArgumentException("Source pix depth must be 8bpp");
if (hsize < 1 || vsize < 1)
throw new IllegalArgumentException("hsize or vsize < 1");
if (type < 0 || type > 1)
throw new IllegalArgumentException("Type must be L_TOPHAT_BLACK or L_TOPHAT_WHITE");
long nativePix = nativePixTophat(pixs.mNativePix, hsize, vsize, type);
if (nativePix == 0)
throw new RuntimeException("Failed to perform Tophat on image");
return new Pix(nativePix);
}
/**
* Performs a tophat-like operation.
* <p>
* Notes:
* <ol>
* <li> Don't be fooled. This is NOT a tophat. It is a tophat-like
* operation, where the result is similar to what you'd get if you used an
* erosion instead of an opening, or a dilation instead of a closing.
*
* <li> Instead of opening or closing at full resolution, it does a fast
* downscale/minmax operation, then a quick small smoothing at low res, a
* replicative expansion of the "background" to full res, and finally a
* removal of the background level from the input image. The smoothing
* step may not be important.
*
* <li> It does not remove noise as well as a tophat, but it is 5 to 10
* times faster. If you need the preciseness of the tophat, don't use this.
* <li> The L_TOPHAT_WHITE flag emphasizes small bright regions, whereas
* the L_TOPHAT_BLACK flag emphasizes small dark regions.
* </ol>
*
* @param pixs Source pix (8bpp)
* @param xsize width of max/min op, smoothing; any integer >= 1
* @param ysize height of max/min op, smoothing; any integer >= 1
* @param type L_TOPHAT_WHITE: image - min, or L_TOPHAT_BLACK: max - image
* @return a new Pix image
*/
public static Pix pixFastTophat(Pix pixs, int xsize, int ysize, int type) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (pixs.getDepth() != 8)
throw new IllegalArgumentException("Source pix depth must be 8bpp");
if (xsize < 1 || ysize < 1)
throw new IllegalArgumentException("size < 1");
if (type < 0 || type > 1)
throw new IllegalArgumentException("Type must be L_TOPHAT_BLACK or L_TOPHAT_WHITE");
long nativePix = nativePixFastTophat(pixs.mNativePix, xsize, ysize, type);
if (nativePix == 0)
throw new RuntimeException("Failed to perform pixFastTophat on image");
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativePixTophat(long nativePix, int hsize, int vsize, int type);
private static native long nativePixFastTophat(long nativePix, int xsize, int ysize, int type);
}

View File

@@ -0,0 +1,299 @@
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
import android.graphics.Rect;
/**
* Java representation of a native Leptonica PIX object.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Pix {
static {
System.loadLibrary("lept");
}
/** Index of the image width within the dimensions array. */
public static final int INDEX_W = 0;
/** Index of the image height within the dimensions array. */
public static final int INDEX_H = 1;
/** Index of the image bit-depth within the dimensions array. */
public static final int INDEX_D = 2;
/** Package-accessible pointer to native pix */
final long mNativePix;
private boolean mRecycled;
/**
* Creates a new Pix wrapper for the specified native PIX object. Never call
* this twice on the same native pointer, because finalize() will attempt to
* free native memory twice.
*
* @param nativePix A pointer to the native PIX object.
*/
public Pix(long nativePix) {
mNativePix = nativePix;
mRecycled = false;
}
public Pix(int width, int height, int depth) {
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Pix width and height must be > 0");
} else if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && depth != 16
&& depth != 24 && depth != 32) {
throw new IllegalArgumentException("Depth must be one of 1, 2, 4, 8, 16, or 32");
}
mNativePix = nativeCreatePix(width, height, depth);
mRecycled = false;
}
/**
* Returns a pointer to the native Pix object. This is used by native code
* and is only valid within the same process in which the Pix was created.
*
* @return a native pointer to the Pix object
*/
public long getNativePix() {
return mNativePix;
}
/**
* Return the raw bytes of the native PIX object. You can reconstruct the
* Pix from this data using createFromPix().
*
* @return a copy of this PIX object's raw data
*/
public byte[] getData() {
int size = nativeGetDataSize(mNativePix);
byte[] buffer = new byte[size];
if (!nativeGetData(mNativePix, buffer)) {
throw new RuntimeException("native getData failed");
}
return buffer;
}
/**
* Returns an array of this image's dimensions. See Pix.INDEX_* for indices.
*
* @return an array of this image's dimensions or <code>null</code> on
* failure
*/
public int[] getDimensions() {
int[] dimensions = new int[4];
if (getDimensions(dimensions)) {
return dimensions;
}
return null;
}
/**
* Fills an array with this image's dimensions. The array must be at least 3
* elements long.
*
* @param dimensions An integer array with at least three elements.
* @return <code>true</code> on success
*/
public boolean getDimensions(int[] dimensions) {
return nativeGetDimensions(mNativePix, dimensions);
}
/**
* Returns a clone of this Pix. This does NOT create a separate copy, just a
* new pointer that can be recycled without affecting other clones.
*
* @return a clone (shallow copy) of the Pix
*/
@Override
public Pix clone() {
long nativePix = nativeClone(mNativePix);
if (nativePix == 0) {
throw new OutOfMemoryError();
}
return new Pix(nativePix);
}
/**
* Returns a deep copy of this Pix that can be modified without affecting
* the original Pix.
*
* @return a copy of the Pix
*/
public Pix copy() {
long nativePix = nativeCopy(mNativePix);
if (nativePix == 0) {
throw new OutOfMemoryError();
}
return new Pix(nativePix);
}
/**
* Inverts this Pix in-place.
*
* @return <code>true</code> on success
*/
public boolean invert() {
return nativeInvert(mNativePix);
}
/**
* Releases resources and frees any memory associated with this Pix. You may
* not modify or access the pix after calling this method.
*/
public void recycle() {
if (!mRecycled) {
nativeDestroy(mNativePix);
mRecycled = true;
}
}
@Override
protected void finalize() throws Throwable {
recycle();
super.finalize();
}
/**
* Creates a new Pix from raw Pix data obtained from getData().
*
* @param pixData Raw pix data obtained from getData().
* @param width The width of the original Pix.
* @param height The height of the original Pix.
* @param depth The bit-depth of the original Pix.
* @return a new Pix or <code>null</code> on error
*/
public static Pix createFromPix(byte[] pixData, int width, int height, int depth) {
long nativePix = nativeCreateFromData(pixData, width, height, depth);
if (nativePix == 0) {
throw new OutOfMemoryError();
}
return new Pix(nativePix);
}
/**
* Returns a Rect with the width and height of this Pix.
*
* @return a Rect with the width and height of this Pix
*/
public Rect getRect() {
int w = getWidth();
int h = getHeight();
return new Rect(0, 0, w, h);
}
/**
* Returns the width of this Pix.
*
* @return the width of this Pix
*/
public int getWidth() {
return nativeGetWidth(mNativePix);
}
/**
* Returns the height of this Pix.
*
* @return the height of this Pix
*/
public int getHeight() {
return nativeGetHeight(mNativePix);
}
/**
* Returns the depth of this Pix.
*
* @return the depth of this Pix
*/
public int getDepth() {
return nativeGetDepth(mNativePix);
}
/**
* Returns the {@link android.graphics.Color} at the specified location.
*
* @param x The x coordinate (0...width-1) of the pixel to return.
* @param y The y coordinate (0...height-1) of the pixel to return.
* @return The argb {@link android.graphics.Color} at the specified
* coordinate.
* @throws IllegalArgumentException If x, y exceeds the image bounds.
*/
public int getPixel(int x, int y) {
if (x < 0 || x >= getWidth()) {
throw new IllegalArgumentException("Supplied x coordinate exceeds image bounds");
} else if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException("Supplied x coordinate exceeds image bounds");
}
return nativeGetPixel(mNativePix, x, y);
}
/**
* Sets the {@link android.graphics.Color} at the specified location.
*
* @param x The x coordinate (0...width-1) of the pixel to set.
* @param y The y coordinate (0...height-1) of the pixel to set.
* @param color The argb {@link android.graphics.Color} to set at the
* specified coordinate.
* @throws IllegalArgumentException If x, y exceeds the image bounds.
*/
public void setPixel(int x, int y, int color) {
if (x < 0 || x >= getWidth()) {
throw new IllegalArgumentException("Supplied x coordinate exceeds image bounds");
} else if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException("Supplied x coordinate exceeds image bounds");
}
nativeSetPixel(mNativePix, x, y, color);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativeCreatePix(int w, int h, int d);
private static native long nativeCreateFromData(byte[] data, int w, int h, int d);
private static native boolean nativeGetData(long nativePix, byte[] data);
private static native int nativeGetDataSize(long nativePix);
private static native long nativeClone(long nativePix);
private static native long nativeCopy(long nativePix);
private static native boolean nativeInvert(long nativePix);
private static native void nativeDestroy(long nativePix);
private static native boolean nativeGetDimensions(long nativePix, int[] dimensions);
private static native int nativeGetWidth(long nativePix);
private static native int nativeGetHeight(long nativePix);
private static native int nativeGetDepth(long nativePix);
private static native int nativeGetPixel(long nativePix, int x, int y);
private static native void nativeSetPixel(long nativePix, int x, int y, int color);
}

View File

@@ -0,0 +1,450 @@
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
import android.graphics.Rect;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Java representation of a native PIXA object. This object contains multiple
* PIX objects and their associated bounding BOX objects.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Pixa implements Iterable<Pix> {
static {
System.loadLibrary("lept");
}
/** A pointer to the native PIXA object. This is used internally by native code. */
final long mNativePixa;
/** The specified width of this Pixa. */
final int mWidth;
/** The specified height of this Pixa. */
final int mHeight;
private boolean mRecycled;
/**
* Creates a new Pixa with the specified minimum capacity. The Pixa will
* expand automatically as new Pix are added.
*
* @param size The minimum capacity of this Pixa.
* @return a new Pixa or <code>null</code> on error
*/
public static Pixa createPixa(int size) {
return createPixa(size, 0, 0);
}
/**
* Creates a new Pixa with the specified minimum capacity. The Pixa will
* expand automatically as new Pix are added.
* <p>
* If non-zero, the specified width and height will be used to specify the
* bounds of output images. *
*
* @param size The minimum capacity of this Pixa.
* @param width (Optional) The width of this Pixa, use 0 for default.
* @param height (Optional) The height of this Pixa, use 0 for default.
* @return a new Pixa or <code>null</code> on error
*/
public static Pixa createPixa(int size, int width, int height) {
long nativePixa = nativeCreate(size);
if (nativePixa == 0) {
throw new OutOfMemoryError();
}
return new Pixa(nativePixa, width, height);
}
/**
* Creates a wrapper for the specified native Pixa pointer.
*
* @param nativePixa Native pointer to a PIXA object.
* @param width The width of the PIXA.
* @param height The height of the PIXA.
*/
public Pixa(long nativePixa, int width, int height) {
mNativePixa = nativePixa;
mWidth = width;
mHeight = height;
mRecycled = false;
}
/**
* Returns a pointer to the native PIXA object. This is used by native code.
*
* @return a pointer to the native PIXA object
*/
public long getNativePixa() {
return mNativePixa;
}
/**
* Creates a shallow copy of this Pixa. Contained Pix are cloned, and the
* resulting Pixa may be recycled separately from the original.
*
* @return a shallow copy of this Pixa
*/
public Pixa copy() {
int nativePixa = nativeCopy(mNativePixa);
if (nativePixa == 0) {
throw new OutOfMemoryError();
}
return new Pixa(nativePixa, mWidth, mHeight);
}
/**
* Sorts this Pixa using the specified field and order. See
* Constants.L_SORT_BY_* and Constants.L_SORT_INCREASING or
* Constants.L_SORT_DECREASING.
*
* @param field The field to sort by. See Constants.L_SORT_BY_*.
* @param order The order in which to sort. Must be either
* Constants.L_SORT_INCREASING or Constants.L_SORT_DECREASING.
* @return a sorted copy of this Pixa
*/
public Pixa sort(int field, int order) {
int nativePixa = nativeSort(mNativePixa, field, order);
if (nativePixa == 0) {
throw new OutOfMemoryError();
}
return new Pixa(nativePixa, mWidth, mHeight);
}
/**
* Returns the number of elements in this Pixa.
*
* @return the number of elements in this Pixa
*/
public int size() {
return nativeGetCount(mNativePixa);
}
/**
* Recycles this Pixa and frees natively allocated memory. You may not
* access or modify the Pixa after calling this method.
* <p>
* Any Pix obtained from this Pixa or copies of this Pixa will still be
* accessible until they are explicitly recycled or finalized by the garbage
* collector.
*/
public synchronized void recycle() {
if (!mRecycled) {
nativeDestroy(mNativePixa);
mRecycled = true;
}
}
@Override
protected void finalize() throws Throwable {
recycle();
super.finalize();
}
/**
* Merges the contents of another Pixa into this one.
*
* @param otherPixa
* @return <code>true</code> on success
*/
public boolean join(Pixa otherPixa) {
return nativeJoin(mNativePixa, otherPixa.mNativePixa);
}
/**
* Adds a Pix to this Pixa.
*
* @param pix The Pix to add.
* @param mode The mode in which to add this Pix, typically
* Constants.L_CLONE.
*/
public void addPix(Pix pix, int mode) {
nativeAddPix(mNativePixa, pix.mNativePix, mode);
}
/**
* Adds a Box to this Pixa.
*
* @param box The Box to add.
* @param mode The mode in which to add this Box, typically
* Constants.L_CLONE.
*/
public void addBox(Box box, int mode) {
nativeAddBox(mNativePixa, box.mNativeBox, mode);
}
/**
* Adds a Pix and associated Box to this Pixa.
*
* @param pix The Pix to add.
* @param box The Box to add.
* @param mode The mode in which to add this Pix and Box, typically
* Constants.L_CLONE.
*/
public void add(Pix pix, Box box, int mode) {
nativeAdd(mNativePixa, pix.mNativePix, box.mNativeBox, mode);
}
/**
* Returns the Box at the specified index, or <code>null</code> on error.
*
* @param index The index of the Box to return.
* @return the Box at the specified index, or <code>null</code> on error
*/
public Box getBox(int index) {
long nativeBox = nativeGetBox(mNativePixa, index);
if (nativeBox == 0) {
return null;
}
return new Box(nativeBox);
}
/**
* Returns the Pix at the specified index, or <code>null</code> on error.
*
* @param index The index of the Pix to return.
* @return the Pix at the specified index, or <code>null</code> on error
*/
public Pix getPix(int index) {
int nativePix = nativeGetPix(mNativePixa, index);
if (nativePix == 0) {
return null;
}
return new Pix(nativePix);
}
/**
* Returns the width of this Pixa, or 0 if one was not set when it was
* created.
*
* @return the width of this Pixa, or 0 if one was not set when it was
* created
*/
public int getWidth() {
return mWidth;
}
/**
* Returns the height of this Pixa, or 0 if one was not set when it was
* created.
*
* @return the height of this Pixa, or 0 if one was not set when it was
* created
*/
public int getHeight() {
return mHeight;
}
/**
* Returns a bounding Rect for this Pixa, which may be (0,0,0,0) if width
* and height were not specified on creation.
*
* @return a bounding Rect for this Pixa
*/
public Rect getRect() {
return new Rect(0, 0, mWidth, mHeight);
}
/**
* Returns a bounding Rect for the Box at the specified index.
*
* @param index The index of the Box to get the bounding Rect of.
* @return a bounding Rect for the Box at the specified index
*/
public Rect getBoxRect(int index) {
int[] dimensions = getBoxGeometry(index);
if (dimensions == null) {
return null;
}
int x = dimensions[Box.INDEX_X];
int y = dimensions[Box.INDEX_Y];
int w = dimensions[Box.INDEX_W];
int h = dimensions[Box.INDEX_H];
Rect bound = new Rect(x, y, x + w, y + h);
return bound;
}
/**
* Returns a geometry array for the Box at the specified index. See
* Box.INDEX_* for indices.
*
* @param index The index of the Box to get the geometry of.
* @return a bounding Rect for the Box at the specified index
*/
public int[] getBoxGeometry(int index) {
int[] dimensions = new int[4];
if (getBoxGeometry(index, dimensions)) {
return dimensions;
}
return null;
}
/**
* Fills an array with the geometry of the Box at the specified index. See
* Box.INDEX_* for indices.
*
* @param index The index of the Box to get the geometry of.
* @param dimensions The array to fill with Box geometry. Must be at least 4
* elements.
* @return <code>true</code> on success
*/
public boolean getBoxGeometry(int index, int[] dimensions) {
return nativeGetBoxGeometry(mNativePixa, index, dimensions);
}
/**
* Returns an ArrayList of Box bounding Rects.
*
* @return an ArrayList of Box bounding Rects
*/
public ArrayList<Rect> getBoxRects() {
final int pixaCount = nativeGetCount(mNativePixa);
final int[] buffer = new int[4];
final ArrayList<Rect> rects = new ArrayList<Rect>(pixaCount);
for (int i = 0; i < pixaCount; i++) {
getBoxGeometry(i, buffer);
final int x = buffer[Box.INDEX_X];
final int y = buffer[Box.INDEX_Y];
final Rect bound = new Rect(x, y, x + buffer[Box.INDEX_W], y + buffer[Box.INDEX_H]);
rects.add(bound);
}
return rects;
}
/**
* Replaces the Pix and Box at the specified index with the specified Pix
* and Box, both of which may be recycled after calling this method.
*
* @param index The index of the Pix to replace.
* @param pix The Pix to replace the existing Pix.
* @param box The Box to replace the existing Box.
*/
public void replacePix(int index, Pix pix, Box box) {
nativeReplacePix(mNativePixa, index, pix.mNativePix, box.mNativeBox);
}
/**
* Merges the Pix at the specified indices and removes the Pix at the second
* index.
*
* @param indexA The index of the first Pix.
* @param indexB The index of the second Pix, which will be removed after
* merging.
*/
public void mergeAndReplacePix(int indexA, int indexB) {
nativeMergeAndReplacePix(mNativePixa, indexA, indexB);
}
/**
* Writes the components of this Pix to a bitmap-formatted file using a
* random color map.
*
* @param file The file to write to.
* @return <code>true</code> on success
*/
public boolean writeToFileRandomCmap(File file) {
return nativeWriteToFileRandomCmap(mNativePixa, file.getAbsolutePath(), mWidth, mHeight);
}
public Iterator<Pix> iterator() {
return new PixIterator();
}
private class PixIterator implements Iterator<Pix> {
private int mIndex;
private PixIterator() {
mIndex = 0;
}
public boolean hasNext() {
final int size = size();
return (size > 0 && mIndex < size);
}
public Pix next() {
return getPix(mIndex++);
}
public void remove() {
throw new UnsupportedOperationException();
}
}
// ***************
// * NATIVE CODE *
// ***************
private static native int nativeCreate(int size);
private static native int nativeCopy(long nativePixa);
private static native int nativeSort(long nativePixa, int field, int order);
private static native boolean nativeJoin(long nativePixa, long otherPixa);
private static native int nativeGetCount(long nativePixa);
private static native void nativeDestroy(long nativePixa);
private static native void nativeAddPix(long nativePixa, long nativePix, int mode);
private static native void nativeAddBox(long nativePixa, long nativeBox, int mode);
private static native void nativeAdd(long nativePixa, long nativePix, long nativeBox, int mode);
private static native boolean nativeWriteToFileRandomCmap(
long nativePixa, String fileName, int width, int height);
private static native void nativeReplacePix(
long nativePixa, int index, long nativePix, long nativeBox);
private static native void nativeMergeAndReplacePix(long nativePixa, int indexA, int indexB);
private static native long nativeGetBox(long nativePix, int index);
private static native int nativeGetPix(long nativePix, int index);
private static native boolean nativeGetBoxGeometry(long nativePixa, int index, int[] dimensions);
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.File;
/**
* Image input and output methods.
*
* @author alanv@google.com (Alan Viverette)
*/
public class ReadFile {
static {
System.loadLibrary("lept");
}
/**
* Creates a 32bpp Pix object from encoded data. Supported formats are BMP
* and JPEG.
*
* @param encodedData JPEG or BMP encoded byte data.
* @return a 32bpp Pix object
*/
public static Pix readMem(byte[] encodedData) {
if (encodedData == null)
throw new IllegalArgumentException("Image data byte array must be non-null");
final BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
final Bitmap bmp = BitmapFactory.decodeByteArray(encodedData, 0, encodedData.length,
opts);
final Pix pix = readBitmap(bmp);
bmp.recycle();
return pix;
}
/**
* Creates an 8bpp Pix object from raw 8bpp grayscale pixels.
*
* @param pixelData 8bpp grayscale pixel data.
* @param width The width of the input image.
* @param height The height of the input image.
* @return an 8bpp Pix object
*/
public static Pix readBytes8(byte[] pixelData, int width, int height) {
if (pixelData == null)
throw new IllegalArgumentException("Byte array must be non-null");
if (width <= 0)
throw new IllegalArgumentException("Image width must be greater than 0");
if (height <= 0)
throw new IllegalArgumentException("Image height must be greater than 0");
if (pixelData.length < width * height)
throw new IllegalArgumentException("Array length does not match dimensions");
long nativePix = nativeReadBytes8(pixelData, width, height);
if (nativePix == 0)
throw new RuntimeException("Failed to read pix from memory");
return new Pix(nativePix);
}
/**
* Replaces the bytes in an 8bpp Pix object with raw grayscale 8bpp pixels.
* Width and height be identical to the input Pix.
*
* @param pixs The Pix whose bytes will be replaced.
* @param pixelData 8bpp grayscale pixel data.
* @param width The width of the input image.
* @param height The height of the input image.
* @return an 8bpp Pix object
*/
public static boolean replaceBytes8(Pix pixs, byte[] pixelData, int width, int height) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (pixelData == null)
throw new IllegalArgumentException("Byte array must be non-null");
if (width <= 0)
throw new IllegalArgumentException("Image width must be greater than 0");
if (height <= 0)
throw new IllegalArgumentException("Image height must be greater than 0");
if (pixelData.length < width * height)
throw new IllegalArgumentException("Array length does not match dimensions");
if (pixs.getWidth() != width)
throw new IllegalArgumentException("Source pix width does not match image width");
if (pixs.getHeight() != height)
throw new IllegalArgumentException("Source pix width does not match image width");
return nativeReplaceBytes8(pixs.mNativePix, pixelData, width, height);
}
/**
* Creates a Pixa object from encoded files in a directory. Supported
* formats are BMP and JPEG.
*
* @param dir The directory containing the files.
* @param prefix The prefix of the files to load into a Pixa.
* @return a Pixa object containing one Pix for each file
*/
public static Pixa readFiles(File dir, String prefix) {
if (dir == null)
throw new IllegalArgumentException("Directory must be non-null");
if (!dir.exists())
throw new IllegalArgumentException("Directory does not exist");
if (!dir.canRead())
throw new IllegalArgumentException("Cannot read directory");
// TODO: Remove or fix this.
throw new RuntimeException("readFiles() is not current supported");
}
/**
* Creates a Pix object from encoded file data. Supported formats are BMP
* and JPEG.
*
* @param file The JPEG or BMP-encoded file to read in as a Pix.
* @return a Pix object
*/
public static Pix readFile(File file) {
if (file == null)
throw new IllegalArgumentException("File must be non-null");
if (!file.exists())
throw new IllegalArgumentException("File does not exist");
if (!file.canRead())
throw new IllegalArgumentException("Cannot read file");
final BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
final Bitmap bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), opts);
final Pix pix = readBitmap(bmp);
bmp.recycle();
return pix;
}
/**
* Creates a Pix object from Bitmap data. Currently supports only
* ARGB_8888-formatted bitmaps.
*
* @param bmp The Bitmap object to convert to a Pix.
* @return a Pix object
*/
public static Pix readBitmap(Bitmap bmp) {
if (bmp == null)
throw new IllegalArgumentException("Bitmap must be non-null");
if (bmp.getConfig() != Bitmap.Config.ARGB_8888)
throw new IllegalArgumentException("Bitmap config must be ARGB_8888");
long nativePix = nativeReadBitmap(bmp);
if (nativePix == 0)
throw new RuntimeException("Failed to read pix from bitmap");
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativeReadMem(byte[] data, int size);
private static native long nativeReadBytes8(byte[] data, int w, int h);
private static native boolean nativeReplaceBytes8(long nativePix, byte[] data, int w, int h);
private static native long nativeReadFiles(String dirname, String prefix);
private static native long nativeReadFile(String filename);
private static native long nativeReadBitmap(Bitmap bitmap);
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* @author alanv@google.com (Alan Viverette)
*/
public class Rotate {
static {
System.loadLibrary("lept");
}
// Rotation default
/** Default rotation quality is high. */
public static final boolean ROTATE_QUALITY = true;
/**
* Performs rotation using the default parameters.
*
* @param pixs The source pix.
* @param degrees The number of degrees to rotate; clockwise is positive.
* @return the rotated source image
*/
public static Pix rotate(Pix pixs, float degrees) {
return rotate(pixs, degrees, false);
}
/**
* Performs rotation with resizing using the default parameters.
*
* @param pixs The source pix.
* @param degrees The number of degrees to rotate; clockwise is positive.
* @param quality Whether to use high-quality rotation.
* @return the rotated source image
*/
public static Pix rotate(Pix pixs, float degrees, boolean quality) {
return rotate(pixs, degrees, quality, true);
}
/**
* Performs basic image rotation about the center.
* <p>
* Notes:
* <ol>
* <li>Rotation is about the center of the image.
* <li>For very small rotations, just return a clone.
* <li>Rotation brings either white or black pixels in from outside the
* image.
* <li>Above 20 degrees, if rotation by shear is requested, we rotate by
* sampling.
* <li>Colormaps are removed for rotation by area map and shear.
* <li>The dest can be expanded so that no image pixels are lost. To invoke
* expansion, input the original width and height. For repeated rotation,
* use of the original width and height allows the expansion to stop at the
* maximum required size, which is a square with side = sqrt(w*w + h*h).
* </ol>
*
* @param pixs The source pix.
* @param degrees The number of degrees to rotate; clockwise is positive.
* @param quality Whether to use high-quality rotation.
* @param Whether to expand the output so that no pixels are lost.
* <strong>Note:</strong> 1bpp images are always resized when
* quality is {@code true}.
* @return the rotated source image
*/
public static Pix rotate(Pix pixs, float degrees, boolean quality, boolean resize) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
long nativePix = nativeRotate(pixs.mNativePix, degrees, quality, resize);
if (nativePix == 0)
return null;
return new Pix(nativePix);
}
/**
* Performs top-level rotation by multiples of 90 degrees.
*
* @param pixs The source pix (all depths)
* @param quads 0-3; number of 90 degree cw rotations
* @return the rotated source image
*/
public static Pix rotateOrth(Pix pixs, int quads) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (quads < 0 || quads > 3)
throw new IllegalArgumentException("quads not in {0,1,2,3}");
int nativePix = nativeRotateOrth(pixs.mNativePix, quads);
if (nativePix == 0)
return null;
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native int nativeRotateOrth(long nativePix, int quads);
private static native long nativeRotate(long nativePix, float degrees, boolean quality,
boolean resize);
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Image scaling methods.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Scale {
static {
System.loadLibrary("lept");
}
public enum ScaleType {
/* Scale in X and Y independently, so that src matches dst exactly. */
FILL,
/*
* Compute a scale that will maintain the original src aspect ratio, but
* will also ensure that src fits entirely inside dst. May shrink or
* expand src to fit dst.
*/
FIT,
/*
* Compute a scale that will maintain the original src aspect ratio, but
* will also ensure that src fits entirely inside dst. May shrink src to
* fit dst, but will not expand it.
*/
FIT_SHRINK,
}
/**
* Scales the Pix to a specified width and height using a specified scaling
* type (fill, stretch, etc.). Returns a scaled image or a clone of the Pix
* if no scaling is required.
*
* @param pixs
* @param width
* @param height
* @param type
* @return a scaled image or a clone of the Pix if no scaling is required
*/
public static Pix scaleToSize(Pix pixs, int width, int height, ScaleType type) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
int pixWidth = pixs.getWidth();
int pixHeight = pixs.getHeight();
float scaleX = width / (float) pixWidth;
float scaleY = height / (float) pixHeight;
switch (type) {
case FILL:
// Retains default scaleX and scaleY values
break;
case FIT:
scaleX = Math.min(scaleX, scaleY);
scaleY = scaleX;
break;
case FIT_SHRINK:
scaleX = Math.min(1.0f, Math.min(scaleX, scaleY));
scaleY = scaleX;
break;
}
return scale(pixs, scaleX, scaleY);
}
/**
* Scales the Pix to specified scale. If no scaling is required, returns a
* clone of the source Pix.
*
* @param pixs the source Pix
* @param scale dimension scaling factor
* @return a Pix scaled according to the supplied factors
*/
public static Pix scale(Pix pixs, float scale) {
return scale(pixs, scale, scale);
}
/**
* Scales the Pix to the specified scale without sharpening.
*
* @param pixs the source Pix (1, 2, 4, 8, 16 and 32 bpp)
* @param scale scaling factor for both X and Y
* @return a Pix scaled while maintaining its aspect ratio
*/
public static Pix scaleWithoutSharpening(Pix pixs, float scale) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (scale <= 0.0f)
throw new IllegalArgumentException("Scaling factor must be positive");
return new Pix(nativeScaleGeneral(pixs.mNativePix, scale, scale, 0f, 0));
}
/**
* Scales the Pix to specified x and y scale. If no scaling is required,
* returns a clone of the source Pix.
*
* @param pixs the source Pix
* @param scaleX x-dimension (width) scaling factor
* @param scaleY y-dimension (height) scaling factor
* @return a Pix scaled according to the supplied factors
*/
public static Pix scale(Pix pixs, float scaleX, float scaleY) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (scaleX <= 0.0f)
throw new IllegalArgumentException("X scaling factor must be positive");
if (scaleY <= 0.0f)
throw new IllegalArgumentException("Y scaling factor must be positive");
long nativePix = nativeScale(pixs.mNativePix, scaleX, scaleY);
if (nativePix == 0)
throw new RuntimeException("Failed to natively scale pix");
return new Pix(nativePix);
}
// ***************
// * NATIVE CODE *
// ***************
private static native long nativeScale(long nativePix, float scaleX, float scaleY);
private static native long nativeScaleGeneral(long nativePix, float scaleX, float scaleY, float sharpfract, int sharpwidth);
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
/**
* Image rotation and skew detection methods.
*
* @author alanv@google.com (Alan Viverette)
*/
public class Skew {
static {
System.loadLibrary("lept");
}
// Text alignment defaults
/** Default range for sweep, will detect rotation of + or - 30 degrees. */
public final static float SWEEP_RANGE = 30.0f;
/** Default sweep delta, reasonably accurate within 0.05 degrees. */
public final static float SWEEP_DELTA = 5.0f;
/** Default sweep reduction, one-eighth the size of the original image. */
public final static int SWEEP_REDUCTION = 8;
/** Default sweep reduction, one-fourth the size of the original image. */
public final static int SEARCH_REDUCTION = 4;
/** Default search minimum delta, reasonably accurate within 0.05 degrees. */
public final static float SEARCH_MIN_DELTA = 0.01f;
/**
* Finds and returns the skew angle using default parameters.
*
* @param pixs Input pix (1 bpp).
* @return the detected skew angle, or 0.0 on failure
*/
public static float findSkew(Pix pixs) {
return findSkew(pixs, SWEEP_RANGE, SWEEP_DELTA, SWEEP_REDUCTION, SEARCH_REDUCTION,
SEARCH_MIN_DELTA);
}
/**
* Finds and returns the skew angle, doing first a sweep through a set of
* equal angles, and then doing a binary search until convergence.
* <p>
* Notes:
* <ol>
* <li>In computing the differential line sum variance score, we sum the
* result over scanlines, but we always skip:
* <ul>
* <li>at least one scanline
* <li>not more than 10% of the image height
* <li>not more than 5% of the image width
* </ul>
* </ol>
*
* @param pixs Input pix (1 bpp).
* @param sweepRange Half the full search range, assumed about 0; in
* degrees.
* @param sweepDelta Angle increment of sweep; in degrees.
* @param sweepReduction Sweep reduction factor = 1, 2, 4 or 8.
* @param searchReduction Binary search reduction factor = 1, 2, 4 or 8; and
* must not exceed redsweep.
* @param searchMinDelta Minimum binary search increment angle; in degrees.
* @return the detected skew angle, or 0.0 on failure
*/
public static float findSkew(Pix pixs, float sweepRange, float sweepDelta, int sweepReduction,
int searchReduction, float searchMinDelta) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
return nativeFindSkew(pixs.mNativePix, sweepRange, sweepDelta, sweepReduction,
searchReduction, searchMinDelta);
}
// ***************
// * NATIVE CODE *
// ***************
private static native float nativeFindSkew(long nativePix, float sweepRange, float sweepDelta,
int sweepReduction, int searchReduction, float searchMinDelta);
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.leptonica.android;
import android.graphics.Bitmap;
import java.io.File;
/**
* @author alanv@google.com (Alan Viverette)
*/
public class WriteFile {
static {
System.loadLibrary("lept");
}
/* Default JPEG quality */
public static final int DEFAULT_QUALITY = 85;
/* Default JPEG progressive encoding */
public static final boolean DEFAULT_PROGRESSIVE = true;
/**
* Write an 8bpp Pix to a flat byte array.
*
* @param pixs The 8bpp source image.
* @return a byte array where each byte represents a single 8-bit pixel
*/
public static byte[] writeBytes8(Pix pixs) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
int size = pixs.getWidth() * pixs.getHeight();
if (pixs.getDepth() != 8) {
Pix pix8 = Convert.convertTo8(pixs);
pixs.recycle();
pixs = pix8;
}
byte[] data = new byte[size];
writeBytes8(pixs, data);
return data;
}
/**
* Write an 8bpp Pix to a flat byte array.
*
* @param pixs The 8bpp source image.
* @param data A byte array large enough to hold the pixels of pixs.
* @return the number of bytes written to data
*/
public static int writeBytes8(Pix pixs, byte[] data) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
int size = pixs.getWidth() * pixs.getHeight();
if (data.length < size)
throw new IllegalArgumentException("Data array must be large enough to hold image bytes");
int bytesWritten = nativeWriteBytes8(pixs.mNativePix, data);
return bytesWritten;
}
/**
* Writes all the images in a Pixa array to individual files using the
* specified format. The output file extension will be determined by the
* format.
* <p>
* Output file names will take the format <path>/<prefix><index>.<extension>
*
* @param pixas The source Pixa image array.
* @param path The output directory.
* @param prefix The prefix to give output files.
* @param format The format to use for output files.
* @return <code>true</code> on success
*/
public static boolean writeFiles(Pixa pixas, File path, String prefix, int format) {
if (pixas == null)
throw new IllegalArgumentException("Source pixa must be non-null");
if (path == null)
throw new IllegalArgumentException("Destination path non-null");
if (prefix == null)
throw new IllegalArgumentException("Filename prefix must be non-null");
//String rootname = new File(path, prefix).getAbsolutePath();
throw new RuntimeException("writeFiles() is not currently supported");
}
/**
* Write a Pix to a byte array using the specified encoding from
* Constants.IFF_*.
*
* @param pixs The source image.
* @param format A format from Constants.IFF_*.
* @return a byte array containing encoded bytes
*/
public static byte[] writeMem(Pix pixs, int format) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
throw new RuntimeException("writeMem() is not currently supported");
}
/**
* Writes a Pix to file using the file extension as the output format;
* supported formats are .jpg or .jpeg for JPEG and .bmp for bitmap.
* <p>
* Uses default quality and progressive encoding settings.
*
* @param pixs Source image.
* @param file The file to write.
* @return <code>true</code> on success
*/
public static boolean writeImpliedFormat(Pix pixs, File file) {
return writeImpliedFormat(pixs, file, DEFAULT_QUALITY, DEFAULT_PROGRESSIVE);
}
/**
* Writes a Pix to file using the file extension as the output format;
* supported formats are .jpg or .jpeg for JPEG and .bmp for bitmap.
* <p>
* Notes:
* <ol>
* <li>This determines the output format from the filename extension.
* <li>The last two args are ignored except for requests for jpeg files.
* <li>The jpeg default quality is 75.
* </ol>
*
* @param pixs Source image.
* @param file The file to write.
* @param quality (Only for lossy formats) Quality between 1 - 100, 0 for
* default.
* @param progressive (Only for JPEG) Whether to encode as progressive.
* @return <code>true</code> on success
*/
public static boolean writeImpliedFormat(
Pix pixs, File file, int quality, boolean progressive) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
if (file == null)
throw new IllegalArgumentException("File must be non-null");
return nativeWriteImpliedFormat(
pixs.mNativePix, file.getAbsolutePath(), quality, progressive);
}
/**
* Writes a Pix to an Android Bitmap object. The output Bitmap will always
* be in ARGB_8888 format, but the input Pixs may be any bit-depth.
*
* @param pixs The source image.
* @return a Bitmap containing a copy of the source image, or <code>null
* </code> on failure
*/
public static Bitmap writeBitmap(Pix pixs) {
if (pixs == null)
throw new IllegalArgumentException("Source pix must be non-null");
final int[] dimensions = pixs.getDimensions();
final int width = dimensions[Pix.INDEX_W];
final int height = dimensions[Pix.INDEX_H];
//final int depth = dimensions[Pix.INDEX_D];
final Bitmap.Config config = Bitmap.Config.ARGB_8888;
final Bitmap bitmap = Bitmap.createBitmap(width, height, config);
if (nativeWriteBitmap(pixs.mNativePix, bitmap)) {
return bitmap;
}
bitmap.recycle();
return null;
}
// ***************
// * NATIVE CODE *
// ***************
private static native int nativeWriteBytes8(long nativePix, byte[] data);
private static native boolean nativeWriteFiles(long nativePix, String rootname, int format);
private static native byte[] nativeWriteMem(long nativePix, int format);
private static native boolean nativeWriteImpliedFormat(
long nativePix, String fileName, int quality, boolean progressive);
private static native boolean nativeWriteBitmap(long nativePix, Bitmap bitmap);
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.tesseract.android;
import com.googlecode.tesseract.android.TessBaseAPI.PageIteratorLevel;
public class PageIterator {
static {
System.loadLibrary("lept");
System.loadLibrary("tess");
}
/** Pointer to native page iterator. */
private final long mNativePageIterator;
/* package */PageIterator(long nativePageIterator) {
mNativePageIterator = nativePageIterator;
}
/**
* Resets the iterator to point to the start of the page.
*/
public void begin() {
nativeBegin(mNativePageIterator);
}
/**
* Moves to the start of the next object at the given level in the page
* hierarchy, and returns false if the end of the page was reached.
* <p>
* NOTE that {@link PageIteratorLevel#RIL_SYMBOL} will skip non-text blocks,
* but all other {@link PageIteratorLevel} level values will visit each
* non-text block once. Think of non text blocks as containing a single
* para, with a single line, with a single imaginary word.
* <p>
* Calls to {@link #next} with different levels may be freely intermixed.
* <p>
* This function iterates words in right-to-left scripts correctly, if the
* appropriate language has been loaded into Tesseract.
*
* @param level the page iterator level. See {@link PageIteratorLevel}.
* @return {@code false} if the end of the page was reached, {@code true}
* otherwise.
*/
public boolean next(int level) {
return nativeNext(mNativePageIterator, level);
}
/**
* Get bounding box: x, y, w, h
*
* ============= Accessing data ==============.
* Coordinate system:
* Integer coordinates are at the cracks between the pixels.
* The top-left corner of the top-left pixel in the image is at (0,0).
* The bottom-right corner of the bottom-right pixel in the image is at
* (width, height).
* Every bounding box goes from the top-left of the top-left contained
* pixel to the bottom-right of the bottom-right contained pixel, so
* the bounding box of the single top-left pixel in the image is:
* (0,0)->(1,1).
* If an image rectangle has been set in the API, then returned coordinates
* relate to the original (full) image, rather than the rectangle.
*
* Returns the bounding rectangle of the current object at the given level.
* See comment on coordinate system above.
* The returned bounding box may clip foreground pixels from a grey image.
*
* @param level the page iterator level. See {@link PageIteratorLevel}.
* @return the bounding rectangle of the current object at the given level
*/
public int[] getBoundingBox(int level){
return nativeBoundingBox(mNativePageIterator, level);
}
private static native void nativeBegin(long nativeIterator);
private static native boolean nativeNext(long nativeIterator, int level);
private static native int[] nativeBoundingBox(long nativeIterator, int level);
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.tesseract.android;
import java.util.ArrayList;
import java.util.List;
import android.util.Log;
import android.util.Pair;
import com.googlecode.tesseract.android.TessBaseAPI.PageIteratorLevel;
/**
* Java interface for the ResultIterator. Does not implement all available JNI
* methods, but does implement enough to be useful. Comments are adapted from
* original Tesseract source.
*
* @author alanv@google.com (Alan Viverette)
*/
public class ResultIterator extends PageIterator {
static {
System.loadLibrary("lept");
System.loadLibrary("tess");
}
/** Pointer to native result iterator. */
private final long mNativeResultIterator;
/* package */ResultIterator(long nativeResultIterator) {
super(nativeResultIterator);
mNativeResultIterator = nativeResultIterator;
}
/**
* Returns the text string for the current object at the given level.
*
* @param level the page iterator level. See {@link PageIteratorLevel}.
* @return the text string for the current object at the given level.
*/
public String getUTF8Text(int level) {
return nativeGetUTF8Text(mNativeResultIterator, level);
}
/**
* Returns the mean confidence of the current object at the given level. The
* number should be interpreted as a percent probability (0-100).
*
* @param level the page iterator level. See {@link PageIteratorLevel}.
* @return the mean confidence of the current object at the given level.
*/
public float confidence(int level) {
return nativeConfidence(mNativeResultIterator, level);
}
/**
* Returns all possible matching text strings and their confidence level
* for the current object at the given level.
* <p>
* The default matching text is blank ("").
* The default confidence level is zero (0.0)
*
* @param level the page iterator level. See {@link PageIteratorLevel}.
* @return A list of pairs with the UTF string and the confidence
*/
public List<Pair<String, Double>> getChoicesAndConfidence(int level) {
// Get the native choices
String[] nativeChoices = nativeGetChoices(mNativeResultIterator, level);
// Create the output list
ArrayList<Pair<String, Double>> pairedResults = new ArrayList<Pair<String, Double>>();
for (int i = 0; i < nativeChoices.length; i++ ) {
// The string and the confidence level are separated by a '|'
int separatorPosition = nativeChoices[i].lastIndexOf('|');
// Create a pair with the choices
String utfString = "";
Double confidenceLevel = Double.valueOf(0);
if (separatorPosition > 0) {
// If the string contains a '|' separate the UTF string and the confidence level
utfString = nativeChoices[i].substring(0, separatorPosition);
try {
confidenceLevel = Double.parseDouble(nativeChoices[i].substring(separatorPosition + 1));
} catch (NumberFormatException e) {
Log.e("ResultIterator","Invalid confidence level for " + nativeChoices[i]);
}
} else {
// If the string contains no '|' then save the full native result as the utfString
utfString = nativeChoices[i];
}
// Add the UTF string to the results
pairedResults.add(new Pair<String, Double> (utfString, confidenceLevel));
}
return pairedResults;
}
private static native String[] nativeGetChoices(long nativeResultIterator, int level);
private static native String nativeGetUTF8Text(long nativeResultIterator, int level);
private static native float nativeConfidence(long nativeResultIterator, int level);
}

View File

@@ -0,0 +1,742 @@
/*
* Copyright (C) 2011 Google Inc.
* Copyright (C) 2011 Robert Theis
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.tesseract.android;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.Log;
import com.googlecode.leptonica.android.Pixa;
import com.googlecode.leptonica.android.Pix;
import com.googlecode.leptonica.android.ReadFile;
import java.io.File;
/**
* Java interface for the Tesseract OCR engine. Does not implement all available
* JNI methods, but does implement enough to be useful. Comments are adapted
* from original Tesseract source.
*
* @author alanv@google.com (Alan Viverette)
*/
public class TessBaseAPI {
/**
* Used by the native implementation of the class.
*/
private long mNativeData;
static {
System.loadLibrary("lept");
System.loadLibrary("tess");
nativeClassInit();
}
public static final class PageSegMode {
/** Orientation and script detection only. */
public static final int PSM_OSD_ONLY = 0;
/** Automatic page segmentation with orientation and script detection. (OSD) */
public static final int PSM_AUTO_OSD = 1;
/** Fully automatic page segmentation, but no OSD, or OCR. */
public static final int PSM_AUTO_ONLY = 2;
/** Fully automatic page segmentation, but no OSD. */
public static final int PSM_AUTO = 3;
/** Assume a single column of text of variable sizes. */
public static final int PSM_SINGLE_COLUMN = 4;
/** Assume a single uniform block of vertically aligned text. */
public static final int PSM_SINGLE_BLOCK_VERT_TEXT = 5;
/** Assume a single uniform block of text. (Default.) */
public static final int PSM_SINGLE_BLOCK = 6;
/** Treat the image as a single text line. */
public static final int PSM_SINGLE_LINE = 7;
/** Treat the image as a single word. */
public static final int PSM_SINGLE_WORD = 8;
/** Treat the image as a single word in a circle. */
public static final int PSM_CIRCLE_WORD = 9;
/** Treat the image as a single character. */
public static final int PSM_SINGLE_CHAR = 10;
/** Find as much text as possible in no particular order. */
public static final int PSM_SPARSE_TEXT = 11;
/** Sparse text with orientation and script detection. */
public static final int PSM_SPARSE_TEXT_OSD = 12;
/** Number of enum entries. */
public static final int PSM_COUNT = 13;
}
/** Whitelist of characters to recognize. */
public static final String VAR_CHAR_WHITELIST = "tessedit_char_whitelist";
/** Blacklist of characters to not recognize. */
public static final String VAR_CHAR_BLACKLIST = "tessedit_char_blacklist";
/** Save blob choices allowing us to get alternative results. */
public static final String VAR_SAVE_BLOB_CHOICES = "save_blob_choices";
/** String value used to assign a boolean variable to true. */
public static final String VAR_TRUE = "T";
/** String value used to assign a boolean variable to false. */
public static final String VAR_FALSE = "F";
/** Run Tesseract only - fastest */
public static final int OEM_TESSERACT_ONLY = 0;
/** Run Cube only - better accuracy, but slower */
public static final int OEM_CUBE_ONLY = 1;
/** Run both and combine results - best accuracy */
public static final int OEM_TESSERACT_CUBE_COMBINED = 2;
/** Default OCR engine mode. */
public static final int OEM_DEFAULT = 3;
/**
* Elements of the page hierarchy, used in {@link ResultIterator} to provide
* functions that operate on each level without having to have 5x as many
* functions.
* <p>
* NOTE: At present {@link #RIL_PARA} and {@link #RIL_BLOCK} are equivalent
* as there is no paragraph internally yet.
*/
public static final class PageIteratorLevel {
/** Block of text/image/separator line. */
public static final int RIL_BLOCK = 0;
/** Paragraph within a block. */
public static final int RIL_PARA = 1;
/** Line within a paragraph. */
public static final int RIL_TEXTLINE = 2;
/** Word within a text line. */
public static final int RIL_WORD = 3;
/** Symbol/character within a word. */
public static final int RIL_SYMBOL = 4;
};
private ProgressNotifier progressNotifier;
/**
* Interface that may be implemented by calling object in order to receive
* progress callbacks during OCR.
*/
public interface ProgressNotifier {
void onProgressValues(ProgressValues progressValues);
}
/**
* Represents values indicating recognition progress and status.
*/
public class ProgressValues {
private int percent;
private int boundingBoxLeft;
private int boundingBoxRight;
private int boundingBoxTop;
private int boundingBoxBottom;
public ProgressValues(int percent, int left, int right, int top, int bottom) {
this.percent = percent;
this.boundingBoxLeft = left;
this.boundingBoxRight = right;
this.boundingBoxTop = top;
this.boundingBoxBottom = bottom;
}
public int getPercent() {
return percent;
}
public int getBoundingBoxLeft() {
return boundingBoxLeft;
}
public int getBoundingBoxRight() {
return boundingBoxRight;
}
public int getBoundingBoxTop() {
return boundingBoxTop;
}
public int getBoundingBoxBottom() {
return boundingBoxBottom;
}
}
/**
* Constructs an instance of TessBaseAPI.
*/
public TessBaseAPI() {
nativeConstruct();
}
/**
* Constructs an instance of TessBaseAPI with a callback method for
* receiving progress updates during OCR.
*
* @param progressNotifier Callback to receive progress notifications
*/
public TessBaseAPI(ProgressNotifier progressNotifier) {
this.progressNotifier = progressNotifier;
nativeConstruct();
}
/**
* Called by the GC to clean up the native data that we set up when we
* construct the object.
*
* Altered from original version to avoid a crash-causing bug in OCR Test application.
*/
@Override
protected void finalize() throws Throwable {
// TODO Find out why finalize() is getting called when we change languages, even though
// we're still using the object. Is bypassing nativeFinalize() OK if we still call
// baseApi.end() in the Activity's onDestroy()?
try {
Log.d("TessBaseAPI.java", "finalize(): NOT calling nativeFinalize() due to premature garbage collection");
//nativeFinalize();
} finally {
Log.d("TessBaseAPI.java", "finalize(): calling super.finalize()");
super.finalize();
}
}
/**
* Initializes the Tesseract engine with a specified language model. Returns
* <code>true</code> on success.
* <p>
* Instances are now mostly thread-safe and totally independent, but some
* global parameters remain. Basically it is safe to use multiple
* TessBaseAPIs in different threads in parallel, UNLESS you use SetVariable
* on some of the Params in classify and textord. If you do, then the effect
* will be to change it for all your instances.
* <p>
* The datapath must be the name of the parent directory of tessdata and
* must end in / . Any name after the last / will be stripped. The language
* is (usually) an ISO 639-3 string or <code>null</code> will default to eng.
* It is entirely safe (and eventually will be efficient too) to call Init
* multiple times on the same instance to change language, or just to reset
* the classifier.
* <p>
* The language may be a string of the form [~]<lang>[+[~]<lang>]* indicating
* that multiple languages are to be loaded. Eg hin+eng will load Hindi and
* English. Languages may specify internally that they want to be loaded
* with one or more other languages, so the ~ sign is available to override
* that. Eg if hin were set to load eng by default, then hin+~eng would force
* loading only hin. The number of loaded languages is limited only by
* memory, with the caveat that loading additional languages will impact
* both speed and accuracy, as there is more work to do to decide on the
* applicable language, and there is more chance of hallucinating incorrect
* words.
* <p>
* <b>WARNING:</b> On changing languages, all Tesseract parameters are reset
* back to their default values. (Which may vary between languages.)
* <p>
* If you have a rare need to set a Variable that controls initialization
* for a second call to Init you should explicitly call End() and then use
* SetVariable before Init. This is only a very rare use case, since there
* are very few uses that require any parameters to be set before Init.
*
* @param datapath the parent directory of tessdata ending in a forward
* slash
* @param language (optional) an ISO 639-3 string representing the language(s)
* @return <code>true</code> on success
*/
public boolean init(String datapath, String language) {
if (datapath == null)
throw new IllegalArgumentException("Data path must not be null!");
if (!datapath.endsWith(File.separator))
datapath += File.separator;
File tessdata = new File(datapath + "tessdata");
if (!tessdata.exists() || !tessdata.isDirectory())
throw new IllegalArgumentException("Data path must contain subfolder tessdata!");
return nativeInit(datapath, language);
}
/**
* Initializes the Tesseract engine with the specified language model(s). Returns
* <code>true</code> on success.
*
* @param datapath the parent directory of tessdata ending in a forward
* slash
* @param language (optional) an ISO 639-3 string representing the language(s)
* @param ocrEngineMode the OCR engine mode to be set
* @return <code>true</code> on success
*/
public boolean init(String datapath, String language, int ocrEngineMode) {
if (datapath == null)
throw new IllegalArgumentException("Data path must not be null!");
if (!datapath.endsWith(File.separator))
datapath += File.separator;
File tessdata = new File(datapath + "tessdata");
if (!tessdata.exists() || !tessdata.isDirectory())
throw new IllegalArgumentException("Data path must contain subfolder tessdata!");
return nativeInitOem(datapath, language, ocrEngineMode);
}
/**
* Returns the languages string used in the last valid initialization.
* If the last initialization specified "deu+hin" then that will be
* returned. If hin loaded eng automatically as well, then that will
* not be included in this list. To find the languages actually
* loaded use GetLoadedLanguagesAsVector.
*
* @return the last-used language code
*/
public String getInitLanguagesAsString() {
return nativeGetInitLanguagesAsString();
}
/**
* Frees up recognition results and any stored image data, without actually
* freeing any recognition data that would be time-consuming to reload.
* Afterwards, you must call SetImage or SetRectangle before doing any
* Recognize or Get* operation.
*/
public void clear() {
nativeClear();
}
/**
* Closes down tesseract and free up all memory. End() is equivalent to
* destructing and reconstructing your TessBaseAPI.
* <p>
* Once End() has been used, none of the other API functions may be used
* other than Init and anything declared above it in the class definition.
*/
public void end() {
nativeEnd();
}
/**
* Set the value of an internal "variable" (of either old or new types).
* Supply the name of the variable and the value as a string, just as you
* would in a config file.
* <p>
* Example: <code>setVariable(VAR_TESSEDIT_CHAR_BLACKLIST, "xyz"); to ignore x, y and z. * setVariable(VAR_BLN_NUMERICMODE, "1"); to set numeric-only mode. * </code>
* <p>
* setVariable() may be used before open(), but settings will revert to
* defaults on close().
*
* @param var name of the variable
* @param value value to set
* @return false if the name lookup failed
*/
public boolean setVariable(String var, String value) {
return nativeSetVariable(var, value);
}
/**
* Return the current page segmentation mode.
*
* @return value of the current page segmentation mode
*/
public int getPageSegMode() {
return nativeGetPageSegMode();
}
/**
* Sets the page segmentation mode. This controls how much processing the
* OCR engine will perform before recognizing text.
*
* @param mode the page segmentation mode to set
*/
public void setPageSegMode(int mode) {
nativeSetPageSegMode(mode);
}
/**
* Sets debug mode. This controls how much information is displayed in the
* log during recognition.
*
* @param enabled <code>true</code> to enable debugging mode
*/
public void setDebug(boolean enabled) {
nativeSetDebug(enabled);
}
/**
* Restricts recognition to a sub-rectangle of the image. Call after
* SetImage. Each SetRectangle clears the recogntion results so multiple
* rectangles can be recognized with the same image.
*
* @param rect the bounding rectangle
*/
public void setRectangle(Rect rect) {
setRectangle(rect.left, rect.top, rect.width(), rect.height());
}
/**
* Restricts recognition to a sub-rectangle of the image. Call after
* SetImage. Each SetRectangle clears the recogntion results so multiple
* rectangles can be recognized with the same image.
*
* @param left the left bound
* @param top the right bound
* @param width the width of the bounding box
* @param height the height of the bounding box
*/
public void setRectangle(int left, int top, int width, int height) {
nativeSetRectangle(left, top, width, height);
}
/**
* Provides an image for Tesseract to recognize.
*
* @param file absolute path to the image file
*/
public void setImage(File file) {
Pix image = ReadFile.readFile(file);
if (image == null) {
throw new RuntimeException("Failed to read image file");
}
nativeSetImagePix(image.getNativePix());
}
/**
* Provides an image for Tesseract to recognize. Does not copy the image
* buffer. The source image must persist until after Recognize or
* GetUTF8Chars is called.
*
* @param bmp bitmap representation of the image
*/
public void setImage(Bitmap bmp) {
Pix image = ReadFile.readBitmap(bmp);
if (image == null) {
throw new RuntimeException("Failed to read bitmap");
}
nativeSetImagePix(image.getNativePix());
}
/**
* Provides a Leptonica pix format image for Tesseract to recognize. Clones
* the pix object. The source image may be destroyed immediately after
* SetImage is called, but its contents may not be modified.
*
* @param image Leptonica pix representation of the image
*/
public void setImage(Pix image) {
nativeSetImagePix(image.getNativePix());
}
/**
* Provides an image for Tesseract to recognize. Copies the image buffer.
* The source image may be destroyed immediately after SetImage is called.
* SetImage clears all recognition results, and sets the rectangle to the
* full image, so it may be followed immediately by a GetUTF8Text, and it
* will automatically perform recognition.
*
* @param imagedata byte representation of the image
* @param width image width
* @param height image height
* @param bpp bytes per pixel
* @param bpl bytes per line
*/
public void setImage(byte[] imagedata, int width, int height, int bpp, int bpl) {
nativeSetImageBytes(imagedata, width, height, bpp, bpl);
}
/**
* The recognized text is returned as a String which is coded as UTF8.
*
* @return the recognized text
*/
public String getUTF8Text() {
// Trim because the text will have extra line breaks at the end
String text = nativeGetUTF8Text();
return text.trim();
}
/**
* Returns the mean confidence of text recognition.
*
* @return the mean confidence
*/
public int meanConfidence() {
return nativeMeanConfidence();
}
/**
* Returns all word confidences (between 0 and 100) in an array. The number
* of confidences should correspond to the number of space-delimited words
* in GetUTF8Text().
*
* @return an array of word confidences (between 0 and 100) for each
* space-delimited word returned by GetUTF8Text()
*/
public int[] wordConfidences() {
int[] conf = nativeWordConfidences();
// We shouldn't return null confidences
if (conf == null)
conf = new int[0];
return conf;
}
/**
* Return a copy of the internal thresholded image from Tesseract.
* Only available after setImage.
*
* @return Pix containing the thresholded image
*/
public Pix getThresholdedImage() {
return new Pix(nativeGetThresholdedImage());
}
/**
* Returns the result of page layout analysis as a Pixa, in reading order.
*
* @return Pixa contaning page layout bounding boxes
*/
public Pixa getRegions() {
return new Pixa(nativeGetRegions(), 0, 0);
}
/**
* Returns the textlines as a Pixa.
*
* Block IDs are not returned.
*
* @return Pixa containing textlines
*/
public Pixa getTextlines() {
return new Pixa(nativeGetTextlines(), 0, 0);
}
/**
* Returns the strips as a Pixa.
*
* Block IDs are not returned.
*
* @return Pixa containing strips
*/
public Pixa getStrips() {
return new Pixa(nativeGetStrips(), 0, 0);
}
/**
* Returns the word bounding boxes as a Pixa, in reading order.
*
* @return Pixa containing word bounding boxes
*/
public Pixa getWords() {
return new Pixa(nativeGetWords(), 0, 0);
}
/**
* Gets the individual connected (text) components (created after pages
* segmentation step, but before recognition) as a Pixa, in reading order.
* Can be called before or after Recognize.
*
* @return Pixa containing connected components bounding boxes
*/
public Pixa getConnectedComponents() {
return new Pixa(nativeGetConnectedComponents(), 0, 0);
}
/**
* Returns an iterator allowing you to iterate over the top result for each recognized word or symbol.
*
* @return ResultIterator iterate over the words
*/
public ResultIterator getResultIterator() {
long nativeResultIterator = nativeGetResultIterator();
if (nativeResultIterator == 0) {
return null;
}
return new ResultIterator(nativeResultIterator);
}
/**
* Make a HTML-formatted string with hOCR markup from the internal data
* structures.
*
* @param page is 0-based but will appear in the output as 1-based.
* @return HTML-formatted string with hOCR markup
*/
public String getHOCRText(int page){
return nativeGetHOCRText(page);
}
/**
* Set the name of the input file. Needed only for training and
* reading a UNLV zone file.
*
* @param name input file name
*/
public void setInputName(String name){
nativeSetInputName(name);
}
/**
* Set the name of the output files.
* Needed only for debugging.
* @param name output file name
*/
public void setOutputName(String name){
nativeSetOutputName(name);
}
/**
* Read a "config" file containing a set of variable, value pairs.
* Searches the standard places: <i>tessdata/configs, tessdata/tessconfigs</i>.
*
* @param filename the configuration filename, without path
*/
public void ReadConfigFile(String filename){
nativeReadConfigFile(filename);
}
/**
* The recognized text is returned as coded in the same format as a UTF8
* box file used in training.
*
* @param page is a 0-based page index that will appear in the box file.
*/
public String getBoxText(int page){
return nativeGetBoxText(page);
}
/**
* Cancel any recognition in progress.
*/
public void stop() {
nativeStop();
}
/**
* Called from native code to update progress of ongoing recognition passes.
*
* @param percent Percent complete
* @param left Left bound of word bounding box
* @param right Right bound of word bounding box
* @param top Top bound of word bounding box
* @param bottom Bottom bound of word bounding box
*/
private void onProgressValues(final int percent, final int left,
final int right, final int top, final int bottom) {
if (progressNotifier != null) {
ProgressValues pv = new ProgressValues(percent, left, right, top, bottom);
progressNotifier.onProgressValues(pv);
}
}
// ******************
// * Native methods *
// ******************
/**
* Initializes static native data. Must be called on object load.
*/
private static native void nativeClassInit();
/**
* Initializes native data. Must be called on object construction.
*/
private native void nativeConstruct();
/**
* Finalizes native data. Must be called on object destruction.
*/
private native void nativeFinalize();
private native boolean nativeInit(String datapath, String language);
private native boolean nativeInitOem(String datapath, String language, int mode);
private native String nativeGetInitLanguagesAsString();
private native void nativeClear();
private native void nativeEnd();
private native void nativeSetImageBytes(
byte[] imagedata, int width, int height, int bpp, int bpl);
private native void nativeSetImagePix(long nativePix);
private native void nativeSetRectangle(int left, int top, int width, int height);
private native String nativeGetUTF8Text();
private native int nativeMeanConfidence();
private native int[] nativeWordConfidences();
private native boolean nativeSetVariable(String var, String value);
private native void nativeSetDebug(boolean debug);
private native int nativeGetPageSegMode();
private native void nativeSetPageSegMode(int mode);
private native long nativeGetThresholdedImage();
private native long nativeGetRegions();
private native long nativeGetTextlines();
private native long nativeGetStrips();
private native long nativeGetWords();
private native long nativeGetConnectedComponents();
private native long nativeGetResultIterator();
private native String nativeGetBoxText(int page_number);
private native String nativeGetHOCRText(int page_number);
private native void nativeSetInputName(String name);
private native void nativeSetOutputName(String name);
private native void nativeReadConfigFile(String fileName);
private native int nativeStop();
}