D4DJ leaderboard parsing bot
27
d4dj/.classpath
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
23
d4dj/.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>d4dj</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
4
d4dj/.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
encoding/<project>=UTF-8
|
8
d4dj/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,8 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
|
||||
org.eclipse.jdt.core.compiler.release=disabled
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
4
d4dj/.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
BIN
d4dj/imgtest1.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
d4dj/imgtest2.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
d4dj/imgtest3.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
d4dj/imgtest4.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
d4dj/imgtest5.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
86
d4dj/pom.xml
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>d4dj</groupId>
|
||||
<artifactId>d4dj</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<name>d4dj</name>
|
||||
<!-- FIXME change it to the project's website -->
|
||||
<url>http://www.example.com</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.tess4j</groupId>
|
||||
<artifactId>tess4j</artifactId>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,180 @@
|
||||
/**
|
||||
* <a url=http://www.jdeskew.com/>JDeskew</a>
|
||||
*/
|
||||
package com.recognition.software.jdeskew;
|
||||
|
||||
import net.sourceforge.tess4j.util.LoggHelper;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class ImageDeskew {
|
||||
|
||||
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
|
||||
/**
|
||||
* Representation of a line in the image.
|
||||
*/
|
||||
public class HoughLine {
|
||||
|
||||
// count of points in the line
|
||||
public int count = 0;
|
||||
// index in matrix.
|
||||
public int index = 0;
|
||||
// the line is represented as all x, y that solve y * cos(alpha) - x *
|
||||
// sin(alpha) = d
|
||||
public double alpha;
|
||||
public double d;
|
||||
}
|
||||
|
||||
// the source image
|
||||
private BufferedImage cImage;
|
||||
// the range of angles to search for lines
|
||||
private double cAlphaStart = -20;
|
||||
private double cAlphaStep = 0.2;
|
||||
private int cSteps = 40 * 5;
|
||||
// pre-calculation of sin and cos
|
||||
private double[] cSinA;
|
||||
private double[] cCosA;
|
||||
// range of d
|
||||
private double cDMin;
|
||||
private double cDStep = 1.0;
|
||||
private int cDCount;
|
||||
// count of points that fit in a line
|
||||
private int[] cHMatrix;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param image
|
||||
*/
|
||||
public ImageDeskew(BufferedImage image) {
|
||||
this.cImage = image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the skew angle of the image cImage.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public double getSkewAngle() {
|
||||
ImageDeskew.HoughLine[] hl;
|
||||
double sum = 0.0;
|
||||
int count = 0;
|
||||
|
||||
// perform Hough Transformation
|
||||
calc();
|
||||
// top 20 of the detected lines in the image
|
||||
hl = getTop(20);
|
||||
|
||||
if (hl.length >= 20) {
|
||||
// average angle of the lines
|
||||
for (int i = 0; i < 19; i++) {
|
||||
sum += hl[i].alpha;
|
||||
count++;
|
||||
}
|
||||
return (sum / count);
|
||||
} else {
|
||||
return 0.0d;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the count lines in the image with most points
|
||||
private ImageDeskew.HoughLine[] getTop(int count) {
|
||||
|
||||
ImageDeskew.HoughLine[] hl = new ImageDeskew.HoughLine[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
hl[i] = new ImageDeskew.HoughLine();
|
||||
}
|
||||
|
||||
ImageDeskew.HoughLine tmp;
|
||||
|
||||
for (int i = 0; i < (this.cHMatrix.length - 1); i++) {
|
||||
if (this.cHMatrix[i] > hl[count - 1].count) {
|
||||
hl[count - 1].count = this.cHMatrix[i];
|
||||
hl[count - 1].index = i;
|
||||
int j = count - 1;
|
||||
while ((j > 0) && (hl[j].count > hl[j - 1].count)) {
|
||||
tmp = hl[j];
|
||||
hl[j] = hl[j - 1];
|
||||
hl[j - 1] = tmp;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int alphaIndex;
|
||||
int dIndex;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
dIndex = hl[i].index / cSteps; // integer division, no
|
||||
// remainder
|
||||
alphaIndex = hl[i].index - dIndex * cSteps;
|
||||
hl[i].alpha = getAlpha(alphaIndex);
|
||||
hl[i].d = dIndex + cDMin;
|
||||
}
|
||||
|
||||
return hl;
|
||||
}
|
||||
|
||||
// Hough Transformation
|
||||
private void calc() {
|
||||
int hMin = (int) ((this.cImage.getHeight()) / 4.0);
|
||||
int hMax = (int) ((this.cImage.getHeight()) * 3.0 / 4.0);
|
||||
init();
|
||||
|
||||
for (int y = hMin; y < hMax; y++) {
|
||||
for (int x = 1; x < (this.cImage.getWidth() - 2); x++) {
|
||||
// only lower edges are considered
|
||||
if (ImageUtil.isBlack(this.cImage, x, y)) {
|
||||
if (!ImageUtil.isBlack(this.cImage, x, y + 1)) {
|
||||
calc(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// calculate all lines through the point (x,y)
|
||||
private void calc(int x, int y) {
|
||||
double d;
|
||||
int dIndex;
|
||||
int index;
|
||||
|
||||
for (int alpha = 0; alpha < (this.cSteps - 1); alpha++) {
|
||||
d = y * this.cCosA[alpha] - x * this.cSinA[alpha];
|
||||
dIndex = (int) (d - this.cDMin);
|
||||
index = dIndex * this.cSteps + alpha;
|
||||
try {
|
||||
this.cHMatrix[index] += 1;
|
||||
} catch (Exception e) {
|
||||
logger.warn("", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
||||
double angle;
|
||||
|
||||
// pre-calculation of sin and cos
|
||||
this.cSinA = new double[this.cSteps - 1];
|
||||
this.cCosA = new double[this.cSteps - 1];
|
||||
|
||||
for (int i = 0; i < (this.cSteps - 1); i++) {
|
||||
angle = getAlpha(i) * Math.PI / 180.0;
|
||||
this.cSinA[i] = Math.sin(angle);
|
||||
this.cCosA[i] = Math.cos(angle);
|
||||
}
|
||||
|
||||
// range of d
|
||||
this.cDMin = -this.cImage.getWidth();
|
||||
this.cDCount = (int) (2.0 * ((this.cImage.getWidth() + this.cImage.getHeight())) / this.cDStep);
|
||||
this.cHMatrix = new int[this.cDCount * this.cSteps];
|
||||
}
|
||||
|
||||
public double getAlpha(int index) {
|
||||
return this.cAlphaStart + (index * this.cAlphaStep);
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/**
|
||||
* <a url=http://www.jdeskew.com/>JDeskew</a>
|
||||
*/
|
||||
package com.recognition.software.jdeskew;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
import net.sourceforge.tess4j.util.LoggHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ImageUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
|
||||
/**
|
||||
* Whether the pixel is black.
|
||||
*
|
||||
* @param image source image
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
public static boolean isBlack(BufferedImage image, int x, int y) {
|
||||
if (image.getType() == BufferedImage.TYPE_BYTE_BINARY) {
|
||||
WritableRaster raster = image.getRaster();
|
||||
int pixelRGBValue = raster.getSample(x, y, 0);
|
||||
return pixelRGBValue == 0;
|
||||
}
|
||||
|
||||
int luminanceValue = 140;
|
||||
return isBlack(image, x, y, luminanceValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the pixel is black.
|
||||
*
|
||||
* @param image source image
|
||||
* @param x
|
||||
* @param y
|
||||
* @param luminanceCutOff
|
||||
* @return
|
||||
*/
|
||||
public static boolean isBlack(BufferedImage image, int x, int y, int luminanceCutOff) {
|
||||
int pixelRGBValue;
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
double luminance = 0.0;
|
||||
|
||||
// return white on areas outside of image boundaries
|
||||
if (x < 0 || y < 0 || x > image.getWidth() || y > image.getHeight()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
pixelRGBValue = image.getRGB(x, y);
|
||||
r = (pixelRGBValue >> 16) & 0xff;
|
||||
g = (pixelRGBValue >> 8) & 0xff;
|
||||
b = (pixelRGBValue) & 0xff;
|
||||
luminance = (r * 0.299) + (g * 0.587) + (b * 0.114);
|
||||
} catch (Exception e) {
|
||||
logger.warn("", e);
|
||||
}
|
||||
|
||||
return luminance < luminanceCutOff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates image.
|
||||
*
|
||||
* @param image source image
|
||||
* @param angle by degrees
|
||||
* @param cx x-coordinate of pivot point
|
||||
* @param cy y-coordinate of pivot point
|
||||
* @return rotated image
|
||||
*/
|
||||
public static BufferedImage rotate(BufferedImage image, double angle, int cx, int cy) {
|
||||
int width = image.getWidth(null);
|
||||
int height = image.getHeight(null);
|
||||
|
||||
int minX, minY, maxX, maxY;
|
||||
minX = minY = maxX = maxY = 0;
|
||||
|
||||
int[] corners = {0, 0, width, 0, width, height, 0, height};
|
||||
|
||||
double theta = Math.toRadians(angle);
|
||||
for (int i = 0; i < corners.length; i += 2) {
|
||||
int x = (int) (Math.cos(theta) * (corners[i] - cx)
|
||||
- Math.sin(theta) * (corners[i + 1] - cy) + cx);
|
||||
int y = (int) (Math.sin(theta) * (corners[i] - cx)
|
||||
+ Math.cos(theta) * (corners[i + 1] - cy) + cy);
|
||||
|
||||
if (x > maxX) {
|
||||
maxX = x;
|
||||
}
|
||||
|
||||
if (x < minX) {
|
||||
minX = x;
|
||||
}
|
||||
|
||||
if (y > maxY) {
|
||||
maxY = y;
|
||||
}
|
||||
|
||||
if (y < minY) {
|
||||
minY = y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cx = (cx - minX);
|
||||
cy = (cy - minY);
|
||||
|
||||
BufferedImage bi = new BufferedImage((maxX - minX), (maxY - minY),
|
||||
image.getType());
|
||||
Graphics2D g2 = bi.createGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
|
||||
g2.setBackground(Color.white);
|
||||
g2.fillRect(0, 0, bi.getWidth(), bi.getHeight());
|
||||
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.rotate(theta, cx, cy);
|
||||
|
||||
g2.setTransform(at);
|
||||
g2.drawImage(image, -minX, -minY, null);
|
||||
g2.dispose();
|
||||
|
||||
return bi;
|
||||
}
|
||||
}
|
177
d4dj/src/main/java/d4dj/d4dj/App.java
Normal file
@ -0,0 +1,177 @@
|
||||
package d4dj.d4dj;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.sourceforge.tess4j.Tesseract;
|
||||
import net.sourceforge.tess4j.TesseractException;
|
||||
import sig.utils.ImageUtils;
|
||||
class SubmitThread implements Runnable{
|
||||
String name,description,points;
|
||||
int event,rank;
|
||||
|
||||
SubmitThread(String name,String description,String points,int event,int rank) {
|
||||
this.name=name;
|
||||
this.description=description;
|
||||
this.points=points;
|
||||
this.event=event;
|
||||
this.rank=rank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
HttpClient httpclient = HttpClients.createDefault();
|
||||
HttpPost httppost = new HttpPost("http://projectdivar.com/eventsubmit");
|
||||
List<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
params.add(new BasicNameValuePair("eventid", Integer.toString(7)));
|
||||
params.add(new BasicNameValuePair("rank", Integer.toString(rank)));
|
||||
params.add(new BasicNameValuePair("name", name));
|
||||
params.add(new BasicNameValuePair("description", description));
|
||||
params.add(new BasicNameValuePair("points", points));
|
||||
try {
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//Execute and get the response.
|
||||
HttpResponse response = null;
|
||||
try {
|
||||
response = httpclient.execute(httppost);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
HttpEntity entity = response.getEntity();
|
||||
|
||||
if (entity != null) {
|
||||
try (InputStream instream = entity.getContent()) {
|
||||
Scanner s = new Scanner(instream).useDelimiter("\\A");
|
||||
String result = s.hasNext() ? s.next() : "";
|
||||
System.out.println(result);
|
||||
instream.close();
|
||||
} catch (UnsupportedOperationException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public class App
|
||||
{
|
||||
public static void main( String[] args )
|
||||
{
|
||||
/*
|
||||
Tesseract tesseract = new Tesseract();
|
||||
tesseract.setDatapath("C:\\Users\\sigon\\eclipse-workspace\\d4djRankReaderBot\\d4dj\\tessdata");
|
||||
try {
|
||||
tesseract.setLanguage("jpn");
|
||||
//tesseract.setLanguage("eng");
|
||||
String finaldata = tesseract.doOCR(new File("imgtest5.png"));
|
||||
Thread.sleep(500);
|
||||
System.out.println(finaldata);
|
||||
} catch (TesseractException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
|
||||
Tesseract tesseract = new Tesseract();
|
||||
tesseract.setTessVariable("tessedit_write_images", "true");
|
||||
tesseract.setDatapath("C:\\Users\\sigon\\eclipse-workspace\\d4djRankReaderBot\\d4dj\\tessdata");
|
||||
|
||||
|
||||
Rectangle[] namepositions = new Rectangle[] {new Rectangle(475,263,316,36),new Rectangle(475,384,316,36),new Rectangle(475,510,316,36),new Rectangle(475,636,316,36)};
|
||||
Rectangle[] descriptions = new Rectangle[] {new Rectangle(475,328,544,36),new Rectangle(475,452,544,36),new Rectangle(475,576,544,36),new Rectangle(475,700,544,36)};
|
||||
Rectangle[] pointpositions = new Rectangle[] {new Rectangle(1042,317,200,34),new Rectangle(1042,442,200,34),new Rectangle(1042,566,200,34),new Rectangle(1042,688,200,34)};
|
||||
Point[] offsets = new Point[] {new Point(0,0),new Point(0,-2),new Point(0,-1),new Point(0,5),new Point(0,20)};
|
||||
|
||||
String[][] namedata = new String[5][4];
|
||||
String[][] descriptiondata = new String[5][4];
|
||||
String[][] pointdata = new String[5][4];
|
||||
|
||||
while (true) {
|
||||
File f = new File("C:\\Users\\sigon\\Pictures\\MEmu Photo\\Screenshots");
|
||||
//System.out.println(Arrays.deepToString(f.listFiles()));
|
||||
|
||||
if (f.listFiles().length==5) {
|
||||
//New files found!
|
||||
|
||||
|
||||
//Grab the first 5 files and try to parse them.
|
||||
File[] list = f.listFiles();
|
||||
for (int i=0;i<5;i++) {
|
||||
try {
|
||||
BufferedImage img = ImageUtils.toBufferedImage(ImageIO.read(list[i]));
|
||||
//ImageIO.write(img,"png",new File("debug/img"+))
|
||||
for (int j=0;j<4;j++) {
|
||||
tesseract.setLanguage("jpn");
|
||||
//ImageIO.write(img.getSubimage(namepositions[j].x+offsets[j].x,namepositions[j].y+offsets[j].y,namepositions[j].width,namepositions[j].height),"png",new File("debug/img"+i+"_"+j+"_0.png"));
|
||||
//ImageIO.write(img.getSubimage(descriptions[j].x+offsets[j].x,descriptions[j].y+offsets[j].y,descriptions[j].width,descriptions[j].height),"png",new File("debug/img"+i+"_"+j+"_1.png"));
|
||||
//ImageIO.write(img.getSubimage(pointpositions[j].x+offsets[j].x,pointpositions[j].y+offsets[j].y,pointpositions[j].width,pointpositions[j].height),"png",new File("debug/img"+i+"_"+j+"_2.png"));
|
||||
String name = tesseract.doOCR(img,new Rectangle(namepositions[j].x+offsets[i].x,namepositions[j].y+offsets[i].y,namepositions[j].width,namepositions[j].height));
|
||||
String description = tesseract.doOCR(img,new Rectangle(descriptions[j].x+offsets[i].x,descriptions[j].y+offsets[i].y,descriptions[j].width,descriptions[j].height));
|
||||
tesseract.setLanguage("eng");
|
||||
String points = tesseract.doOCR(img,new Rectangle(pointpositions[j].x+offsets[i].x,pointpositions[j].y+offsets[i].y,pointpositions[j].width,pointpositions[j].height));
|
||||
|
||||
namedata[i][j]=name;
|
||||
descriptiondata[i][j]=description;
|
||||
pointdata[i][j]=points;
|
||||
}
|
||||
} catch (IOException | TesseractException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (File ff : list) {
|
||||
ff.delete();
|
||||
}
|
||||
|
||||
// Request parameters and other properties.
|
||||
for (int i=0;i<20;i++) {
|
||||
new Thread(
|
||||
new SubmitThread(namedata[i/4][i%4],descriptiondata[i/4][i%4],pointdata[i/4][i%4].replaceAll(" ","").replaceAll("\\.",""),7,i+1))
|
||||
.start();
|
||||
}
|
||||
} else {
|
||||
if (f.listFiles().length>5) {
|
||||
File[] list = f.listFiles();
|
||||
for (File ff : list) {
|
||||
ff.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*System.out.println(Arrays.deepToString(namedata));
|
||||
System.out.println(Arrays.deepToString(descriptiondata));
|
||||
System.out.println(Arrays.deepToString(pointdata));*/
|
||||
|
||||
|
||||
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
284
d4dj/src/main/java/org/json/CDL.java
Normal file
@ -0,0 +1,284 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This provides static methods to convert comma delimited text into a
|
||||
* JSONArray, and to convert a JSONArray into comma delimited text. Comma
|
||||
* delimited text is a very popular format for data interchange. It is
|
||||
* understood by most database, spreadsheet, and organizer programs.
|
||||
* <p>
|
||||
* Each row of text represents a row in a table or a data record. Each row
|
||||
* ends with a NEWLINE character. Each row contains one or more values.
|
||||
* Values are separated by commas. A value can contain any character except
|
||||
* for comma, unless is is wrapped in single quotes or double quotes.
|
||||
* <p>
|
||||
* The first row usually contains the names of the columns.
|
||||
* <p>
|
||||
* A comma delimited list can be converted into a JSONArray of JSONObjects.
|
||||
* The names for the elements in the JSONObjects can be taken from the names
|
||||
* in the first row.
|
||||
* @author JSON.org
|
||||
* @version 2016-05-01
|
||||
*/
|
||||
public class CDL {
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be wrapped in quotes. The value can
|
||||
* be empty.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @return The value string, or null if empty.
|
||||
* @throws JSONException if the quoted string is badly formed.
|
||||
*/
|
||||
private static String getValue(JSONTokener x) throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
StringBuffer sb;
|
||||
do {
|
||||
c = x.next();
|
||||
} while (c == ' ' || c == '\t');
|
||||
switch (c) {
|
||||
case 0:
|
||||
return null;
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
sb = new StringBuffer();
|
||||
for (;;) {
|
||||
c = x.next();
|
||||
if (c == q) {
|
||||
//Handle escaped double-quote
|
||||
if(x.next() != '\"')
|
||||
{
|
||||
x.back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == 0 || c == '\n' || c == '\r') {
|
||||
throw x.syntaxError("Missing close quote '" + q + "'.");
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
case ',':
|
||||
x.back();
|
||||
return "";
|
||||
default:
|
||||
x.back();
|
||||
return x.nextTo(',');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of strings from a row of comma delimited values.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @return A JSONArray of strings.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
|
||||
JSONArray ja = new JSONArray();
|
||||
for (;;) {
|
||||
String value = getValue(x);
|
||||
char c = x.next();
|
||||
if (value == null ||
|
||||
(ja.length() == 0 && value.length() == 0 && c != ',')) {
|
||||
return null;
|
||||
}
|
||||
ja.put(value);
|
||||
for (;;) {
|
||||
if (c == ',') {
|
||||
break;
|
||||
}
|
||||
if (c != ' ') {
|
||||
if (c == '\n' || c == '\r' || c == 0) {
|
||||
return ja;
|
||||
}
|
||||
throw x.syntaxError("Bad character '" + c + "' (" +
|
||||
(int)c + ").");
|
||||
}
|
||||
c = x.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONObject from a row of comma delimited text, using a
|
||||
* parallel JSONArray of strings to provides the names of the elements.
|
||||
* @param names A JSONArray of names. This is commonly obtained from the
|
||||
* first row of a comma delimited text file using the rowToJSONArray
|
||||
* method.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @return A JSONObject combining the names and values.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
|
||||
throws JSONException {
|
||||
JSONArray ja = rowToJSONArray(x);
|
||||
return ja != null ? ja.toJSONObject(names) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text row from a JSONArray. Values containing
|
||||
* the comma character will be quoted. Troublesome characters may be
|
||||
* removed.
|
||||
* @param ja A JSONArray of strings.
|
||||
* @return A string ending in NEWLINE.
|
||||
*/
|
||||
public static String rowToString(JSONArray ja) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < ja.length(); i += 1) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
Object object = ja.opt(i);
|
||||
if (object != null) {
|
||||
String string = object.toString();
|
||||
if (string.length() > 0 && (string.indexOf(',') >= 0 ||
|
||||
string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 ||
|
||||
string.indexOf(0) >= 0 || string.charAt(0) == '"')) {
|
||||
sb.append('"');
|
||||
int length = string.length();
|
||||
for (int j = 0; j < length; j += 1) {
|
||||
char c = string.charAt(j);
|
||||
if (c >= ' ' && c != '"') {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
} else {
|
||||
sb.append(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('\n');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string,
|
||||
* using the first row as a source of names.
|
||||
* @param string The comma delimited text.
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string) throws JSONException {
|
||||
return toJSONArray(new JSONTokener(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string,
|
||||
* using the first row as a source of names.
|
||||
* @param x The JSONTokener containing the comma delimited text.
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
|
||||
return toJSONArray(rowToJSONArray(x), x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string
|
||||
* using a supplied JSONArray as the source of element names.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param string The comma delimited text.
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, String string)
|
||||
throws JSONException {
|
||||
return toJSONArray(names, new JSONTokener(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string
|
||||
* using a supplied JSONArray as the source of element names.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
|
||||
throws JSONException {
|
||||
if (names == null || names.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
JSONArray ja = new JSONArray();
|
||||
for (;;) {
|
||||
JSONObject jo = rowToJSONObject(names, x);
|
||||
if (jo == null) {
|
||||
break;
|
||||
}
|
||||
ja.put(jo);
|
||||
}
|
||||
if (ja.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
return ja;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text from a JSONArray of JSONObjects. The
|
||||
* first row will be a list of names obtained by inspecting the first
|
||||
* JSONObject.
|
||||
* @param ja A JSONArray of JSONObjects.
|
||||
* @return A comma delimited text.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONArray ja) throws JSONException {
|
||||
JSONObject jo = ja.optJSONObject(0);
|
||||
if (jo != null) {
|
||||
JSONArray names = jo.names();
|
||||
if (names != null) {
|
||||
return rowToString(names) + toString(names, ja);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text from a JSONArray of JSONObjects using
|
||||
* a provided list of names. The list of names is not included in the
|
||||
* output.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param ja A JSONArray of JSONObjects.
|
||||
* @return A comma delimited text.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONArray names, JSONArray ja)
|
||||
throws JSONException {
|
||||
if (names == null || names.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < ja.length(); i += 1) {
|
||||
JSONObject jo = ja.optJSONObject(i);
|
||||
if (jo != null) {
|
||||
sb.append(rowToString(jo.toJSONArray(names)));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
169
d4dj/src/main/java/org/json/Cookie.java
Normal file
@ -0,0 +1,169 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert a web browser cookie specification to a JSONObject and back.
|
||||
* JSON and Cookies are both notations for name/value pairs.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class Cookie {
|
||||
|
||||
/**
|
||||
* Produce a copy of a string in which the characters '+', '%', '=', ';'
|
||||
* and control characters are replaced with "%hh". This is a gentle form
|
||||
* of URL encoding, attempting to cause as little distortion to the
|
||||
* string as possible. The characters '=' and ';' are meta characters in
|
||||
* cookies. By convention, they are escaped using the URL-encoding. This is
|
||||
* only a convention, not a standard. Often, cookies are expected to have
|
||||
* encoded values. We encode '=' and ';' because we must. We encode '%' and
|
||||
* '+' because they are meta characters in URL encoding.
|
||||
* @param string The source string.
|
||||
* @return The escaped result.
|
||||
*/
|
||||
public static String escape(String string) {
|
||||
char c;
|
||||
String s = string.trim();
|
||||
int length = s.length();
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
c = s.charAt(i);
|
||||
if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') {
|
||||
sb.append('%');
|
||||
sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16));
|
||||
sb.append(Character.forDigit((char)(c & 0x0f), 16));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a cookie specification string into a JSONObject. The string
|
||||
* will contain a name value pair separated by '='. The name and the value
|
||||
* will be unescaped, possibly converting '+' and '%' sequences. The
|
||||
* cookie properties may follow, separated by ';', also represented as
|
||||
* name=value (except the secure property, which does not have a value).
|
||||
* The name will be stored under the key "name", and the value will be
|
||||
* stored under the key "value". This method does not do checking or
|
||||
* validation of the parameters. It only converts the cookie string into
|
||||
* a JSONObject.
|
||||
* @param string The cookie specification string.
|
||||
* @return A JSONObject containing "name", "value", and possibly other
|
||||
* members.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
String name;
|
||||
JSONObject jo = new JSONObject();
|
||||
Object value;
|
||||
JSONTokener x = new JSONTokener(string);
|
||||
jo.put("name", x.nextTo('='));
|
||||
x.next('=');
|
||||
jo.put("value", x.nextTo(';'));
|
||||
x.next();
|
||||
while (x.more()) {
|
||||
name = unescape(x.nextTo("=;"));
|
||||
if (x.next() != '=') {
|
||||
if (name.equals("secure")) {
|
||||
value = Boolean.TRUE;
|
||||
} else {
|
||||
throw x.syntaxError("Missing '=' in cookie parameter.");
|
||||
}
|
||||
} else {
|
||||
value = unescape(x.nextTo(';'));
|
||||
x.next();
|
||||
}
|
||||
jo.put(name, value);
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into a cookie specification string. The JSONObject
|
||||
* must contain "name" and "value" members.
|
||||
* If the JSONObject contains "expires", "domain", "path", or "secure"
|
||||
* members, they will be appended to the cookie specification string.
|
||||
* All other members are ignored.
|
||||
* @param jo A JSONObject
|
||||
* @return A cookie specification string
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(escape(jo.getString("name")));
|
||||
sb.append("=");
|
||||
sb.append(escape(jo.getString("value")));
|
||||
if (jo.has("expires")) {
|
||||
sb.append(";expires=");
|
||||
sb.append(jo.getString("expires"));
|
||||
}
|
||||
if (jo.has("domain")) {
|
||||
sb.append(";domain=");
|
||||
sb.append(escape(jo.getString("domain")));
|
||||
}
|
||||
if (jo.has("path")) {
|
||||
sb.append(";path=");
|
||||
sb.append(escape(jo.getString("path")));
|
||||
}
|
||||
if (jo.optBoolean("secure")) {
|
||||
sb.append(";secure");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert <code>%</code><i>hh</i> sequences to single characters, and
|
||||
* convert plus to space.
|
||||
* @param string A string that may contain
|
||||
* <code>+</code> <small>(plus)</small> and
|
||||
* <code>%</code><i>hh</i> sequences.
|
||||
* @return The unescaped string.
|
||||
*/
|
||||
public static String unescape(String string) {
|
||||
int length = string.length();
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
char c = string.charAt(i);
|
||||
if (c == '+') {
|
||||
c = ' ';
|
||||
} else if (c == '%' && i + 2 < length) {
|
||||
int d = JSONTokener.dehexchar(string.charAt(i + 1));
|
||||
int e = JSONTokener.dehexchar(string.charAt(i + 2));
|
||||
if (d >= 0 && e >= 0) {
|
||||
c = (char)(d * 16 + e);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
89
d4dj/src/main/java/org/json/CookieList.java
Normal file
@ -0,0 +1,89 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Convert a web browser cookie list string to a JSONObject and back.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class CookieList {
|
||||
|
||||
/**
|
||||
* Convert a cookie list into a JSONObject. A cookie list is a sequence
|
||||
* of name/value pairs. The names are separated from the values by '='.
|
||||
* The pairs are separated by ';'. The names and the values
|
||||
* will be unescaped, possibly converting '+' and '%' sequences.
|
||||
*
|
||||
* To add a cookie to a cooklist,
|
||||
* cookielistJSONObject.put(cookieJSONObject.getString("name"),
|
||||
* cookieJSONObject.getString("value"));
|
||||
* @param string A cookie list string
|
||||
* @return A JSONObject
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
JSONTokener x = new JSONTokener(string);
|
||||
while (x.more()) {
|
||||
String name = Cookie.unescape(x.nextTo('='));
|
||||
x.next('=');
|
||||
jo.put(name, Cookie.unescape(x.nextTo(';')));
|
||||
x.next();
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into a cookie list. A cookie list is a sequence
|
||||
* of name/value pairs. The names are separated from the values by '='.
|
||||
* The pairs are separated by ';'. The characters '%', '+', '=', and ';'
|
||||
* in the names and values are replaced by "%hh".
|
||||
* @param jo A JSONObject
|
||||
* @return A cookie list string
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
boolean b = false;
|
||||
Iterator<String> keys = jo.keys();
|
||||
String string;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (keys.hasNext()) {
|
||||
string = keys.next();
|
||||
if (!jo.isNull(string)) {
|
||||
if (b) {
|
||||
sb.append(';');
|
||||
}
|
||||
sb.append(Cookie.escape(string));
|
||||
sb.append("=");
|
||||
sb.append(Cookie.escape(jo.getString(string)));
|
||||
b = true;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
164
d4dj/src/main/java/org/json/HTTP.java
Normal file
@ -0,0 +1,164 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Convert an HTTP header to a JSONObject and back.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class HTTP {
|
||||
|
||||
/** Carriage return/line feed. */
|
||||
public static final String CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* Convert an HTTP header string into a JSONObject. It can be a request
|
||||
* header or a response header. A request header will contain
|
||||
* <pre>{
|
||||
* Method: "POST" (for example),
|
||||
* "Request-URI": "/" (for example),
|
||||
* "HTTP-Version": "HTTP/1.1" (for example)
|
||||
* }</pre>
|
||||
* A response header will contain
|
||||
* <pre>{
|
||||
* "HTTP-Version": "HTTP/1.1" (for example),
|
||||
* "Status-Code": "200" (for example),
|
||||
* "Reason-Phrase": "OK" (for example)
|
||||
* }</pre>
|
||||
* In addition, the other parameters in the header will be captured, using
|
||||
* the HTTP field names as JSON names, so that <pre>
|
||||
* Date: Sun, 26 May 2002 18:06:04 GMT
|
||||
* Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
|
||||
* Cache-Control: no-cache</pre>
|
||||
* become
|
||||
* <pre>{...
|
||||
* Date: "Sun, 26 May 2002 18:06:04 GMT",
|
||||
* Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
|
||||
* "Cache-Control": "no-cache",
|
||||
* ...}</pre>
|
||||
* It does no further checking or conversion. It does not parse dates.
|
||||
* It does not do '%' transforms on URLs.
|
||||
* @param string An HTTP header string.
|
||||
* @return A JSONObject containing the elements and attributes
|
||||
* of the XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
HTTPTokener x = new HTTPTokener(string);
|
||||
String token;
|
||||
|
||||
token = x.nextToken();
|
||||
if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) {
|
||||
|
||||
// Response
|
||||
|
||||
jo.put("HTTP-Version", token);
|
||||
jo.put("Status-Code", x.nextToken());
|
||||
jo.put("Reason-Phrase", x.nextTo('\0'));
|
||||
x.next();
|
||||
|
||||
} else {
|
||||
|
||||
// Request
|
||||
|
||||
jo.put("Method", token);
|
||||
jo.put("Request-URI", x.nextToken());
|
||||
jo.put("HTTP-Version", x.nextToken());
|
||||
}
|
||||
|
||||
// Fields
|
||||
|
||||
while (x.more()) {
|
||||
String name = x.nextTo(':');
|
||||
x.next(':');
|
||||
jo.put(name, x.nextTo('\0'));
|
||||
x.next();
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into an HTTP header. A request header must contain
|
||||
* <pre>{
|
||||
* Method: "POST" (for example),
|
||||
* "Request-URI": "/" (for example),
|
||||
* "HTTP-Version": "HTTP/1.1" (for example)
|
||||
* }</pre>
|
||||
* A response header must contain
|
||||
* <pre>{
|
||||
* "HTTP-Version": "HTTP/1.1" (for example),
|
||||
* "Status-Code": "200" (for example),
|
||||
* "Reason-Phrase": "OK" (for example)
|
||||
* }</pre>
|
||||
* Any other members of the JSONObject will be output as HTTP fields.
|
||||
* The result will end with two CRLF pairs.
|
||||
* @param jo A JSONObject
|
||||
* @return An HTTP header string.
|
||||
* @throws JSONException if the object does not contain enough
|
||||
* information.
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
Iterator<String> keys = jo.keys();
|
||||
String string;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (jo.has("Status-Code") && jo.has("Reason-Phrase")) {
|
||||
sb.append(jo.getString("HTTP-Version"));
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("Status-Code"));
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("Reason-Phrase"));
|
||||
} else if (jo.has("Method") && jo.has("Request-URI")) {
|
||||
sb.append(jo.getString("Method"));
|
||||
sb.append(' ');
|
||||
sb.append('"');
|
||||
sb.append(jo.getString("Request-URI"));
|
||||
sb.append('"');
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("HTTP-Version"));
|
||||
} else {
|
||||
throw new JSONException("Not enough material for an HTTP header.");
|
||||
}
|
||||
sb.append(CRLF);
|
||||
while (keys.hasNext()) {
|
||||
string = keys.next();
|
||||
if (!"HTTP-Version".equals(string) && !"Status-Code".equals(string) &&
|
||||
!"Reason-Phrase".equals(string) && !"Method".equals(string) &&
|
||||
!"Request-URI".equals(string) && !jo.isNull(string)) {
|
||||
sb.append(string);
|
||||
sb.append(": ");
|
||||
sb.append(jo.getString(string));
|
||||
sb.append(CRLF);
|
||||
}
|
||||
}
|
||||
sb.append(CRLF);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
77
d4dj/src/main/java/org/json/HTTPTokener.java
Normal file
@ -0,0 +1,77 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The HTTPTokener extends the JSONTokener to provide additional methods
|
||||
* for the parsing of HTTP headers.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class HTTPTokener extends JSONTokener {
|
||||
|
||||
/**
|
||||
* Construct an HTTPTokener from a string.
|
||||
* @param string A source string.
|
||||
*/
|
||||
public HTTPTokener(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next token or string. This is used in parsing HTTP headers.
|
||||
* @throws JSONException
|
||||
* @return A String.
|
||||
*/
|
||||
public String nextToken() throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
if (c == '"' || c == '\'') {
|
||||
q = c;
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (c < ' ') {
|
||||
throw syntaxError("Unterminated string.");
|
||||
}
|
||||
if (c == q) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (c == 0 || Character.isWhitespace(c)) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
c = next();
|
||||
}
|
||||
}
|
||||
}
|
1200
d4dj/src/main/java/org/json/JSONArray.java
Normal file
45
d4dj/src/main/java/org/json/JSONException.java
Normal file
@ -0,0 +1,45 @@
|
||||
package org.json;
|
||||
|
||||
/**
|
||||
* The JSONException is thrown by the JSON.org classes when things are amiss.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class JSONException extends RuntimeException {
|
||||
/** Serialization ID */
|
||||
private static final long serialVersionUID = 0;
|
||||
|
||||
/**
|
||||
* Constructs a JSONException with an explanatory message.
|
||||
*
|
||||
* @param message
|
||||
* Detail about the reason for the exception.
|
||||
*/
|
||||
public JSONException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a JSONException with an explanatory message and cause.
|
||||
*
|
||||
* @param message
|
||||
* Detail about the reason for the exception.
|
||||
* @param cause
|
||||
* The cause.
|
||||
*/
|
||||
public JSONException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new JSONException with the specified cause.
|
||||
*
|
||||
* @param cause
|
||||
* The cause.
|
||||
*/
|
||||
public JSONException(final Throwable cause) {
|
||||
super(cause.getMessage(), cause);
|
||||
}
|
||||
|
||||
}
|
552
d4dj/src/main/java/org/json/JSONML.java
Normal file
@ -0,0 +1,552 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2008 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* This provides static methods to convert an XML text into a JSONArray or
|
||||
* JSONObject, and to covert a JSONArray or JSONObject into an XML text using
|
||||
* the JsonML transform.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2016-01-30
|
||||
*/
|
||||
public class JSONML {
|
||||
/**
|
||||
* Parse XML values and store them in a JSONArray.
|
||||
* @param x The XMLTokener containing the source string.
|
||||
* @param arrayForm true if array form, false if object form.
|
||||
* @param ja The JSONArray that is containing the current tag or null
|
||||
* if we are at the outermost level.
|
||||
* @param keepStrings Don't type-convert text nodes and attibute values
|
||||
* @return A JSONArray if the value is the outermost tag, otherwise null.
|
||||
* @throws JSONException
|
||||
*/
|
||||
private static Object parse(
|
||||
XMLTokener x,
|
||||
boolean arrayForm,
|
||||
JSONArray ja,
|
||||
boolean keepStrings
|
||||
) throws JSONException {
|
||||
String attribute;
|
||||
char c;
|
||||
String closeTag = null;
|
||||
int i;
|
||||
JSONArray newja = null;
|
||||
JSONObject newjo = null;
|
||||
Object token;
|
||||
String tagName = null;
|
||||
|
||||
// Test for and skip past these forms:
|
||||
// <!-- ... -->
|
||||
// <![ ... ]]>
|
||||
// <! ... >
|
||||
// <? ... ?>
|
||||
|
||||
while (true) {
|
||||
if (!x.more()) {
|
||||
throw x.syntaxError("Bad XML");
|
||||
}
|
||||
token = x.nextContent();
|
||||
if (token == XML.LT) {
|
||||
token = x.nextToken();
|
||||
if (token instanceof Character) {
|
||||
if (token == XML.SLASH) {
|
||||
|
||||
// Close tag </
|
||||
|
||||
token = x.nextToken();
|
||||
if (!(token instanceof String)) {
|
||||
throw new JSONException(
|
||||
"Expected a closing name instead of '" +
|
||||
token + "'.");
|
||||
}
|
||||
if (x.nextToken() != XML.GT) {
|
||||
throw x.syntaxError("Misshaped close tag");
|
||||
}
|
||||
return token;
|
||||
} else if (token == XML.BANG) {
|
||||
|
||||
// <!
|
||||
|
||||
c = x.next();
|
||||
if (c == '-') {
|
||||
if (x.next() == '-') {
|
||||
x.skipPast("-->");
|
||||
} else {
|
||||
x.back();
|
||||
}
|
||||
} else if (c == '[') {
|
||||
token = x.nextToken();
|
||||
if (token.equals("CDATA") && x.next() == '[') {
|
||||
if (ja != null) {
|
||||
ja.put(x.nextCDATA());
|
||||
}
|
||||
} else {
|
||||
throw x.syntaxError("Expected 'CDATA['");
|
||||
}
|
||||
} else {
|
||||
i = 1;
|
||||
do {
|
||||
token = x.nextMeta();
|
||||
if (token == null) {
|
||||
throw x.syntaxError("Missing '>' after '<!'.");
|
||||
} else if (token == XML.LT) {
|
||||
i += 1;
|
||||
} else if (token == XML.GT) {
|
||||
i -= 1;
|
||||
}
|
||||
} while (i > 0);
|
||||
}
|
||||
} else if (token == XML.QUEST) {
|
||||
|
||||
// <?
|
||||
|
||||
x.skipPast("?>");
|
||||
} else {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
|
||||
// Open tag <
|
||||
|
||||
} else {
|
||||
if (!(token instanceof String)) {
|
||||
throw x.syntaxError("Bad tagName '" + token + "'.");
|
||||
}
|
||||
tagName = (String)token;
|
||||
newja = new JSONArray();
|
||||
newjo = new JSONObject();
|
||||
if (arrayForm) {
|
||||
newja.put(tagName);
|
||||
if (ja != null) {
|
||||
ja.put(newja);
|
||||
}
|
||||
} else {
|
||||
newjo.put("tagName", tagName);
|
||||
if (ja != null) {
|
||||
ja.put(newjo);
|
||||
}
|
||||
}
|
||||
token = null;
|
||||
for (;;) {
|
||||
if (token == null) {
|
||||
token = x.nextToken();
|
||||
}
|
||||
if (token == null) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if (!(token instanceof String)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// attribute = value
|
||||
|
||||
attribute = (String)token;
|
||||
if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {
|
||||
throw x.syntaxError("Reserved attribute.");
|
||||
}
|
||||
token = x.nextToken();
|
||||
if (token == XML.EQ) {
|
||||
token = x.nextToken();
|
||||
if (!(token instanceof String)) {
|
||||
throw x.syntaxError("Missing value");
|
||||
}
|
||||
newjo.accumulate(attribute, keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token));
|
||||
token = null;
|
||||
} else {
|
||||
newjo.accumulate(attribute, "");
|
||||
}
|
||||
}
|
||||
if (arrayForm && newjo.length() > 0) {
|
||||
newja.put(newjo);
|
||||
}
|
||||
|
||||
// Empty tag <.../>
|
||||
|
||||
if (token == XML.SLASH) {
|
||||
if (x.nextToken() != XML.GT) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if (ja == null) {
|
||||
if (arrayForm) {
|
||||
return newja;
|
||||
}
|
||||
return newjo;
|
||||
}
|
||||
|
||||
// Content, between <...> and </...>
|
||||
|
||||
} else {
|
||||
if (token != XML.GT) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
closeTag = (String)parse(x, arrayForm, newja, keepStrings);
|
||||
if (closeTag != null) {
|
||||
if (!closeTag.equals(tagName)) {
|
||||
throw x.syntaxError("Mismatched '" + tagName +
|
||||
"' and '" + closeTag + "'");
|
||||
}
|
||||
tagName = null;
|
||||
if (!arrayForm && newja.length() > 0) {
|
||||
newjo.put("childNodes", newja);
|
||||
}
|
||||
if (ja == null) {
|
||||
if (arrayForm) {
|
||||
return newja;
|
||||
}
|
||||
return newjo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ja != null) {
|
||||
ja.put(token instanceof String
|
||||
? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token)
|
||||
: token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child tags.
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param string The source string.
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONArray
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string) throws JSONException {
|
||||
return (JSONArray)parse(new XMLTokener(string), true, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child tags.
|
||||
* As opposed to toJSONArray this method does not attempt to convert
|
||||
* any text node or attribute value to any type
|
||||
* but just leaves it as a string.
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param string The source string.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONArray
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException {
|
||||
return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child content and tags.
|
||||
* As opposed to toJSONArray this method does not attempt to convert
|
||||
* any text node or attribute value to any type
|
||||
* but just leaves it as a string.
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param x An XMLTokener.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONArray
|
||||
*/
|
||||
public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException {
|
||||
return (JSONArray)parse(x, true, null, keepStrings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child content and tags.
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param x An XMLTokener.
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONArray
|
||||
*/
|
||||
public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
|
||||
return (JSONArray)parse(x, true, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then
|
||||
* the attributes will be in the JSONObject as properties. If the tag
|
||||
* contains children, the object will have a "childNodes" property which
|
||||
* will be an array of strings and JsonML JSONObjects.
|
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param string The XML source text.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONObject
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
return (JSONObject)parse(new XMLTokener(string), false, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then
|
||||
* the attributes will be in the JSONObject as properties. If the tag
|
||||
* contains children, the object will have a "childNodes" property which
|
||||
* will be an array of strings and JsonML JSONObjects.
|
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param string The XML source text.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONObject
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
|
||||
return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then
|
||||
* the attributes will be in the JSONObject as properties. If the tag
|
||||
* contains children, the object will have a "childNodes" property which
|
||||
* will be an array of strings and JsonML JSONObjects.
|
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param x An XMLTokener of the XML source text.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONObject
|
||||
*/
|
||||
public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
|
||||
return (JSONObject)parse(x, false, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then
|
||||
* the attributes will be in the JSONObject as properties. If the tag
|
||||
* contains children, the object will have a "childNodes" property which
|
||||
* will be an array of strings and JsonML JSONObjects.
|
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param x An XMLTokener of the XML source text.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONObject
|
||||
*/
|
||||
public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException {
|
||||
return (JSONObject)parse(x, false, null, keepStrings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the JSONML transformation, making an XML text from a JSONArray.
|
||||
* @param ja A JSONArray.
|
||||
* @return An XML string.
|
||||
* @throws JSONException Thrown on error converting to a string
|
||||
*/
|
||||
public static String toString(JSONArray ja) throws JSONException {
|
||||
int i;
|
||||
JSONObject jo;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
int length;
|
||||
Object object;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String tagName;
|
||||
String value;
|
||||
|
||||
// Emit <tagName
|
||||
|
||||
tagName = ja.getString(0);
|
||||
XML.noSpace(tagName);
|
||||
tagName = XML.escape(tagName);
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
|
||||
object = ja.opt(1);
|
||||
if (object instanceof JSONObject) {
|
||||
i = 2;
|
||||
jo = (JSONObject)object;
|
||||
|
||||
// Emit the attributes
|
||||
|
||||
keys = jo.keys();
|
||||
while (keys.hasNext()) {
|
||||
key = keys.next();
|
||||
XML.noSpace(key);
|
||||
value = jo.optString(key);
|
||||
if (value != null) {
|
||||
sb.append(' ');
|
||||
sb.append(XML.escape(key));
|
||||
sb.append('=');
|
||||
sb.append('"');
|
||||
sb.append(XML.escape(value));
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i = 1;
|
||||
}
|
||||
|
||||
// Emit content in body
|
||||
|
||||
length = ja.length();
|
||||
if (i >= length) {
|
||||
sb.append('/');
|
||||
sb.append('>');
|
||||
} else {
|
||||
sb.append('>');
|
||||
do {
|
||||
object = ja.get(i);
|
||||
i += 1;
|
||||
if (object != null) {
|
||||
if (object instanceof String) {
|
||||
sb.append(XML.escape(object.toString()));
|
||||
} else if (object instanceof JSONObject) {
|
||||
sb.append(toString((JSONObject)object));
|
||||
} else if (object instanceof JSONArray) {
|
||||
sb.append(toString((JSONArray)object));
|
||||
} else {
|
||||
sb.append(object.toString());
|
||||
}
|
||||
}
|
||||
} while (i < length);
|
||||
sb.append('<');
|
||||
sb.append('/');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the JSONML transformation, making an XML text from a JSONObject.
|
||||
* The JSONObject must contain a "tagName" property. If it has children,
|
||||
* then it must have a "childNodes" property containing an array of objects.
|
||||
* The other properties are attributes with string values.
|
||||
* @param jo A JSONObject.
|
||||
* @return An XML string.
|
||||
* @throws JSONException Thrown on error converting to a string
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i;
|
||||
JSONArray ja;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
int length;
|
||||
Object object;
|
||||
String tagName;
|
||||
String value;
|
||||
|
||||
//Emit <tagName
|
||||
|
||||
tagName = jo.optString("tagName");
|
||||
if (tagName == null) {
|
||||
return XML.escape(jo.toString());
|
||||
}
|
||||
XML.noSpace(tagName);
|
||||
tagName = XML.escape(tagName);
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
|
||||
//Emit the attributes
|
||||
|
||||
keys = jo.keys();
|
||||
while (keys.hasNext()) {
|
||||
key = keys.next();
|
||||
if (!"tagName".equals(key) && !"childNodes".equals(key)) {
|
||||
XML.noSpace(key);
|
||||
value = jo.optString(key);
|
||||
if (value != null) {
|
||||
sb.append(' ');
|
||||
sb.append(XML.escape(key));
|
||||
sb.append('=');
|
||||
sb.append('"');
|
||||
sb.append(XML.escape(value));
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Emit content in body
|
||||
|
||||
ja = jo.optJSONArray("childNodes");
|
||||
if (ja == null) {
|
||||
sb.append('/');
|
||||
sb.append('>');
|
||||
} else {
|
||||
sb.append('>');
|
||||
length = ja.length();
|
||||
for (i = 0; i < length; i += 1) {
|
||||
object = ja.get(i);
|
||||
if (object != null) {
|
||||
if (object instanceof String) {
|
||||
sb.append(XML.escape(object.toString()));
|
||||
} else if (object instanceof JSONObject) {
|
||||
sb.append(toString((JSONObject)object));
|
||||
} else if (object instanceof JSONArray) {
|
||||
sb.append(toString((JSONArray)object));
|
||||
} else {
|
||||
sb.append(object.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('<');
|
||||
sb.append('/');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
1938
d4dj/src/main/java/org/json/JSONObject.java
Normal file
267
d4dj/src/main/java/org/json/JSONPointer.java
Normal file
@ -0,0 +1,267 @@
|
||||
package org.json;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A JSON Pointer is a simple query language defined for JSON documents by
|
||||
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
|
||||
*
|
||||
* In a nutshell, JSONPointer allows the user to navigate into a JSON document
|
||||
* using strings, and retrieve targeted objects, like a simple form of XPATH.
|
||||
* Path segments are separated by the '/' char, which signifies the root of
|
||||
* the document when it appears as the first char of the string. Array
|
||||
* elements are navigated using ordinals, counting from 0. JSONPointer strings
|
||||
* may be extended to any arbitrary number of segments. If the navigation
|
||||
* is successful, the matched item is returned. A matched item may be a
|
||||
* JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building
|
||||
* fails, an appropriate exception is thrown. If the navigation fails to find
|
||||
* a match, a JSONPointerException is thrown.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2016-05-14
|
||||
*/
|
||||
public class JSONPointer {
|
||||
|
||||
// used for URL encoding and decoding
|
||||
private static final String ENCODING = "utf-8";
|
||||
|
||||
/**
|
||||
* This class allows the user to build a JSONPointer in steps, using
|
||||
* exactly one segment in each step.
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
// Segments for the eventual JSONPointer string
|
||||
private final List<String> refTokens = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Creates a {@code JSONPointer} instance using the tokens previously set using the
|
||||
* {@link #append(String)} method calls.
|
||||
*/
|
||||
public JSONPointer build() {
|
||||
return new JSONPointer(refTokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an arbitary token to the list of reference tokens. It can be any non-null value.
|
||||
*
|
||||
* Unlike in the case of JSON string or URI fragment representation of JSON pointers, the
|
||||
* argument of this method MUST NOT be escaped. If you want to query the property called
|
||||
* {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no
|
||||
* need to escape it as {@code "a~0b"}.
|
||||
*
|
||||
* @param token the new token to be appended to the list
|
||||
* @return {@code this}
|
||||
* @throws NullPointerException if {@code token} is null
|
||||
*/
|
||||
public Builder append(String token) {
|
||||
if (token == null) {
|
||||
throw new NullPointerException("token cannot be null");
|
||||
}
|
||||
refTokens.add(token);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an integer to the reference token list. Although not necessarily, mostly this token will
|
||||
* denote an array index.
|
||||
*
|
||||
* @param arrayIndex the array index to be added to the token list
|
||||
* @return {@code this}
|
||||
*/
|
||||
public Builder append(int arrayIndex) {
|
||||
refTokens.add(String.valueOf(arrayIndex));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method for {@link Builder}. Example usage:
|
||||
*
|
||||
* <pre><code>
|
||||
* JSONPointer pointer = JSONPointer.builder()
|
||||
* .append("obj")
|
||||
* .append("other~key").append("another/key")
|
||||
* .append("\"")
|
||||
* .append(0)
|
||||
* .build();
|
||||
* </code></pre>
|
||||
*
|
||||
* @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained
|
||||
* {@link Builder#append(String)} calls.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
// Segments for the JSONPointer string
|
||||
private final List<String> refTokens;
|
||||
|
||||
/**
|
||||
* Pre-parses and initializes a new {@code JSONPointer} instance. If you want to
|
||||
* evaluate the same JSON Pointer on different JSON documents then it is recommended
|
||||
* to keep the {@code JSONPointer} instances due to performance considerations.
|
||||
*
|
||||
* @param pointer the JSON String or URI Fragment representation of the JSON pointer.
|
||||
* @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer
|
||||
*/
|
||||
public JSONPointer(String pointer) {
|
||||
if (pointer == null) {
|
||||
throw new NullPointerException("pointer cannot be null");
|
||||
}
|
||||
if (pointer.isEmpty() || pointer.equals("#")) {
|
||||
refTokens = Collections.emptyList();
|
||||
return;
|
||||
}
|
||||
if (pointer.startsWith("#/")) {
|
||||
pointer = pointer.substring(2);
|
||||
try {
|
||||
pointer = URLDecoder.decode(pointer, ENCODING);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else if (pointer.startsWith("/")) {
|
||||
pointer = pointer.substring(1);
|
||||
} else {
|
||||
throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'");
|
||||
}
|
||||
refTokens = new ArrayList<String>();
|
||||
for (String token : pointer.split("/")) {
|
||||
refTokens.add(unescape(token));
|
||||
}
|
||||
}
|
||||
|
||||
public JSONPointer(List<String> refTokens) {
|
||||
this.refTokens = new ArrayList<String>(refTokens);
|
||||
}
|
||||
|
||||
private String unescape(String token) {
|
||||
return token.replace("~1", "/").replace("~0", "~")
|
||||
.replace("\\\"", "\"")
|
||||
.replace("\\\\", "\\");
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates this JSON Pointer on the given {@code document}. The {@code document}
|
||||
* is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty
|
||||
* JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the
|
||||
* returned value will be {@code document} itself.
|
||||
*
|
||||
* @param document the JSON document which should be the subject of querying.
|
||||
* @return the result of the evaluation
|
||||
* @throws JSONPointerException if an error occurs during evaluation
|
||||
*/
|
||||
public Object queryFrom(Object document) {
|
||||
if (refTokens.isEmpty()) {
|
||||
return document;
|
||||
}
|
||||
Object current = document;
|
||||
for (String token : refTokens) {
|
||||
if (current instanceof JSONObject) {
|
||||
current = ((JSONObject) current).opt(unescape(token));
|
||||
} else if (current instanceof JSONArray) {
|
||||
current = readByIndexToken(current, token);
|
||||
} else {
|
||||
throw new JSONPointerException(format(
|
||||
"value [%s] is not an array or object therefore its key %s cannot be resolved", current,
|
||||
token));
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a JSONArray element by ordinal position
|
||||
* @param current the JSONArray to be evaluated
|
||||
* @param indexToken the array index in string form
|
||||
* @return the matched object. If no matching item is found a
|
||||
* JSONPointerException is thrown
|
||||
*/
|
||||
private Object readByIndexToken(Object current, String indexToken) {
|
||||
try {
|
||||
int index = Integer.parseInt(indexToken);
|
||||
JSONArray currentArr = (JSONArray) current;
|
||||
if (index >= currentArr.length()) {
|
||||
throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index,
|
||||
currentArr.length()));
|
||||
}
|
||||
return currentArr.get(index);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JSONPointerException(format("%s is not an array index", indexToken), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the JSONPointer path value using string
|
||||
* representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder rval = new StringBuilder("");
|
||||
for (String token: refTokens) {
|
||||
rval.append('/').append(escape(token));
|
||||
}
|
||||
return rval.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes path segment values to an unambiguous form.
|
||||
* The escape char to be inserted is '~'. The chars to be escaped
|
||||
* are ~, which maps to ~0, and /, which maps to ~1. Backslashes
|
||||
* and double quote chars are also escaped.
|
||||
* @param token the JSONPointer segment value to be escaped
|
||||
* @return the escaped value for the token
|
||||
*/
|
||||
private String escape(String token) {
|
||||
return token.replace("~", "~0")
|
||||
.replace("/", "~1")
|
||||
.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the JSONPointer path value using URI
|
||||
* fragment identifier representation
|
||||
*/
|
||||
public String toURIFragment() {
|
||||
try {
|
||||
StringBuilder rval = new StringBuilder("#");
|
||||
for (String token : refTokens) {
|
||||
rval.append('/').append(URLEncoder.encode(token, ENCODING));
|
||||
}
|
||||
return rval.toString();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
45
d4dj/src/main/java/org/json/JSONPointerException.java
Normal file
@ -0,0 +1,45 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The JSONPointerException is thrown by {@link JSONPointer} if an error occurs
|
||||
* during evaluating a pointer.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2016-05-13
|
||||
*/
|
||||
public class JSONPointerException extends JSONException {
|
||||
private static final long serialVersionUID = 8872944667561856751L;
|
||||
|
||||
public JSONPointerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JSONPointerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
18
d4dj/src/main/java/org/json/JSONString.java
Normal file
@ -0,0 +1,18 @@
|
||||
package org.json;
|
||||
/**
|
||||
* The <code>JSONString</code> interface allows a <code>toJSONString()</code>
|
||||
* method so that a class can change the behavior of
|
||||
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
|
||||
* and <code>JSONWriter.value(</code>Object<code>)</code>. The
|
||||
* <code>toJSONString</code> method will be used instead of the default behavior
|
||||
* of using the Object's <code>toString()</code> method and quoting the result.
|
||||
*/
|
||||
public interface JSONString {
|
||||
/**
|
||||
* The <code>toJSONString</code> method allows a class to produce its own JSON
|
||||
* serialization.
|
||||
*
|
||||
* @return A strictly syntactically correct JSON text.
|
||||
*/
|
||||
public String toJSONString();
|
||||
}
|
78
d4dj/src/main/java/org/json/JSONStringer.java
Normal file
@ -0,0 +1,78 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* JSONStringer provides a quick and convenient way of producing JSON text.
|
||||
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||
* added, so the results are ready for transmission or storage. Each instance of
|
||||
* JSONStringer can produce one JSON text.
|
||||
* <p>
|
||||
* A JSONStringer instance provides a <code>value</code> method for appending
|
||||
* values to the
|
||||
* text, and a <code>key</code>
|
||||
* method for adding keys before values in objects. There are <code>array</code>
|
||||
* and <code>endArray</code> methods that make and bound array values, and
|
||||
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||
* object values. All of these methods return the JSONWriter instance,
|
||||
* permitting cascade style. For example, <pre>
|
||||
* myString = new JSONStringer()
|
||||
* .object()
|
||||
* .key("JSON")
|
||||
* .value("Hello, World!")
|
||||
* .endObject()
|
||||
* .toString();</pre> which produces the string <pre>
|
||||
* {"JSON":"Hello, World!"}</pre>
|
||||
* <p>
|
||||
* The first method called must be <code>array</code> or <code>object</code>.
|
||||
* There are no methods for adding commas or colons. JSONStringer adds them for
|
||||
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||
* <p>
|
||||
* This can sometimes be easier than using a JSONObject to build a string.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class JSONStringer extends JSONWriter {
|
||||
/**
|
||||
* Make a fresh JSONStringer. It can be used to build one JSON text.
|
||||
*/
|
||||
public JSONStringer() {
|
||||
super(new StringWriter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON text. This method is used to obtain the product of the
|
||||
* JSONStringer instance. It will return <code>null</code> if there was a
|
||||
* problem in the construction of the JSON text (such as the calls to
|
||||
* <code>array</code> were not properly balanced with calls to
|
||||
* <code>endArray</code>).
|
||||
* @return The JSON text.
|
||||
*/
|
||||
public String toString() {
|
||||
return this.mode == 'd' ? this.writer.toString() : null;
|
||||
}
|
||||
}
|
475
d4dj/src/main/java/org/json/JSONTokener.java
Normal file
@ -0,0 +1,475 @@
|
||||
package org.json;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A JSONTokener takes a source string and extracts characters and tokens from
|
||||
* it. It is used by the JSONObject and JSONArray constructors to parse
|
||||
* JSON source strings.
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class JSONTokener {
|
||||
|
||||
private long character;
|
||||
private boolean eof;
|
||||
private long index;
|
||||
private long line;
|
||||
private char previous;
|
||||
private Reader reader;
|
||||
private boolean usePrevious;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a Reader.
|
||||
*
|
||||
* @param reader A reader.
|
||||
*/
|
||||
public JSONTokener(Reader reader) {
|
||||
this.reader = reader.markSupported()
|
||||
? reader
|
||||
: new BufferedReader(reader);
|
||||
this.eof = false;
|
||||
this.usePrevious = false;
|
||||
this.previous = 0;
|
||||
this.index = 0;
|
||||
this.character = 1;
|
||||
this.line = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from an InputStream.
|
||||
* @param inputStream The source.
|
||||
*/
|
||||
public JSONTokener(InputStream inputStream) {
|
||||
this(new InputStreamReader(inputStream));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a string.
|
||||
*
|
||||
* @param s A source string.
|
||||
*/
|
||||
public JSONTokener(String s) {
|
||||
this(new StringReader(s));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Back up one character. This provides a sort of lookahead capability,
|
||||
* so that you can test for a digit or letter before attempting to parse
|
||||
* the next number or identifier.
|
||||
* @throws JSONException Thrown if trying to step back more than 1 step
|
||||
* or if already at the start of the string
|
||||
*/
|
||||
public void back() throws JSONException {
|
||||
if (this.usePrevious || this.index <= 0) {
|
||||
throw new JSONException("Stepping back two steps is not supported");
|
||||
}
|
||||
this.index -= 1;
|
||||
this.character -= 1;
|
||||
this.usePrevious = true;
|
||||
this.eof = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the hex value of a character (base16).
|
||||
* @param c A character between '0' and '9' or between 'A' and 'F' or
|
||||
* between 'a' and 'f'.
|
||||
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
||||
*/
|
||||
public static int dehexchar(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - ('A' - 10);
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - ('a' - 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if at the end of the file and we didn't step back
|
||||
*/
|
||||
public boolean end() {
|
||||
return this.eof && !this.usePrevious;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the source string still contains characters that next()
|
||||
* can consume.
|
||||
* @return true if not yet at the end of the source.
|
||||
* @throws JSONException thrown if there is an error stepping forward
|
||||
* or backward while checking for more data.
|
||||
*/
|
||||
public boolean more() throws JSONException {
|
||||
this.next();
|
||||
if (this.end()) {
|
||||
return false;
|
||||
}
|
||||
this.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next character in the source string.
|
||||
*
|
||||
* @return The next character, or 0 if past the end of the source string.
|
||||
* @throws JSONException Thrown if there is an error reading the source string.
|
||||
*/
|
||||
public char next() throws JSONException {
|
||||
int c;
|
||||
if (this.usePrevious) {
|
||||
this.usePrevious = false;
|
||||
c = this.previous;
|
||||
} else {
|
||||
try {
|
||||
c = this.reader.read();
|
||||
} catch (IOException exception) {
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
|
||||
if (c <= 0) { // End of stream
|
||||
this.eof = true;
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
this.index += 1;
|
||||
if (this.previous == '\r') {
|
||||
this.line += 1;
|
||||
this.character = c == '\n' ? 0 : 1;
|
||||
} else if (c == '\n') {
|
||||
this.line += 1;
|
||||
this.character = 0;
|
||||
} else {
|
||||
this.character += 1;
|
||||
}
|
||||
this.previous = (char) c;
|
||||
return this.previous;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consume the next character, and check that it matches a specified
|
||||
* character.
|
||||
* @param c The character to match.
|
||||
* @return The character.
|
||||
* @throws JSONException if the character does not match.
|
||||
*/
|
||||
public char next(char c) throws JSONException {
|
||||
char n = this.next();
|
||||
if (n != c) {
|
||||
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
|
||||
n + "'");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next n characters.
|
||||
*
|
||||
* @param n The number of characters to take.
|
||||
* @return A string of n characters.
|
||||
* @throws JSONException
|
||||
* Substring bounds error if there are not
|
||||
* n characters remaining in the source string.
|
||||
*/
|
||||
public String next(int n) throws JSONException {
|
||||
if (n == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char[] chars = new char[n];
|
||||
int pos = 0;
|
||||
|
||||
while (pos < n) {
|
||||
chars[pos] = this.next();
|
||||
if (this.end()) {
|
||||
throw this.syntaxError("Substring bounds error");
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next char in the string, skipping whitespace.
|
||||
* @throws JSONException Thrown if there is an error reading the source string.
|
||||
* @return A character, or 0 if there are no more characters.
|
||||
*/
|
||||
public char nextClean() throws JSONException {
|
||||
for (;;) {
|
||||
char c = this.next();
|
||||
if (c == 0 || c > ' ') {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the characters up to the next close quote character.
|
||||
* Backslash processing is done. The formal JSON format does not
|
||||
* allow strings in single quotes, but an implementation is allowed to
|
||||
* accept them.
|
||||
* @param quote The quoting character, either
|
||||
* <code>"</code> <small>(double quote)</small> or
|
||||
* <code>'</code> <small>(single quote)</small>.
|
||||
* @return A String.
|
||||
* @throws JSONException Unterminated string.
|
||||
*/
|
||||
public String nextString(char quote) throws JSONException {
|
||||
char c;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
case 0:
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw this.syntaxError("Unterminated string");
|
||||
case '\\':
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
case 'b':
|
||||
sb.append('\b');
|
||||
break;
|
||||
case 't':
|
||||
sb.append('\t');
|
||||
break;
|
||||
case 'n':
|
||||
sb.append('\n');
|
||||
break;
|
||||
case 'f':
|
||||
sb.append('\f');
|
||||
break;
|
||||
case 'r':
|
||||
sb.append('\r');
|
||||
break;
|
||||
case 'u':
|
||||
try {
|
||||
sb.append((char)Integer.parseInt(this.next(4), 16));
|
||||
} catch (NumberFormatException e) {
|
||||
throw this.syntaxError("Illegal escape.", e);
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '/':
|
||||
sb.append(c);
|
||||
break;
|
||||
default:
|
||||
throw this.syntaxError("Illegal escape.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (c == quote) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the text up but not including the specified character or the
|
||||
* end of line, whichever comes first.
|
||||
* @param delimiter A delimiter character.
|
||||
* @return A string.
|
||||
* @throws JSONException Thrown if there is an error while searching
|
||||
* for the delimiter
|
||||
*/
|
||||
public String nextTo(char delimiter) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
char c = this.next();
|
||||
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the text up but not including one of the specified delimiter
|
||||
* characters or the end of line, whichever comes first.
|
||||
* @param delimiters A set of delimiter characters.
|
||||
* @return A string, trimmed.
|
||||
* @throws JSONException Thrown if there is an error while searching
|
||||
* for the delimiter
|
||||
*/
|
||||
public String nextTo(String delimiters) throws JSONException {
|
||||
char c;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = this.next();
|
||||
if (delimiters.indexOf(c) >= 0 || c == 0 ||
|
||||
c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be a Boolean, Double, Integer,
|
||||
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||
* @throws JSONException If syntax error.
|
||||
*
|
||||
* @return An object.
|
||||
*/
|
||||
public Object nextValue() throws JSONException {
|
||||
char c = this.nextClean();
|
||||
String string;
|
||||
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\'':
|
||||
return this.nextString(c);
|
||||
case '{':
|
||||
this.back();
|
||||
return new JSONObject(this);
|
||||
case '[':
|
||||
this.back();
|
||||
return new JSONArray(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle unquoted text. This could be the values true, false, or
|
||||
* null, or it can be a number. An implementation (such as this one)
|
||||
* is allowed to also accept non-standard forms.
|
||||
*
|
||||
* Accumulate characters until we reach the end of the text or a
|
||||
* formatting character.
|
||||
*/
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
|
||||
sb.append(c);
|
||||
c = this.next();
|
||||
}
|
||||
this.back();
|
||||
|
||||
string = sb.toString().trim();
|
||||
if ("".equals(string)) {
|
||||
throw this.syntaxError("Missing value");
|
||||
}
|
||||
return JSONObject.stringToValue(string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skip characters until the next character is the requested character.
|
||||
* If the requested character is not found, no characters are skipped.
|
||||
* @param to A character to skip to.
|
||||
* @return The requested character, or zero if the requested character
|
||||
* is not found.
|
||||
* @throws JSONException Thrown if there is an error while searching
|
||||
* for the to character
|
||||
*/
|
||||
public char skipTo(char to) throws JSONException {
|
||||
char c;
|
||||
try {
|
||||
long startIndex = this.index;
|
||||
long startCharacter = this.character;
|
||||
long startLine = this.line;
|
||||
this.reader.mark(1000000);
|
||||
do {
|
||||
c = this.next();
|
||||
if (c == 0) {
|
||||
this.reader.reset();
|
||||
this.index = startIndex;
|
||||
this.character = startCharacter;
|
||||
this.line = startLine;
|
||||
return c;
|
||||
}
|
||||
} while (c != to);
|
||||
} catch (IOException exception) {
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
this.back();
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a JSONException to signal a syntax error.
|
||||
*
|
||||
* @param message The error message.
|
||||
* @return A JSONException object, suitable for throwing
|
||||
*/
|
||||
public JSONException syntaxError(String message) {
|
||||
return new JSONException(message + this.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a JSONException to signal a syntax error.
|
||||
*
|
||||
* @param message The error message.
|
||||
* @param causedBy The throwable that caused the error.
|
||||
* @return A JSONException object, suitable for throwing
|
||||
*/
|
||||
public JSONException syntaxError(String message, Throwable causedBy) {
|
||||
return new JSONException(message + this.toString(), causedBy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a printable string of this JSONTokener.
|
||||
*
|
||||
* @return " at {index} [character {character} line {line}]"
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return " at " + this.index + " [character " + this.character + " line " +
|
||||
this.line + "]";
|
||||
}
|
||||
}
|
326
d4dj/src/main/java/org/json/JSONWriter.java
Normal file
@ -0,0 +1,326 @@
|
||||
package org.json;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JSONWriter provides a quick and convenient way of producing JSON text.
|
||||
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||
* added, so the results are ready for transmission or storage. Each instance of
|
||||
* JSONWriter can produce one JSON text.
|
||||
* <p>
|
||||
* A JSONWriter instance provides a <code>value</code> method for appending
|
||||
* values to the
|
||||
* text, and a <code>key</code>
|
||||
* method for adding keys before values in objects. There are <code>array</code>
|
||||
* and <code>endArray</code> methods that make and bound array values, and
|
||||
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||
* object values. All of these methods return the JSONWriter instance,
|
||||
* permitting a cascade style. For example, <pre>
|
||||
* new JSONWriter(myWriter)
|
||||
* .object()
|
||||
* .key("JSON")
|
||||
* .value("Hello, World!")
|
||||
* .endObject();</pre> which writes <pre>
|
||||
* {"JSON":"Hello, World!"}</pre>
|
||||
* <p>
|
||||
* The first method called must be <code>array</code> or <code>object</code>.
|
||||
* There are no methods for adding commas or colons. JSONWriter adds them for
|
||||
* you. Objects and arrays can be nested up to 200 levels deep.
|
||||
* <p>
|
||||
* This can sometimes be easier than using a JSONObject to build a string.
|
||||
* @author JSON.org
|
||||
* @version 2016-08-08
|
||||
*/
|
||||
public class JSONWriter {
|
||||
private static final int maxdepth = 200;
|
||||
|
||||
/**
|
||||
* The comma flag determines if a comma should be output before the next
|
||||
* value.
|
||||
*/
|
||||
private boolean comma;
|
||||
|
||||
/**
|
||||
* The current mode. Values:
|
||||
* 'a' (array),
|
||||
* 'd' (done),
|
||||
* 'i' (initial),
|
||||
* 'k' (key),
|
||||
* 'o' (object).
|
||||
*/
|
||||
protected char mode;
|
||||
|
||||
/**
|
||||
* The object/array stack.
|
||||
*/
|
||||
private final JSONObject stack[];
|
||||
|
||||
/**
|
||||
* The stack top index. A value of 0 indicates that the stack is empty.
|
||||
*/
|
||||
private int top;
|
||||
|
||||
/**
|
||||
* The writer that will receive the output.
|
||||
*/
|
||||
protected Appendable writer;
|
||||
|
||||
/**
|
||||
* Make a fresh JSONWriter. It can be used to build one JSON text.
|
||||
*/
|
||||
public JSONWriter(Appendable w) {
|
||||
this.comma = false;
|
||||
this.mode = 'i';
|
||||
this.stack = new JSONObject[maxdepth];
|
||||
this.top = 0;
|
||||
this.writer = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a value.
|
||||
* @param string A string value.
|
||||
* @return this
|
||||
* @throws JSONException If the value is out of sequence.
|
||||
*/
|
||||
private JSONWriter append(String string) throws JSONException {
|
||||
if (string == null) {
|
||||
throw new JSONException("Null pointer");
|
||||
}
|
||||
if (this.mode == 'o' || this.mode == 'a') {
|
||||
try {
|
||||
if (this.comma && this.mode == 'a') {
|
||||
this.writer.append(',');
|
||||
}
|
||||
this.writer.append(string);
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
if (this.mode == 'o') {
|
||||
this.mode = 'k';
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Value out of sequence.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin appending a new array. All values until the balancing
|
||||
* <code>endArray</code> will be appended to this array. The
|
||||
* <code>endArray</code> method must be called to mark the array's end.
|
||||
* @return this
|
||||
* @throws JSONException If the nesting is too deep, or if the object is
|
||||
* started in the wrong place (for example as a key or after the end of the
|
||||
* outermost array or object).
|
||||
*/
|
||||
public JSONWriter array() throws JSONException {
|
||||
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
|
||||
this.push(null);
|
||||
this.append("[");
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced array.");
|
||||
}
|
||||
|
||||
/**
|
||||
* End something.
|
||||
* @param mode Mode
|
||||
* @param c Closing character
|
||||
* @return this
|
||||
* @throws JSONException If unbalanced.
|
||||
*/
|
||||
private JSONWriter end(char mode, char c) throws JSONException {
|
||||
if (this.mode != mode) {
|
||||
throw new JSONException(mode == 'a'
|
||||
? "Misplaced endArray."
|
||||
: "Misplaced endObject.");
|
||||
}
|
||||
this.pop(mode);
|
||||
try {
|
||||
this.writer.append(c);
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* End an array. This method most be called to balance calls to
|
||||
* <code>array</code>.
|
||||
* @return this
|
||||
* @throws JSONException If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endArray() throws JSONException {
|
||||
return this.end('a', ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* End an object. This method most be called to balance calls to
|
||||
* <code>object</code>.
|
||||
* @return this
|
||||
* @throws JSONException If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endObject() throws JSONException {
|
||||
return this.end('k', '}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a key. The key will be associated with the next value. In an
|
||||
* object, every value must be preceded by a key.
|
||||
* @param string A key string.
|
||||
* @return this
|
||||
* @throws JSONException If the key is out of place. For example, keys
|
||||
* do not belong in arrays or if the key is null.
|
||||
*/
|
||||
public JSONWriter key(String string) throws JSONException {
|
||||
if (string == null) {
|
||||
throw new JSONException("Null key.");
|
||||
}
|
||||
if (this.mode == 'k') {
|
||||
try {
|
||||
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
|
||||
if (this.comma) {
|
||||
this.writer.append(',');
|
||||
}
|
||||
this.writer.append(JSONObject.quote(string));
|
||||
this.writer.append(':');
|
||||
this.comma = false;
|
||||
this.mode = 'o';
|
||||
return this;
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
throw new JSONException("Misplaced key.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begin appending a new object. All keys and values until the balancing
|
||||
* <code>endObject</code> will be appended to this object. The
|
||||
* <code>endObject</code> method must be called to mark the object's end.
|
||||
* @return this
|
||||
* @throws JSONException If the nesting is too deep, or if the object is
|
||||
* started in the wrong place (for example as a key or after the end of the
|
||||
* outermost array or object).
|
||||
*/
|
||||
public JSONWriter object() throws JSONException {
|
||||
if (this.mode == 'i') {
|
||||
this.mode = 'o';
|
||||
}
|
||||
if (this.mode == 'o' || this.mode == 'a') {
|
||||
this.append("{");
|
||||
this.push(new JSONObject());
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced object.");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pop an array or object scope.
|
||||
* @param c The scope to close.
|
||||
* @throws JSONException If nesting is wrong.
|
||||
*/
|
||||
private void pop(char c) throws JSONException {
|
||||
if (this.top <= 0) {
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||
if (m != c) {
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
this.top -= 1;
|
||||
this.mode = this.top == 0
|
||||
? 'd'
|
||||
: this.stack[this.top - 1] == null
|
||||
? 'a'
|
||||
: 'k';
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an array or object scope.
|
||||
* @param jo The scope to open.
|
||||
* @throws JSONException If nesting is too deep.
|
||||
*/
|
||||
private void push(JSONObject jo) throws JSONException {
|
||||
if (this.top >= maxdepth) {
|
||||
throw new JSONException("Nesting too deep.");
|
||||
}
|
||||
this.stack[this.top] = jo;
|
||||
this.mode = jo == null ? 'a' : 'k';
|
||||
this.top += 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append either the value <code>true</code> or the value
|
||||
* <code>false</code>.
|
||||
* @param b A boolean.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(boolean b) throws JSONException {
|
||||
return this.append(b ? "true" : "false");
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double value.
|
||||
* @param d A double.
|
||||
* @return this
|
||||
* @throws JSONException If the number is not finite.
|
||||
*/
|
||||
public JSONWriter value(double d) throws JSONException {
|
||||
return this.value(new Double(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a long value.
|
||||
* @param l A long.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(long l) throws JSONException {
|
||||
return this.append(Long.toString(l));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append an object value.
|
||||
* @param object The object to append. It can be null, or a Boolean, Number,
|
||||
* String, JSONObject, or JSONArray, or an object that implements JSONString.
|
||||
* @return this
|
||||
* @throws JSONException If the value is out of sequence.
|
||||
*/
|
||||
public JSONWriter value(Object object) throws JSONException {
|
||||
return this.append(JSONObject.valueToString(object));
|
||||
}
|
||||
}
|
72
d4dj/src/main/java/org/json/Property.java
Normal file
@ -0,0 +1,72 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Converts a Property file data into JSONObject and back.
|
||||
* @author JSON.org
|
||||
* @version 2015-05-05
|
||||
*/
|
||||
public class Property {
|
||||
/**
|
||||
* Converts a property file object into a JSONObject. The property file object is a table of name value pairs.
|
||||
* @param properties java.util.Properties
|
||||
* @return JSONObject
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
if (properties != null && !properties.isEmpty()) {
|
||||
Enumeration<?> enumProperties = properties.propertyNames();
|
||||
while(enumProperties.hasMoreElements()) {
|
||||
String name = (String)enumProperties.nextElement();
|
||||
jo.put(name, properties.getProperty(name));
|
||||
}
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the JSONObject into a property file object.
|
||||
* @param jo JSONObject
|
||||
* @return java.util.Properties
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static Properties toProperties(JSONObject jo) throws JSONException {
|
||||
Properties properties = new Properties();
|
||||
if (jo != null) {
|
||||
Iterator<String> keys = jo.keys();
|
||||
while (keys.hasNext()) {
|
||||
String name = keys.next();
|
||||
properties.put(name, jo.getString(name));
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
621
d4dj/src/main/java/org/json/XML.java
Normal file
@ -0,0 +1,621 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2015 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This provides static methods to convert an XML text into a JSONObject, and to
|
||||
* covert a JSONObject into an XML text.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2016-08-10
|
||||
*/
|
||||
@SuppressWarnings("boxing")
|
||||
public class XML {
|
||||
/** The Character '&'. */
|
||||
public static final Character AMP = '&';
|
||||
|
||||
/** The Character '''. */
|
||||
public static final Character APOS = '\'';
|
||||
|
||||
/** The Character '!'. */
|
||||
public static final Character BANG = '!';
|
||||
|
||||
/** The Character '='. */
|
||||
public static final Character EQ = '=';
|
||||
|
||||
/** The Character '>'. */
|
||||
public static final Character GT = '>';
|
||||
|
||||
/** The Character '<'. */
|
||||
public static final Character LT = '<';
|
||||
|
||||
/** The Character '?'. */
|
||||
public static final Character QUEST = '?';
|
||||
|
||||
/** The Character '"'. */
|
||||
public static final Character QUOT = '"';
|
||||
|
||||
/** The Character '/'. */
|
||||
public static final Character SLASH = '/';
|
||||
|
||||
/**
|
||||
* Creates an iterator for navigating Code Points in a string instead of
|
||||
* characters. Once Java7 support is dropped, this can be replaced with
|
||||
* <code>
|
||||
* string.codePoints()
|
||||
* </code>
|
||||
* which is available in Java8 and above.
|
||||
*
|
||||
* @see <a href=
|
||||
* "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a>
|
||||
*/
|
||||
private static Iterable<Integer> codePointIterator(final String string) {
|
||||
return new Iterable<Integer>() {
|
||||
@Override
|
||||
public Iterator<Integer> iterator() {
|
||||
return new Iterator<Integer>() {
|
||||
private int nextIndex = 0;
|
||||
private int length = string.length();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.nextIndex < this.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer next() {
|
||||
int result = string.codePointAt(this.nextIndex);
|
||||
this.nextIndex += Character.charCount(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace special characters with XML escapes:
|
||||
*
|
||||
* <pre>
|
||||
* & <small>(ampersand)</small> is replaced by &amp;
|
||||
* < <small>(less than)</small> is replaced by &lt;
|
||||
* > <small>(greater than)</small> is replaced by &gt;
|
||||
* " <small>(double quote)</small> is replaced by &quot;
|
||||
* ' <small>(single quote / apostrophe)</small> is replaced by &apos;
|
||||
* </pre>
|
||||
*
|
||||
* @param string
|
||||
* The string to be escaped.
|
||||
* @return The escaped string.
|
||||
*/
|
||||
public static String escape(String string) {
|
||||
StringBuilder sb = new StringBuilder(string.length());
|
||||
for (final int cp : codePointIterator(string)) {
|
||||
switch (cp) {
|
||||
case '&':
|
||||
sb.append("&");
|
||||
break;
|
||||
case '<':
|
||||
sb.append("<");
|
||||
break;
|
||||
case '>':
|
||||
sb.append(">");
|
||||
break;
|
||||
case '"':
|
||||
sb.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
sb.append("'");
|
||||
break;
|
||||
default:
|
||||
if (mustEscape(cp)) {
|
||||
sb.append("&#x");
|
||||
sb.append(Integer.toHexString(cp));
|
||||
sb.append(";");
|
||||
} else {
|
||||
sb.appendCodePoint(cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cp code point to test
|
||||
* @return true if the code point is not valid for an XML
|
||||
*/
|
||||
private static boolean mustEscape(int cp) {
|
||||
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets
|
||||
*
|
||||
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
|
||||
*
|
||||
* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
|
||||
*/
|
||||
// isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F)
|
||||
// all ISO control characters are out of range except tabs and new lines
|
||||
return (Character.isISOControl(cp)
|
||||
&& cp != 0x9
|
||||
&& cp != 0xA
|
||||
&& cp != 0xD
|
||||
) || !(
|
||||
// valid the range of acceptable characters that aren't control
|
||||
(cp >= 0x20 && cp <= 0xD7FF)
|
||||
|| (cp >= 0xE000 && cp <= 0xFFFD)
|
||||
|| (cp >= 0x10000 && cp <= 0x10FFFF)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes XML escapes from the string.
|
||||
*
|
||||
* @param string
|
||||
* string to remove escapes from
|
||||
* @return string with converted entities
|
||||
*/
|
||||
public static String unescape(String string) {
|
||||
StringBuilder sb = new StringBuilder(string.length());
|
||||
for (int i = 0, length = string.length(); i < length; i++) {
|
||||
char c = string.charAt(i);
|
||||
if (c == '&') {
|
||||
final int semic = string.indexOf(';', i);
|
||||
if (semic > i) {
|
||||
final String entity = string.substring(i + 1, semic);
|
||||
if (entity.charAt(0) == '#') {
|
||||
int cp;
|
||||
if (entity.charAt(1) == 'x') {
|
||||
// hex encoded unicode
|
||||
cp = Integer.parseInt(entity.substring(2), 16);
|
||||
} else {
|
||||
// decimal encoded unicode
|
||||
cp = Integer.parseInt(entity.substring(1));
|
||||
}
|
||||
sb.appendCodePoint(cp);
|
||||
} else {
|
||||
if ("quot".equalsIgnoreCase(entity)) {
|
||||
sb.append('"');
|
||||
} else if ("amp".equalsIgnoreCase(entity)) {
|
||||
sb.append('&');
|
||||
} else if ("apos".equalsIgnoreCase(entity)) {
|
||||
sb.append('\'');
|
||||
} else if ("lt".equalsIgnoreCase(entity)) {
|
||||
sb.append('<');
|
||||
} else if ("gt".equalsIgnoreCase(entity)) {
|
||||
sb.append('>');
|
||||
} else {
|
||||
sb.append('&').append(entity).append(';');
|
||||
}
|
||||
}
|
||||
// skip past the entity we just parsed.
|
||||
i += entity.length() + 1;
|
||||
} else {
|
||||
// this shouldn't happen in most cases since the parser
|
||||
// errors on unclosed enties.
|
||||
sb.append(c);
|
||||
}
|
||||
} else {
|
||||
// not part of an entity
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if the string contains whitespace. Whitespace is not
|
||||
* allowed in tagNames and attributes.
|
||||
*
|
||||
* @param string
|
||||
* A string.
|
||||
* @throws JSONException Thrown if the string contains whitespace or is empty.
|
||||
*/
|
||||
public static void noSpace(String string) throws JSONException {
|
||||
int i, length = string.length();
|
||||
if (length == 0) {
|
||||
throw new JSONException("Empty string.");
|
||||
}
|
||||
for (i = 0; i < length; i += 1) {
|
||||
if (Character.isWhitespace(string.charAt(i))) {
|
||||
throw new JSONException("'" + string
|
||||
+ "' contains a space character.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the content following the named tag, attaching it to the context.
|
||||
*
|
||||
* @param x
|
||||
* The XMLTokener containing the source string.
|
||||
* @param context
|
||||
* The JSONObject that will include the new material.
|
||||
* @param name
|
||||
* The tag name.
|
||||
* @return true if the close tag is processed.
|
||||
* @throws JSONException
|
||||
*/
|
||||
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings)
|
||||
throws JSONException {
|
||||
char c;
|
||||
int i;
|
||||
JSONObject jsonobject = null;
|
||||
String string;
|
||||
String tagName;
|
||||
Object token;
|
||||
|
||||
// Test for and skip past these forms:
|
||||
// <!-- ... -->
|
||||
// <! ... >
|
||||
// <![ ... ]]>
|
||||
// <? ... ?>
|
||||
// Report errors for these forms:
|
||||
// <>
|
||||
// <=
|
||||
// <<
|
||||
|
||||
token = x.nextToken();
|
||||
|
||||
// <!
|
||||
|
||||
if (token == BANG) {
|
||||
c = x.next();
|
||||
if (c == '-') {
|
||||
if (x.next() == '-') {
|
||||
x.skipPast("-->");
|
||||
return false;
|
||||
}
|
||||
x.back();
|
||||
} else if (c == '[') {
|
||||
token = x.nextToken();
|
||||
if ("CDATA".equals(token)) {
|
||||
if (x.next() == '[') {
|
||||
string = x.nextCDATA();
|
||||
if (string.length() > 0) {
|
||||
context.accumulate("content", string);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
throw x.syntaxError("Expected 'CDATA['");
|
||||
}
|
||||
i = 1;
|
||||
do {
|
||||
token = x.nextMeta();
|
||||
if (token == null) {
|
||||
throw x.syntaxError("Missing '>' after '<!'.");
|
||||
} else if (token == LT) {
|
||||
i += 1;
|
||||
} else if (token == GT) {
|
||||
i -= 1;
|
||||
}
|
||||
} while (i > 0);
|
||||
return false;
|
||||
} else if (token == QUEST) {
|
||||
|
||||
// <?
|
||||
x.skipPast("?>");
|
||||
return false;
|
||||
} else if (token == SLASH) {
|
||||
|
||||
// Close tag </
|
||||
|
||||
token = x.nextToken();
|
||||
if (name == null) {
|
||||
throw x.syntaxError("Mismatched close tag " + token);
|
||||
}
|
||||
if (!token.equals(name)) {
|
||||
throw x.syntaxError("Mismatched " + name + " and " + token);
|
||||
}
|
||||
if (x.nextToken() != GT) {
|
||||
throw x.syntaxError("Misshaped close tag");
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (token instanceof Character) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
|
||||
// Open tag <
|
||||
|
||||
} else {
|
||||
tagName = (String) token;
|
||||
token = null;
|
||||
jsonobject = new JSONObject();
|
||||
for (;;) {
|
||||
if (token == null) {
|
||||
token = x.nextToken();
|
||||
}
|
||||
// attribute = value
|
||||
if (token instanceof String) {
|
||||
string = (String) token;
|
||||
token = x.nextToken();
|
||||
if (token == EQ) {
|
||||
token = x.nextToken();
|
||||
if (!(token instanceof String)) {
|
||||
throw x.syntaxError("Missing value");
|
||||
}
|
||||
jsonobject.accumulate(string,
|
||||
keepStrings ? unescape((String)token) : stringToValue((String) token));
|
||||
token = null;
|
||||
} else {
|
||||
jsonobject.accumulate(string, "");
|
||||
}
|
||||
|
||||
|
||||
} else if (token == SLASH) {
|
||||
// Empty tag <.../>
|
||||
if (x.nextToken() != GT) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if (jsonobject.length() > 0) {
|
||||
context.accumulate(tagName, jsonobject);
|
||||
} else {
|
||||
context.accumulate(tagName, "");
|
||||
}
|
||||
return false;
|
||||
|
||||
} else if (token == GT) {
|
||||
// Content, between <...> and </...>
|
||||
for (;;) {
|
||||
token = x.nextContent();
|
||||
if (token == null) {
|
||||
if (tagName != null) {
|
||||
throw x.syntaxError("Unclosed tag " + tagName);
|
||||
}
|
||||
return false;
|
||||
} else if (token instanceof String) {
|
||||
string = (String) token;
|
||||
if (string.length() > 0) {
|
||||
jsonobject.accumulate("content",
|
||||
keepStrings ? unescape(string) : stringToValue(string));
|
||||
}
|
||||
|
||||
} else if (token == LT) {
|
||||
// Nested element
|
||||
if (parse(x, jsonobject, tagName,keepStrings)) {
|
||||
if (jsonobject.length() == 0) {
|
||||
context.accumulate(tagName, "");
|
||||
} else if (jsonobject.length() == 1
|
||||
&& jsonobject.opt("content") != null) {
|
||||
context.accumulate(tagName,
|
||||
jsonobject.opt("content"));
|
||||
} else {
|
||||
context.accumulate(tagName, jsonobject);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is the same as {@link JSONObject.stringToValue(String)}
|
||||
* except that this also tries to unescape String values.
|
||||
*
|
||||
* @param string String to convert
|
||||
* @return JSON value of this string or the string
|
||||
*/
|
||||
public static Object stringToValue(String string) {
|
||||
Object ret = JSONObject.stringToValue(string);
|
||||
if(ret instanceof String){
|
||||
return unescape((String)ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject. Some information may be lost in this transformation because
|
||||
* JSON is a data format and XML is a document format. XML uses elements,
|
||||
* attributes, and content text, while JSON uses unordered collections of
|
||||
* name/value pairs and arrays of values. JSON does not does not like to
|
||||
* distinguish between elements and attributes. Sequences of similar
|
||||
* elements are represented as JSONArrays. Content text may be placed in a
|
||||
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code>
|
||||
* are ignored.
|
||||
*
|
||||
* @param string
|
||||
* The source string.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown if there is an errors while parsing the string
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
return toJSONObject(string, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject. Some information may be lost in this transformation because
|
||||
* JSON is a data format and XML is a document format. XML uses elements,
|
||||
* attributes, and content text, while JSON uses unordered collections of
|
||||
* name/value pairs and arrays of values. JSON does not does not like to
|
||||
* distinguish between elements and attributes. Sequences of similar
|
||||
* elements are represented as JSONArrays. Content text may be placed in a
|
||||
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code>
|
||||
* are ignored.
|
||||
*
|
||||
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
|
||||
* numbers but will instead be the exact value as seen in the XML document.
|
||||
*
|
||||
* @param string
|
||||
* The source string.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown if there is an errors while parsing the string
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
XMLTokener x = new XMLTokener(string);
|
||||
while (x.more() && x.skipPast("<")) {
|
||||
parse(x, jo, null, keepStrings);
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
/**
|
||||
* Convert a JSONObject into a well-formed, element-normal XML string.
|
||||
*
|
||||
* @param object
|
||||
* A JSONObject.
|
||||
* @return A string.
|
||||
* @throws JSONException Thrown if there is an error parsing the string
|
||||
*/
|
||||
public static String toString(Object object) throws JSONException {
|
||||
return toString(object, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into a well-formed, element-normal XML string.
|
||||
*
|
||||
* @param object
|
||||
* A JSONObject.
|
||||
* @param tagName
|
||||
* The optional name of the enclosing tag.
|
||||
* @return A string.
|
||||
* @throws JSONException Thrown if there is an error parsing the string
|
||||
*/
|
||||
public static String toString(Object object, String tagName)
|
||||
throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
JSONArray ja;
|
||||
JSONObject jo;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
String string;
|
||||
Object value;
|
||||
|
||||
if (object instanceof JSONObject) {
|
||||
|
||||
// Emit <tagName>
|
||||
if (tagName != null) {
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
|
||||
// Loop thru the keys.
|
||||
jo = (JSONObject) object;
|
||||
keys = jo.keys();
|
||||
while (keys.hasNext()) {
|
||||
key = keys.next();
|
||||
value = jo.opt(key);
|
||||
if (value == null) {
|
||||
value = "";
|
||||
} else if (value.getClass().isArray()) {
|
||||
value = new JSONArray(value);
|
||||
}
|
||||
string = value instanceof String ? (String) value : null;
|
||||
|
||||
// Emit content in body
|
||||
if ("content".equals(key)) {
|
||||
if (value instanceof JSONArray) {
|
||||
ja = (JSONArray) value;
|
||||
int i = 0;
|
||||
for (Object val : ja) {
|
||||
if (i > 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append(escape(val.toString()));
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
sb.append(escape(value.toString()));
|
||||
}
|
||||
|
||||
// Emit an array of similar keys
|
||||
|
||||
} else if (value instanceof JSONArray) {
|
||||
ja = (JSONArray) value;
|
||||
for (Object val : ja) {
|
||||
if (val instanceof JSONArray) {
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append('>');
|
||||
sb.append(toString(val));
|
||||
sb.append("</");
|
||||
sb.append(key);
|
||||
sb.append('>');
|
||||
} else {
|
||||
sb.append(toString(val, key));
|
||||
}
|
||||
}
|
||||
} else if ("".equals(value)) {
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append("/>");
|
||||
|
||||
// Emit a new tag <k>
|
||||
|
||||
} else {
|
||||
sb.append(toString(value, key));
|
||||
}
|
||||
}
|
||||
if (tagName != null) {
|
||||
|
||||
// Emit the </tagname> close tag
|
||||
sb.append("</");
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
if (object != null) {
|
||||
if (object.getClass().isArray()) {
|
||||
object = new JSONArray(object);
|
||||
}
|
||||
|
||||
if (object instanceof JSONArray) {
|
||||
ja = (JSONArray) object;
|
||||
for (Object val : ja) {
|
||||
// XML does not have good support for arrays. If an array
|
||||
// appears in a place where XML is lacking, synthesize an
|
||||
// <array> element.
|
||||
sb.append(toString(val, tagName == null ? "array" : tagName));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
string = (object == null) ? "null" : escape(object.toString());
|
||||
return (tagName == null) ? "\"" + string + "\""
|
||||
: (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName
|
||||
+ ">" + string + "</" + tagName + ">";
|
||||
|
||||
}
|
||||
}
|
365
d4dj/src/main/java/org/json/XMLTokener.java
Normal file
@ -0,0 +1,365 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The XMLTokener extends the JSONTokener to provide additional methods
|
||||
* for the parsing of XML texts.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class XMLTokener extends JSONTokener {
|
||||
|
||||
|
||||
/** The table of entity values. It initially contains Character values for
|
||||
* amp, apos, gt, lt, quot.
|
||||
*/
|
||||
public static final java.util.HashMap<String, Character> entity;
|
||||
|
||||
static {
|
||||
entity = new java.util.HashMap<String, Character>(8);
|
||||
entity.put("amp", XML.AMP);
|
||||
entity.put("apos", XML.APOS);
|
||||
entity.put("gt", XML.GT);
|
||||
entity.put("lt", XML.LT);
|
||||
entity.put("quot", XML.QUOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an XMLTokener from a string.
|
||||
* @param s A source string.
|
||||
*/
|
||||
public XMLTokener(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text in the CDATA block.
|
||||
* @return The string up to the <code>]]></code>.
|
||||
* @throws JSONException If the <code>]]></code> is not found.
|
||||
*/
|
||||
public String nextCDATA() throws JSONException {
|
||||
char c;
|
||||
int i;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (end()) {
|
||||
throw syntaxError("Unclosed CDATA");
|
||||
}
|
||||
sb.append(c);
|
||||
i = sb.length() - 3;
|
||||
if (i >= 0 && sb.charAt(i) == ']' &&
|
||||
sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
|
||||
sb.setLength(i);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next XML outer token, trimming whitespace. There are two kinds
|
||||
* of tokens: the '<' character which begins a markup tag, and the content
|
||||
* text between markup tags.
|
||||
*
|
||||
* @return A string, or a '<' Character, or null if there is no more
|
||||
* source text.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public Object nextContent() throws JSONException {
|
||||
char c;
|
||||
StringBuilder sb;
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
if (c == 0) {
|
||||
return null;
|
||||
}
|
||||
if (c == '<') {
|
||||
return XML.LT;
|
||||
}
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
if (c == '<' || c == 0) {
|
||||
back();
|
||||
return sb.toString().trim();
|
||||
}
|
||||
if (c == '&') {
|
||||
sb.append(nextEntity(c));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
c = next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the next entity. These entities are translated to Characters:
|
||||
* <code>& ' > < "</code>.
|
||||
* @param ampersand An ampersand character.
|
||||
* @return A Character or an entity String if the entity is not recognized.
|
||||
* @throws JSONException If missing ';' in XML entity.
|
||||
*/
|
||||
public Object nextEntity(char ampersand) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
char c = next();
|
||||
if (Character.isLetterOrDigit(c) || c == '#') {
|
||||
sb.append(Character.toLowerCase(c));
|
||||
} else if (c == ';') {
|
||||
break;
|
||||
} else {
|
||||
throw syntaxError("Missing ';' in XML entity: &" + sb);
|
||||
}
|
||||
}
|
||||
String string = sb.toString();
|
||||
Object object = entity.get(string);
|
||||
return object != null ? object : ampersand + string + ";";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next XML meta token. This is used for skipping over <!...>
|
||||
* and <?...?> structures.
|
||||
* @return Syntax characters (<code>< > / = ! ?</code>) are returned as
|
||||
* Character, and strings and names are returned as Boolean. We don't care
|
||||
* what the values actually are.
|
||||
* @throws JSONException If a string is not properly closed or if the XML
|
||||
* is badly structured.
|
||||
*/
|
||||
public Object nextMeta() throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
switch (c) {
|
||||
case 0:
|
||||
throw syntaxError("Misshaped meta tag");
|
||||
case '<':
|
||||
return XML.LT;
|
||||
case '>':
|
||||
return XML.GT;
|
||||
case '/':
|
||||
return XML.SLASH;
|
||||
case '=':
|
||||
return XML.EQ;
|
||||
case '!':
|
||||
return XML.BANG;
|
||||
case '?':
|
||||
return XML.QUEST;
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
throw syntaxError("Unterminated string");
|
||||
}
|
||||
if (c == q) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
default:
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (Character.isWhitespace(c)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
switch (c) {
|
||||
case 0:
|
||||
case '<':
|
||||
case '>':
|
||||
case '/':
|
||||
case '=':
|
||||
case '!':
|
||||
case '?':
|
||||
case '"':
|
||||
case '\'':
|
||||
back();
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next XML Token. These tokens are found inside of angle
|
||||
* brackets. It may be one of these characters: <code>/ > = ! ?</code> or it
|
||||
* may be a string wrapped in single quotes or double quotes, or it may be a
|
||||
* name.
|
||||
* @return a String or a Character.
|
||||
* @throws JSONException If the XML is not well formed.
|
||||
*/
|
||||
public Object nextToken() throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
StringBuilder sb;
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
switch (c) {
|
||||
case 0:
|
||||
throw syntaxError("Misshaped element");
|
||||
case '<':
|
||||
throw syntaxError("Misplaced '<'");
|
||||
case '>':
|
||||
return XML.GT;
|
||||
case '/':
|
||||
return XML.SLASH;
|
||||
case '=':
|
||||
return XML.EQ;
|
||||
case '!':
|
||||
return XML.BANG;
|
||||
case '?':
|
||||
return XML.QUEST;
|
||||
|
||||
// Quoted string
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
throw syntaxError("Unterminated string");
|
||||
}
|
||||
if (c == q) {
|
||||
return sb.toString();
|
||||
}
|
||||
if (c == '&') {
|
||||
sb.append(nextEntity(c));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
||||
// Name
|
||||
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
sb.append(c);
|
||||
c = next();
|
||||
if (Character.isWhitespace(c)) {
|
||||
return sb.toString();
|
||||
}
|
||||
switch (c) {
|
||||
case 0:
|
||||
return sb.toString();
|
||||
case '>':
|
||||
case '/':
|
||||
case '=':
|
||||
case '!':
|
||||
case '?':
|
||||
case '[':
|
||||
case ']':
|
||||
back();
|
||||
return sb.toString();
|
||||
case '<':
|
||||
case '"':
|
||||
case '\'':
|
||||
throw syntaxError("Bad character in a name");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skip characters until past the requested string.
|
||||
* If it is not found, we are left at the end of the source with a result of false.
|
||||
* @param to A string to skip past.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public boolean skipPast(String to) throws JSONException {
|
||||
boolean b;
|
||||
char c;
|
||||
int i;
|
||||
int j;
|
||||
int offset = 0;
|
||||
int length = to.length();
|
||||
char[] circle = new char[length];
|
||||
|
||||
/*
|
||||
* First fill the circle buffer with as many characters as are in the
|
||||
* to string. If we reach an early end, bail.
|
||||
*/
|
||||
|
||||
for (i = 0; i < length; i += 1) {
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
return false;
|
||||
}
|
||||
circle[i] = c;
|
||||
}
|
||||
|
||||
/* We will loop, possibly for all of the remaining characters. */
|
||||
|
||||
for (;;) {
|
||||
j = offset;
|
||||
b = true;
|
||||
|
||||
/* Compare the circle buffer with the to string. */
|
||||
|
||||
for (i = 0; i < length; i += 1) {
|
||||
if (circle[j] != to.charAt(i)) {
|
||||
b = false;
|
||||
break;
|
||||
}
|
||||
j += 1;
|
||||
if (j >= length) {
|
||||
j -= length;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we exit the loop with b intact, then victory is ours. */
|
||||
|
||||
if (b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Get the next character. If there isn't one, then defeat is ours. */
|
||||
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Shove the character in the circle buffer and advance the
|
||||
* circle offset. The offset is mod n.
|
||||
*/
|
||||
circle[offset] = c;
|
||||
offset += 1;
|
||||
if (offset >= length) {
|
||||
offset -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
219
d4dj/src/main/java/sig/utils/Audio.java
Normal file
@ -0,0 +1,219 @@
|
||||
package sig.utils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.BooleanControl;
|
||||
import javax.sound.sampled.CompoundControl;
|
||||
import javax.sound.sampled.Control;
|
||||
import javax.sound.sampled.Control.Type;
|
||||
import javax.sound.sampled.FloatControl;
|
||||
import javax.sound.sampled.Line;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.Mixer.Info;
|
||||
|
||||
public class Audio {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println(getHierarchyInfo());
|
||||
System.out.println(getMasterOutputVolume());
|
||||
}
|
||||
|
||||
public static void setMasterOutputVolume(float value) {
|
||||
if (value < 0 || value > 1)
|
||||
throw new IllegalArgumentException(
|
||||
"Volume can only be set to a value from 0 to 1. Given value is illegal: " + value);
|
||||
Line line = getMasterOutputLine();
|
||||
if (line == null) throw new RuntimeException("Master output port not found");
|
||||
boolean opened = open(line);
|
||||
try {
|
||||
FloatControl control = getVolumeControl(line);
|
||||
if (control == null)
|
||||
throw new RuntimeException("Volume control not found in master port: " + toString(line));
|
||||
control.setValue(value);
|
||||
} finally {
|
||||
if (opened) line.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static Float getMasterOutputVolume() {
|
||||
Line line = getMasterOutputLine();
|
||||
if (line == null) return null;
|
||||
boolean opened = open(line);
|
||||
try {
|
||||
FloatControl control = getVolumeControl(line);
|
||||
if (control == null) return null;
|
||||
return control.getValue();
|
||||
} finally {
|
||||
if (opened) line.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setMasterOutputMute(boolean value) {
|
||||
Line line = getMasterOutputLine();
|
||||
if (line == null) throw new RuntimeException("Master output port not found");
|
||||
boolean opened = open(line);
|
||||
try {
|
||||
BooleanControl control = getMuteControl(line);
|
||||
if (control == null)
|
||||
throw new RuntimeException("Mute control not found in master port: " + toString(line));
|
||||
control.setValue(value);
|
||||
} finally {
|
||||
if (opened) line.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static Boolean getMasterOutputMute() {
|
||||
Line line = getMasterOutputLine();
|
||||
if (line == null) return null;
|
||||
boolean opened = open(line);
|
||||
try {
|
||||
BooleanControl control = getMuteControl(line);
|
||||
if (control == null) return null;
|
||||
return control.getValue();
|
||||
} finally {
|
||||
if (opened) line.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static Line getMasterOutputLine() {
|
||||
for (Mixer mixer : getMixers()) {
|
||||
for (Line line : getAvailableOutputLines(mixer)) {
|
||||
if (line.getLineInfo().toString().contains("Master")) return line;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FloatControl getVolumeControl(Line line) {
|
||||
if (!line.isOpen()) throw new RuntimeException("Line is closed: " + toString(line));
|
||||
return (FloatControl) findControl(FloatControl.Type.VOLUME, line.getControls());
|
||||
}
|
||||
|
||||
public static BooleanControl getMuteControl(Line line) {
|
||||
if (!line.isOpen()) throw new RuntimeException("Line is closed: " + toString(line));
|
||||
return (BooleanControl) findControl(BooleanControl.Type.MUTE, line.getControls());
|
||||
}
|
||||
|
||||
private static Control findControl(Type type, Control... controls) {
|
||||
if (controls == null || controls.length == 0) return null;
|
||||
for (Control control : controls) {
|
||||
if (control.getType().equals(type)) return control;
|
||||
if (control instanceof CompoundControl) {
|
||||
CompoundControl compoundControl = (CompoundControl) control;
|
||||
Control member = findControl(type, compoundControl.getMemberControls());
|
||||
if (member != null) return member;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Mixer> getMixers() {
|
||||
Info[] infos = AudioSystem.getMixerInfo();
|
||||
List<Mixer> mixers = new ArrayList<Mixer>(infos.length);
|
||||
for (Info info : infos) {
|
||||
Mixer mixer = AudioSystem.getMixer(info);
|
||||
mixers.add(mixer);
|
||||
}
|
||||
return mixers;
|
||||
}
|
||||
|
||||
public static List<Line> getAvailableOutputLines(Mixer mixer) {
|
||||
return getAvailableLines(mixer, mixer.getTargetLineInfo());
|
||||
}
|
||||
|
||||
public static List<Line> getAvailableInputLines(Mixer mixer) {
|
||||
return getAvailableLines(mixer, mixer.getSourceLineInfo());
|
||||
}
|
||||
|
||||
private static List<Line> getAvailableLines(Mixer mixer, Line.Info[] lineInfos) {
|
||||
List<Line> lines = new ArrayList<Line>(lineInfos.length);
|
||||
for (Line.Info lineInfo : lineInfos) {
|
||||
Line line;
|
||||
line = getLineIfAvailable(mixer, lineInfo);
|
||||
if (line != null) lines.add(line);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
public static Line getLineIfAvailable(Mixer mixer, Line.Info lineInfo) {
|
||||
try {
|
||||
return mixer.getLine(lineInfo);
|
||||
} catch (LineUnavailableException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getHierarchyInfo() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Mixer mixer : getMixers()) {
|
||||
sb.append("Mixer: ").append(toString(mixer)).append("\n");
|
||||
|
||||
for (Line line : getAvailableOutputLines(mixer)) {
|
||||
sb.append(" OUT: ").append(toString(line)).append("\n");
|
||||
boolean opened = open(line);
|
||||
for (Control control : line.getControls()) {
|
||||
sb.append(" Control: ").append(toString(control)).append("\n");
|
||||
if (control instanceof CompoundControl) {
|
||||
CompoundControl compoundControl = (CompoundControl) control;
|
||||
for (Control subControl : compoundControl.getMemberControls()) {
|
||||
sb.append(" Sub-Control: ").append(toString(subControl)).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opened) line.close();
|
||||
}
|
||||
|
||||
for (Line line : getAvailableOutputLines(mixer)) {
|
||||
sb.append(" IN: ").append(toString(line)).append("\n");
|
||||
boolean opened = open(line);
|
||||
for (Control control : line.getControls()) {
|
||||
sb.append(" Control: ").append(toString(control)).append("\n");
|
||||
if (control instanceof CompoundControl) {
|
||||
CompoundControl compoundControl = (CompoundControl) control;
|
||||
for (Control subControl : compoundControl.getMemberControls()) {
|
||||
sb.append(" Sub-Control: ").append(toString(subControl)).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opened) line.close();
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static boolean open(Line line) {
|
||||
if (line.isOpen()) return false;
|
||||
try {
|
||||
line.open();
|
||||
} catch (LineUnavailableException ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String toString(Control control) {
|
||||
if (control == null) return null;
|
||||
return control.toString() + " (" + control.getType().toString() + ")";
|
||||
}
|
||||
|
||||
public static String toString(Line line) {
|
||||
if (line == null) return null;
|
||||
Line.Info info = line.getLineInfo();
|
||||
return info.toString();// + " (" + line.getClass().getSimpleName() + ")";
|
||||
}
|
||||
|
||||
public static String toString(Mixer mixer) {
|
||||
if (mixer == null) return null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Info info = mixer.getMixerInfo();
|
||||
sb.append(info.getName());
|
||||
sb.append(" (").append(info.getDescription()).append(")");
|
||||
sb.append(mixer.isOpen() ? " [open]" : " [closed]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
17
d4dj/src/main/java/sig/utils/DebugUtils.java
Normal file
@ -0,0 +1,17 @@
|
||||
package sig.utils;
|
||||
|
||||
|
||||
public class DebugUtils {
|
||||
public static void showStackTrace() {
|
||||
System.out.println("Trace:"+getStackTrace());
|
||||
}
|
||||
|
||||
public static String getStackTrace() {
|
||||
StackTraceElement[] stacktrace = new Throwable().getStackTrace();
|
||||
StringBuilder stack = new StringBuilder("Mini stack tracer:");
|
||||
for (int i=0;i<Math.min(10, stacktrace.length);i++) {
|
||||
stack.append("\n"+stacktrace[i].getClassName()+": **"+stacktrace[i].getFileName()+"** "+stacktrace[i].getMethodName()+"():"+stacktrace[i].getLineNumber());
|
||||
}
|
||||
return stack.toString();
|
||||
}
|
||||
}
|
112
d4dj/src/main/java/sig/utils/DrawUtils.java
Normal file
@ -0,0 +1,112 @@
|
||||
package sig.utils;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.text.AttributedString;
|
||||
|
||||
|
||||
public class DrawUtils {
|
||||
public static void drawOutlineText(Graphics g, Font font, double x, double y, int outline_size, Color text_color, Color shadow_color, String message) {
|
||||
drawOutlineText(g,font,x,y,0,0,1,outline_size,text_color,shadow_color,message);
|
||||
}
|
||||
public static void drawOutlineText(Graphics g, Font font, double x, double y, int font_thickness, int outline_thickness, Color text_color, Color shadow_color, String message) {
|
||||
drawOutlineText(g,font,x,y,0,0,font_thickness,outline_thickness,text_color,shadow_color,message);
|
||||
}
|
||||
static void drawOutlineText(Graphics g, Font font, double x, double y, double xoffset, double yoffset, int font_thickness, int outline_thickness, Color text_color, Color shadow_color, String message) {
|
||||
if (message.length()>0) {
|
||||
AttributedString as = new AttributedString(message);
|
||||
as.addAttribute(TextAttribute.FONT, font);
|
||||
as.addAttribute(TextAttribute.KERNING,TextAttribute.KERNING_ON);
|
||||
as.addAttribute(TextAttribute.WIDTH,TextAttribute.WIDTH_EXTENDED);
|
||||
as.addAttribute(TextAttribute.TRACKING,0.5);
|
||||
g.setColor(shadow_color);
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
FontRenderContext frc = g2.getFontMetrics(font).getFontRenderContext();
|
||||
GlyphVector gv = font.createGlyphVector(frc, message);
|
||||
Shape shape = gv.getOutline((int)(x+xoffset),(int)(y+yoffset));
|
||||
g2.setClip(null);
|
||||
g2.setStroke(new BasicStroke(font_thickness + outline_thickness*2));
|
||||
g2.setColor(shadow_color);
|
||||
g2.setRenderingHint(
|
||||
RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.draw(shape);
|
||||
GlyphVector gv2 = font.createGlyphVector(frc, message);
|
||||
Shape shape2 = gv2.getOutline((int)(x+xoffset),(int)(y+yoffset));
|
||||
g2.setClip(null);
|
||||
g2.setStroke(new BasicStroke(font_thickness));
|
||||
g2.setColor(text_color);
|
||||
g2.setRenderingHint(
|
||||
RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.draw(shape2);
|
||||
g2.setColor(text_color);
|
||||
g2.drawString(as.getIterator(),(int)(x+xoffset),(int)(y+yoffset));
|
||||
}
|
||||
}
|
||||
public static void drawHealthbar(Graphics g, Rectangle bounds, double pct, Color healthbarcol) {
|
||||
g.setColor(Color.BLACK);
|
||||
g.draw3DRect((int)bounds.getX(), (int)bounds.getY(), (int)bounds.getWidth(), (int)bounds.getHeight(), true);
|
||||
g.setColor(healthbarcol);
|
||||
g.fill3DRect((int)bounds.getX()+1, (int)bounds.getY()+1, (int)(bounds.getWidth()*pct)-1, (int)bounds.getHeight()-1, true);
|
||||
}
|
||||
|
||||
public static Color convertStringToColor(String s) {
|
||||
String[] split = s.split(",");
|
||||
if (split.length==3) {
|
||||
return new Color(
|
||||
Math.min(Math.abs(Integer.parseInt(split[0])),255),
|
||||
Math.min(Math.abs(Integer.parseInt(split[1])),255),
|
||||
Math.min(Math.abs(Integer.parseInt(split[2])),255));
|
||||
} else
|
||||
if (split.length==4) {
|
||||
return new Color(
|
||||
Math.min(Math.abs(Integer.parseInt(split[0])),255),
|
||||
Math.min(Math.abs(Integer.parseInt(split[1])),255),
|
||||
Math.min(Math.abs(Integer.parseInt(split[2])),255),
|
||||
Math.min(Math.abs(Integer.parseInt(split[3])),255));
|
||||
} else {
|
||||
System.out.println("WARNING! Invalid Color string specified ("+s+").");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawImage(Graphics g, Image img, double x, double y, Color blend_col, ImageObserver source) {
|
||||
BufferedImage tmp = new BufferedImage(img.getWidth(source),img.getHeight(source),BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2 = tmp.createGraphics();
|
||||
g2.drawImage(img, 0, 0, null);
|
||||
g2.setComposite(AlphaComposite.SrcAtop);
|
||||
g2.setColor(blend_col);
|
||||
g2.fillRect(0, 0, img.getWidth(source), img.getHeight(source));
|
||||
g2.dispose();
|
||||
g.drawImage(tmp,(int)x,(int)y,source);
|
||||
}
|
||||
|
||||
public static void drawImageScaled(Graphics g, Image img, double x, double y, double xsize, double ysize, Color blend_col, ImageObserver source) {
|
||||
BufferedImage tmp = new BufferedImage(img.getWidth(source),img.getHeight(source),BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2 = tmp.createGraphics();
|
||||
g2.drawImage(img, 0, 0, null);
|
||||
g2.setComposite(AlphaComposite.SrcAtop);
|
||||
g2.setColor(blend_col);
|
||||
g2.fillRect(0, 0, img.getWidth(source), img.getHeight(source));
|
||||
g2.dispose();
|
||||
g.drawImage(tmp,(int)x,(int)y,(int)xsize,(int)ysize,source);
|
||||
}
|
||||
|
||||
public static Color invertColor(Color c) {
|
||||
return new Color(255-c.getRed(),255-c.getGreen(),255-c.getBlue(),255);
|
||||
}
|
||||
}
|
380
d4dj/src/main/java/sig/utils/FileUtils.java
Normal file
@ -0,0 +1,380 @@
|
||||
package sig.utils;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.net.ConnectException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class FileUtils {
|
||||
public static String[] readFromFile(String filename) {
|
||||
File file = new File(filename);
|
||||
//System.out.println(file.getAbsolutePath());
|
||||
List<String> contents= new ArrayList<String>();
|
||||
if (file.exists()) {
|
||||
try(
|
||||
//FileReader fw = new FileReader(filename);
|
||||
InputStream in = new FileInputStream(filename);
|
||||
Reader reader = new InputStreamReader(in,StandardCharsets.UTF_8);
|
||||
BufferedReader bw = new BufferedReader(reader);)
|
||||
{
|
||||
String readline = bw.readLine();
|
||||
do {
|
||||
if (readline!=null) {
|
||||
//System.out.println(readline);
|
||||
contents.add(readline);
|
||||
readline = bw.readLine();
|
||||
}} while (readline!=null);
|
||||
in.close();
|
||||
reader.close();
|
||||
bw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return contents.toArray(new String[contents.size()]);
|
||||
}
|
||||
|
||||
private static String readAll(Reader rd) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int cp;
|
||||
while ((cp = rd.read()) != -1) {
|
||||
sb.append((char) cp);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String readFilter(Reader rd, HashMap<Long,String> channel_ids) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean allowed=false;
|
||||
boolean quotation_mark=false;
|
||||
boolean endquotation_mark=false;
|
||||
boolean foundChannel=false;
|
||||
boolean nextBrace=false;
|
||||
boolean outputStuff=false;
|
||||
String numb = "";
|
||||
int braceCount=0;
|
||||
int channelCount=0;
|
||||
int vals=0;
|
||||
int cp;
|
||||
while ((cp = rd.read()) != -1) {
|
||||
if (braceCount==0) {
|
||||
allowed=true;
|
||||
} else
|
||||
if (braceCount==1 && !quotation_mark){
|
||||
quotation_mark=true;
|
||||
numb="";
|
||||
allowed=false;
|
||||
} else
|
||||
if (!endquotation_mark) {
|
||||
if ((char)cp >= '0' &&
|
||||
(char)cp <= '9') {
|
||||
allowed=false;
|
||||
numb+=(char)cp;
|
||||
} else {
|
||||
allowed=false;
|
||||
endquotation_mark=true;
|
||||
try {
|
||||
if (channel_ids.containsKey(Long.parseLong(numb))) {
|
||||
if (channelCount>=1) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("\""+numb+"\"");
|
||||
foundChannel=true;
|
||||
System.out.println("Found channel "+numb);
|
||||
outputStuff=true;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (!nextBrace && foundChannel) {
|
||||
allowed=true;
|
||||
if ((char)cp == '{') {
|
||||
nextBrace=true;
|
||||
}
|
||||
} else
|
||||
if (foundChannel) {
|
||||
allowed=true;
|
||||
if (braceCount==1) {
|
||||
allowed=false;
|
||||
channelCount++;
|
||||
quotation_mark=false;
|
||||
endquotation_mark=false;
|
||||
foundChannel=false;
|
||||
nextBrace=false;
|
||||
}
|
||||
} else {
|
||||
allowed=false;
|
||||
if (braceCount==1) {
|
||||
allowed=false;
|
||||
quotation_mark=false;
|
||||
endquotation_mark=false;
|
||||
foundChannel=false;
|
||||
nextBrace=false;
|
||||
}
|
||||
}
|
||||
|
||||
/*if (outputStuff && vals++<1000) {
|
||||
System.out.print((char)cp);
|
||||
}*/
|
||||
if ((char)cp == '{') {
|
||||
braceCount++;
|
||||
//System.out.println("Brace count is "+braceCount+".");
|
||||
} else
|
||||
if ((char)cp == '}') {
|
||||
braceCount--;
|
||||
//System.out.println("Brace count is "+braceCount+".");
|
||||
}
|
||||
|
||||
if (allowed) {
|
||||
sb.append((char) cp);
|
||||
}
|
||||
}
|
||||
sb.append("}");
|
||||
//System.out.println("=============");
|
||||
//System.out.println(sb.toString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFromUrlWithFilter(String url, HashMap<Long,String> filter) throws IOException, JSONException {
|
||||
return readJsonFromUrlWithFilter(url,filter,null,false);
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFromFileWithFilter(String file, HashMap<Long,String> filter) throws IOException, JSONException {
|
||||
InputStream is = new FileInputStream(new File(file));
|
||||
try {
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||
String jsonText = readFilter(rd,filter);
|
||||
JSONObject json = new JSONObject(jsonText);
|
||||
jsonText=null;
|
||||
return json;
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFromUrlWithFilter(String url, HashMap<Long,String> filter, String file, boolean writeToFile) throws IOException, JSONException {
|
||||
InputStream is = new URL(url).openStream();
|
||||
try {
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||
String jsonText = readFilter(rd,filter);
|
||||
if (writeToFile) {
|
||||
writetoFile(new String[]{jsonText},file);
|
||||
}
|
||||
JSONObject json = new JSONObject(jsonText);
|
||||
return json;
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
|
||||
return readJsonFromUrl(url,null,false);
|
||||
}
|
||||
|
||||
public static JSONArray readJsonArrayFromUrl(String url) throws IOException, JSONException {
|
||||
return readJsonArrayFromUrl(url,null,false);
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFromFile(String file) throws IOException, JSONException {
|
||||
InputStream is = new FileInputStream(new File(file));
|
||||
try {
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||
String jsonText = readAll(rd);
|
||||
JSONObject json = new JSONObject(jsonText);
|
||||
jsonText=null;
|
||||
return json;
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFromUrl(String url, String file, boolean writeToFile) throws IOException, JSONException {
|
||||
try {
|
||||
InputStream is = new URL(url).openStream();
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||
String jsonText = readAll(rd);
|
||||
if (writeToFile) {
|
||||
writetoFile(new String[]{jsonText},file);
|
||||
}
|
||||
JSONObject json = new JSONObject(jsonText);
|
||||
is.close();
|
||||
return json;
|
||||
} catch (IOException e) {
|
||||
return new JSONObject("{}");
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONArray readJsonArrayFromUrl(String url, String file, boolean writeToFile) throws IOException, JSONException {
|
||||
URL obj = new URL(url);
|
||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
int responseCode = con.getResponseCode();
|
||||
System.out.println("GET Response Code :: " + responseCode);
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) { // success
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(
|
||||
con.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuffer response = new StringBuffer();
|
||||
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
|
||||
// print result
|
||||
System.out.println(response);
|
||||
|
||||
return new JSONArray(response.toString());
|
||||
} else {
|
||||
System.out.println("GET request not worked");
|
||||
return new JSONArray("[]");
|
||||
}
|
||||
}
|
||||
|
||||
public static void logToFile(String message, String filename) {
|
||||
logToFile(message,filename,false);
|
||||
}
|
||||
|
||||
public static void logToFile(String message, String filename, boolean outputToChatLog) {
|
||||
File file = new File(filename);
|
||||
try {
|
||||
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
OutputStream out = new FileOutputStream(file,true);
|
||||
Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
|
||||
PrintWriter pw = new PrintWriter(writer);
|
||||
|
||||
pw.println(message);
|
||||
pw.flush();
|
||||
pw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void writetoFile(String[] data, String filename) {
|
||||
File file = new File(filename);
|
||||
try {
|
||||
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
FileWriter fw = new FileWriter(file,false);
|
||||
PrintWriter pw = new PrintWriter(fw);
|
||||
|
||||
for (String s : data) {
|
||||
pw.println(s);
|
||||
}
|
||||
pw.flush();
|
||||
pw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyFile(File source, File dest) throws IOException {
|
||||
FileChannel sourceChannel = null;
|
||||
FileChannel destChannel = null;
|
||||
try {
|
||||
sourceChannel = new FileInputStream(source).getChannel();
|
||||
destChannel = new FileOutputStream(dest).getChannel();
|
||||
destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
|
||||
}finally{
|
||||
sourceChannel.close();
|
||||
destChannel.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyFileDir(File sourcedir, File destdir) throws IOException {
|
||||
FileChannel sourceChannel = null;
|
||||
FileChannel destChannel = null;
|
||||
destdir.mkdirs();
|
||||
try {
|
||||
if (sourcedir.exists()) {
|
||||
for (String name : sourcedir.list()) {
|
||||
File f = new File(sourcedir,name);
|
||||
sourceChannel = new FileInputStream(f).getChannel();
|
||||
destChannel = new FileOutputStream(new File(destdir,name)).getChannel();
|
||||
destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
|
||||
sourceChannel.close();
|
||||
destChannel.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteFile(File filename) {
|
||||
File file = filename;
|
||||
if (file.exists()) {
|
||||
//System.out.println("Trying to delete "+file);
|
||||
if (file.isDirectory()) {
|
||||
for (String name : file.list()) {
|
||||
File f = new File(file,name);
|
||||
deleteFile(f);
|
||||
}
|
||||
}
|
||||
file.delete();
|
||||
//System.out.println(file+" deleted");
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteFile(String filename) {
|
||||
File file = new File(filename);
|
||||
deleteFile(file);
|
||||
}
|
||||
|
||||
|
||||
public static void downloadFileFromUrl(String url, String file) throws IOException, JSONException {
|
||||
File filer = new File(file);
|
||||
filer.createNewFile();
|
||||
|
||||
URL website = new URL(url);
|
||||
HttpURLConnection connection = (HttpURLConnection) website.openConnection();
|
||||
/*for (String s : connection.getHeaderFields().keySet()) {
|
||||
System.out.println(s+": "+connection.getHeaderFields().get(s));
|
||||
}*/
|
||||
connection.setRequestMethod("GET");
|
||||
//connection.setRequestProperty("Content-Type", "application/json");
|
||||
try {
|
||||
ReadableByteChannel rbc = Channels.newChannel(connection.getInputStream());
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
} catch (ConnectException e) {
|
||||
System.out.println("Failed to connect, moving on...");
|
||||
}
|
||||
}
|
||||
}
|
35
d4dj/src/main/java/sig/utils/GithubUtils.java
Normal file
@ -0,0 +1,35 @@
|
||||
package sig.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class GithubUtils {
|
||||
public static int getSizeOfFileFromLatestGithubCommit(String filename) {
|
||||
try {
|
||||
JSONObject data = FileUtils.readJsonFromUrl("https://api.github.com/repos/sigonasr2/sigIRCv2");
|
||||
String url = data.getString("commits_url").replace("{/sha}", "");
|
||||
JSONArray data_array = FileUtils.readJsonArrayFromUrl(url);
|
||||
JSONObject dat = data_array.getJSONObject(0);
|
||||
JSONObject datapoint1 = dat.getJSONObject("commit");
|
||||
datapoint1 = datapoint1.getJSONObject("tree");
|
||||
url = datapoint1.getString("url");
|
||||
data = FileUtils.readJsonFromUrl(url);
|
||||
data_array = data.getJSONArray("tree");
|
||||
for (int i=0;i<data_array.length();i++) {
|
||||
JSONObject file_data = data_array.getJSONObject(i);
|
||||
if (file_data.getString("path").equals(filename)) {
|
||||
return file_data.getInt("size");
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
94
d4dj/src/main/java/sig/utils/ImageUtils.java
Normal file
@ -0,0 +1,94 @@
|
||||
package sig.utils;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class ImageUtils {
|
||||
/**
|
||||
* Converts a given Image into a BufferedImage
|
||||
*
|
||||
* @param img The Image to be converted
|
||||
* @return The converted BufferedImage
|
||||
*/
|
||||
public static BufferedImage toCompatibleImage(BufferedImage image)
|
||||
{
|
||||
return image;
|
||||
}
|
||||
public static BufferedImage toBufferedImage(Image img)
|
||||
{
|
||||
if (img instanceof BufferedImage)
|
||||
{
|
||||
return (BufferedImage) img;
|
||||
}
|
||||
|
||||
// Create a buffered image with transparency
|
||||
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
// Draw the image on to the buffered image
|
||||
Graphics2D bGr = bimage.createGraphics();
|
||||
bGr.drawImage(img, 0, 0, null);
|
||||
bGr.dispose();
|
||||
|
||||
// Return the buffered image
|
||||
return bimage;
|
||||
}
|
||||
public static BufferedImage copyBufferedImage(BufferedImage img)
|
||||
{
|
||||
// Create a buffered image with transparency
|
||||
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
// Draw the image on to the buffered image
|
||||
Graphics2D bGr = bimage.createGraphics();
|
||||
bGr.drawImage(img, 0, 0, null);
|
||||
bGr.dispose();
|
||||
|
||||
// Return the buffered image
|
||||
return bimage;
|
||||
}
|
||||
public static BufferedImage cropImage(BufferedImage img,Rectangle offset)
|
||||
{
|
||||
// Create a buffered image with transparency
|
||||
BufferedImage bimage = new BufferedImage(offset.width, offset.height, BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
// Draw the image on to the buffered image
|
||||
Graphics2D bGr = bimage.createGraphics();
|
||||
bGr.drawImage(img, -offset.x, -offset.y, null);
|
||||
bGr.dispose();
|
||||
|
||||
// Return the buffered image
|
||||
return bimage;
|
||||
}
|
||||
public static BufferedImage copyBufferedImages(BufferedImage...img)
|
||||
{
|
||||
int widthSum=0;
|
||||
int maxHeight=0;
|
||||
|
||||
for (int i=0;i<img.length;i++) {
|
||||
widthSum+=img[i].getWidth();
|
||||
maxHeight=Math.max(maxHeight, img[i].getHeight());
|
||||
}
|
||||
|
||||
// Create a buffered image with transparency
|
||||
BufferedImage bimage = new BufferedImage(widthSum, maxHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
// Draw the image on to the buffered image
|
||||
Graphics2D bGr = bimage.createGraphics();
|
||||
int X=0;
|
||||
for (int i=0;i<img.length;i++) {
|
||||
bGr.drawImage(img[i], X, 0, null);
|
||||
X+=img[i].getWidth();
|
||||
}
|
||||
bGr.dispose();
|
||||
|
||||
// Return the buffered image
|
||||
return bimage;
|
||||
}
|
||||
public static double distanceToColor(Color p2, Color p1) {
|
||||
return Math.sqrt(Math.pow(p2.getRed()-p1.getRed(), 2)+Math.pow(p2.getGreen()-p1.getGreen(), 2)+Math.pow(p2.getBlue()-p1.getBlue(), 2));
|
||||
}
|
||||
}
|
39
d4dj/src/main/java/sig/utils/JavaUtils.java
Normal file
@ -0,0 +1,39 @@
|
||||
package sig.utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class JavaUtils {
|
||||
public JavaUtils clone() {
|
||||
JavaUtils newpos = new JavaUtils();
|
||||
for (Field f : this.getClass().getDeclaredFields()) {
|
||||
if (ReflectUtils.isCloneable(f)) {
|
||||
try {
|
||||
f.set(newpos, f.get(this));
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return newpos;
|
||||
}
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.getClass().getName()+"(");
|
||||
boolean first=true;
|
||||
for (Field f : this.getClass().getDeclaredFields()) {
|
||||
if (!first) {
|
||||
sb.append(",");
|
||||
}
|
||||
try {
|
||||
sb.append(f.getName()+"="+f.get(this));
|
||||
first=false;
|
||||
} catch (IllegalArgumentException|IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
10
d4dj/src/main/java/sig/utils/ReflectUtils.java
Normal file
@ -0,0 +1,10 @@
|
||||
package sig.utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ReflectUtils {
|
||||
public static boolean isCloneable(Field f) {
|
||||
int mods = f.getModifiers();
|
||||
return mods<8;
|
||||
}
|
||||
}
|
30
d4dj/src/main/java/sig/utils/SoundUtils.java
Normal file
@ -0,0 +1,30 @@
|
||||
package sig.utils;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
public class SoundUtils {
|
||||
public static void playSound(String filename) {
|
||||
AudioInputStream audioInputStream;
|
||||
try {
|
||||
audioInputStream = AudioSystem.getAudioInputStream(new File(filename).getAbsoluteFile());
|
||||
Clip clip;
|
||||
try {
|
||||
clip = AudioSystem.getClip();
|
||||
clip.open(audioInputStream);
|
||||
clip.start();
|
||||
} catch (LineUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (UnsupportedAudioFileException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
85
d4dj/src/main/java/sig/utils/TextUtils.java
Normal file
@ -0,0 +1,85 @@
|
||||
package sig.utils;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Point;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TextUtils {
|
||||
|
||||
public static String replaceFirst(String sourcestring, String findstring, String replacestring) {
|
||||
int pos = sourcestring.indexOf(findstring);
|
||||
if (pos>=0) {
|
||||
String piece1 = sourcestring.substring(0,pos);
|
||||
String piece2 = sourcestring.substring(pos+findstring.length(),sourcestring.length());
|
||||
//basemsg = basemsg.replaceFirst(e.getEmoteName(),e.getSpaceFiller());
|
||||
sourcestring = piece1+replacestring+piece2;
|
||||
}
|
||||
return sourcestring;
|
||||
}
|
||||
|
||||
public static boolean isAlphanumeric(String str) {
|
||||
return str.matches("^[a-zA-Z0-9!\\-.?'\":,\\+ ]+$");
|
||||
}
|
||||
|
||||
public static boolean isNumeric(String str)
|
||||
{
|
||||
if (str.length()>0) {
|
||||
return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isInteger(String s, int radix) {
|
||||
if(s.isEmpty()) return false;
|
||||
for(int i = 0; i < s.length(); i++) {
|
||||
if(i == 0 && s.charAt(i) == '-') {
|
||||
if(s.length() == 1) return false;
|
||||
else continue;
|
||||
}
|
||||
if(Character.digit(s.charAt(i),radix) < 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String convertSecondsToTimeFormat(int seconds) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int sec = seconds%60;
|
||||
int min = (seconds/60)%60;
|
||||
int hrs = (seconds/3600)%24;
|
||||
if (hrs>0) {
|
||||
if (hrs>=10) {
|
||||
sb.append(hrs);
|
||||
} else {
|
||||
sb.append(0);
|
||||
sb.append(hrs);
|
||||
}
|
||||
sb.append(":");
|
||||
}
|
||||
if (min>=10) {
|
||||
sb.append(min);
|
||||
} else {
|
||||
sb.append(0);
|
||||
sb.append(min);
|
||||
}
|
||||
sb.append(":");
|
||||
if (sec>=10) {
|
||||
sb.append(sec);
|
||||
} else {
|
||||
sb.append(0);
|
||||
sb.append(sec);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a three CSV value to RGB value.
|
||||
*/
|
||||
public static Color convertStringToColor(String col) {
|
||||
String[] split = col.split(",");
|
||||
return new Color(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2]));
|
||||
}
|
||||
}
|
32
d4dj/src/main/java/sig/utils/TimeUtils.java
Normal file
@ -0,0 +1,32 @@
|
||||
package sig.utils;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class TimeUtils {
|
||||
public static String GetTimeDifferenceFromCurrentDate(Date pastDate) {
|
||||
long totalseconds = (Calendar.getInstance().getTimeInMillis()-pastDate.getTime())/1000;
|
||||
//System.out.println("Total Seconds: "+totalseconds);
|
||||
long seconds = (long)(totalseconds);
|
||||
long minutes = (long)(seconds/60);
|
||||
long hours = (long)(minutes/60);
|
||||
long days = (long)(hours/24);
|
||||
StringBuilder string = new StringBuilder();
|
||||
DecimalFormat df = new DecimalFormat("00");
|
||||
if (days>0) {
|
||||
string.append(days);
|
||||
}
|
||||
if (hours>0) {
|
||||
string.append(((string.length()>0)?":":"")+(hours%24));
|
||||
}
|
||||
if (minutes>0) {
|
||||
string.append(((string.length()>0)?":":"")+df.format((minutes%60)));
|
||||
}
|
||||
if (seconds>0) {
|
||||
string.append(((string.length()>0)?":":"")+df.format((seconds%60)));
|
||||
}
|
||||
return string.toString();
|
||||
}
|
||||
}
|
124
d4dj/src/main/resources/readme.html
Normal file
@ -0,0 +1,124 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Tess4J - Java Wrapper for Tesseract OCR API</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="Section1">
|
||||
<h2 align="center">
|
||||
Tess4J
|
||||
</h2>
|
||||
<h3>
|
||||
DESCRIPTION
|
||||
</h3>
|
||||
<p>
|
||||
Tess4J is a JNA wrapper for <a href="https://github.com/tesseract-ocr">Tesseract OCR
|
||||
API</a>; it provides character recognition support for common image formats,
|
||||
multi-page images, and PDF documents. The library has been developed and tested
|
||||
on Windows and Linux.
|
||||
</p>
|
||||
<p>
|
||||
Tess4J is released and distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html">
|
||||
Apache License, v2.0</a>. Its official homepage is at <a href="http://tess4j.sourceforge.net/">
|
||||
http://tess4j.sourceforge.net</a>.
|
||||
</p>
|
||||
<h3>
|
||||
SOFTWARE REQUIREMENTS
|
||||
</h3>
|
||||
<p>
|
||||
<a href="http://java.oracle.com/">Java Runtime Environment</a>, <a href="https://github.com/twall/jna">
|
||||
JNA</a>, and <a href="https://java.net/projects/jai-imageio">JAI-ImageIO</a>
|
||||
are required. <a href="http://maven.apache.org/">Apache Maven</a> and <a href="http://www.junit.org/">
|
||||
JUnit</a> are used for program building and unit testing. The Tesseract DLLs
|
||||
were built with VS2019 (v142) and therefore depend on the <a href="https://visualstudio.microsoft.com/downloads/">
|
||||
Visual C++ 2019 Redistributable Packages</a>.
|
||||
</p>
|
||||
<h3>
|
||||
INSTRUCTIONS
|
||||
</h3>
|
||||
<p>
|
||||
Tesseract 5.0.0 and Leptonica 1.79 (via Lept4J) 32- and 64-bit
|
||||
DLLs, language data for English, and sample images are bundled with the library.
|
||||
<a href="https://github.com/tesseract-ocr/tessdata">Language data packs</a> for
|
||||
Tesseract should be decompressed and placed into the <code>tessdata</code> folder.
|
||||
</p>
|
||||
<p>
|
||||
The Linux shared object library (<code>libtesseract.so</code>) equivalent to the
|
||||
DLL is available in Tesseract 5.0.0, which can be built from the <a href="https://github.com/tesseract-ocr/tesseract"
|
||||
target="_blank">source</a> with the instructions given in <a href="https://tesseract-ocr.github.io/tessdoc/Compiling"
|
||||
target="_blank">Tesseract Wiki</a>.
|
||||
</p>
|
||||
<p>
|
||||
To unit test, at the command line, execute:
|
||||
</p>
|
||||
<blockquote>
|
||||
<p>
|
||||
<code>mvn test</code>
|
||||
</p>
|
||||
</blockquote>
|
||||
<p>
|
||||
Support for PDF documents is available through either
|
||||
<a href="http://www.ghostscript.com/" target="_blank">GPL Ghostscript</a>, which should be installed and included
|
||||
in system path, or PDFBox, if Ghostscript is not available.
|
||||
</p>
|
||||
<p>
|
||||
Images to be OCRed should be scanned at resolution from at least 200 DPI (dot per
|
||||
inch) to 400 DPI in monochrome (black&white) or grayscale. Scanning at higher
|
||||
resolutions will not necessarily result in better recognition accuracy. The actual
|
||||
success rates depend greatly on the quality of the scanned image. The typical settings
|
||||
for scanning are 300 DPI and 1 bpp (bit per pixel) black&white or 8 bpp grayscale
|
||||
uncompressed TIFF or PNG format. PNG is usually smaller in size than other image
|
||||
formats and still keeps high quality due to its employing lossless data compression
|
||||
algorithms; TIFF has the advantage of the ability to contain multiple images (pages)
|
||||
in a file.
|
||||
</p>
|
||||
<p>
|
||||
Several built-in functions are also provided for merging several images or PDF files
|
||||
into a single one for convenient OCR operations, or for splitting a PDF file into
|
||||
smaller ones if it is too large, which can cause out-of-memory exceptions.
|
||||
</p>
|
||||
<h3>
|
||||
CODE EXAMPLES
|
||||
</h3>
|
||||
<p>
|
||||
The following code example shows common usage of the library. Make sure <code>tessdata</code>
|
||||
folder is populated with appropriate language data files and the <code>.jar</code>
|
||||
files are in the classpath. On Windows, the DLLs will be automatically extracted
|
||||
from <code>tess4j.jar</code> to the default temporary directory and loaded.
|
||||
</p>
|
||||
<blockquote>
|
||||
<pre>
|
||||
package net.sourceforge.tess4j.example;
|
||||
|
||||
import java.io.File;
|
||||
import net.sourceforge.tess4j.*;
|
||||
|
||||
public class TesseractExample {
|
||||
public static void main(String[] args) {
|
||||
// ImageIO.scanForPlugins(); // for server environment
|
||||
File imageFile = new File("eurotext.tif");
|
||||
ITesseract instance = new Tesseract(); // JNA Interface Mapping
|
||||
// ITesseract instance = new Tesseract1(); // JNA Direct Mapping
|
||||
// File tessDataFolder = LoadLibs.extractTessResources("tessdata"); // Maven build only; only English data bundled
|
||||
// instance.setDatapath(tessDataFolder.getPath());
|
||||
|
||||
try {
|
||||
String result = instance.doOCR(imageFile);
|
||||
System.out.println(result);
|
||||
} catch (TesseractException e) {
|
||||
System.err.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h3>
|
||||
DOCUMENTATIONS
|
||||
</h3>
|
||||
<p>
|
||||
Please visit the website for the library's <a href="http://tess4j.sf.net/docs/">documentations</a>
|
||||
</p>
|
||||
<hr />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1
d4dj/src/main/resources/tessdata/configs/alto
Normal file
@ -0,0 +1 @@
|
||||
tessedit_create_alto 1
|
1
d4dj/src/main/resources/tessdata/configs/api_config
Normal file
@ -0,0 +1 @@
|
||||
tessedit_zero_rejection T
|
4
d4dj/src/main/resources/tessdata/configs/bazaar
Normal file
@ -0,0 +1,4 @@
|
||||
load_system_dawg F
|
||||
load_freq_dawg F
|
||||
user_words_suffix user-words
|
||||
user_patterns_suffix user-patterns
|
1
d4dj/src/main/resources/tessdata/configs/digits
Normal file
@ -0,0 +1 @@
|
||||
tessedit_char_whitelist 0123456789-.
|
2
d4dj/src/main/resources/tessdata/configs/hocr
Normal file
@ -0,0 +1,2 @@
|
||||
tessedit_create_hocr 1
|
||||
hocr_font_info 0
|
1
d4dj/src/main/resources/tessdata/configs/lstmbox
Normal file
@ -0,0 +1 @@
|
||||
tessedit_create_lstmbox 1
|
1
d4dj/src/main/resources/tessdata/configs/pdf
Normal file
@ -0,0 +1 @@
|
||||
tessedit_create_pdf 1
|
1
d4dj/src/main/resources/tessdata/configs/quiet
Normal file
@ -0,0 +1 @@
|
||||
debug_file /dev/null
|
1
d4dj/src/main/resources/tessdata/configs/tsv
Normal file
@ -0,0 +1 @@
|
||||
tessedit_create_tsv 1
|
3
d4dj/src/main/resources/tessdata/configs/txt
Normal file
@ -0,0 +1,3 @@
|
||||
# This config file should be used with other cofig files which creates renderers.
|
||||
# usage example: tesseract eurotext.tif eurotext txt hocr pdf
|
||||
tessedit_create_txt 1
|
2
d4dj/src/main/resources/tessdata/configs/unlv
Normal file
@ -0,0 +1,2 @@
|
||||
tessedit_write_unlv 1
|
||||
unlv_tilde_crunching T
|
1
d4dj/src/main/resources/tessdata/configs/wordstrbox
Normal file
@ -0,0 +1 @@
|
||||
tessedit_create_wordstrbox 1
|
BIN
d4dj/src/main/resources/tessdata/eng.traineddata
Normal file
BIN
d4dj/src/main/resources/tessdata/osd.traineddata
Normal file
BIN
d4dj/src/main/resources/tessdata/pdf.ttf
Normal file
199
d4dj/src/main/resources/versionchanges.txt
Normal file
@ -0,0 +1,199 @@
|
||||
Tess4J Change Summary
|
||||
|
||||
Version 0.1 - initial release (14 Aug 2010):
|
||||
- Java JNA-based wrapper for Tesseract OCR DLL 2.04
|
||||
- Support uncompressed, binary TIFF images
|
||||
|
||||
Version 0.2 (16 Aug 2010):
|
||||
- Add support for more image formats (PNG, BMP, GIF, PDF, JPEG)
|
||||
- Add support for compressed, grayscale and colored images
|
||||
|
||||
Version 0.3 (22 Aug 2010):
|
||||
- Include API support for BufferedImage
|
||||
- Clean up codes. Remove unsupported API and files
|
||||
- Document the API
|
||||
|
||||
Version 0.3.1 (26 Aug 2010):
|
||||
- Send only pixel data, not whole image data, to Tesseract engine, to fix a bug that has erroneously put some words at beginning of line towards end of line
|
||||
|
||||
Version 0.4 (1 Nov 2010):
|
||||
- Add JNA Direct Mapping calls, which can provide performance near that of custom JNI
|
||||
|
||||
Version 1.0 (30 October 2012):
|
||||
- Upgrade to Tesseract 3.02 (r798), which is not backward compatible with Tesseract 2.04.
|
||||
- Implement a new JNA wrapper for the new Tesseract OCR API
|
||||
- Add more unit test cases
|
||||
- Update documentation
|
||||
|
||||
Version 1.1 (3 March 2013)
|
||||
- Update Tesseract DLL to r828
|
||||
- Additional API methods, image helper methods, and unit test cases
|
||||
- Improve handling of Unicode character encoding
|
||||
- Fix memory leaks
|
||||
- Add support for determining skew angle and image rotation
|
||||
|
||||
Version 1.2 (22 September 2013)
|
||||
- Update Tesseract DLL to r866
|
||||
- More efficient OCR of multiple images
|
||||
- Various minor improvements
|
||||
- Update JNA to v4.0
|
||||
|
||||
Version 1.3 (31 May 2014)
|
||||
- Update JNA to v4.1.0
|
||||
- Update Ghost4J to v0.5.1
|
||||
- Refactoring
|
||||
- Bundle Tesseract and Leptonica 64-bit DLLs
|
||||
|
||||
Version 1.4 (18 January 2015)
|
||||
- Refactor to reduce code duplication
|
||||
- Embed Windows native resources in JAR
|
||||
- Autoload Windows native libraries
|
||||
|
||||
Version 1.4.1 (24 January 2015)
|
||||
- Enable use of jna.library.path system property for user-customizable path
|
||||
|
||||
Version 1.5 (13 March 2015)
|
||||
- Add UNLV zone file support
|
||||
- Refactor
|
||||
|
||||
Version 2.0 (29 March 2015)
|
||||
- Upgrade to Tesseract 3.03 (r1050), which is compatible with Tesseract 3.03RC on Linux
|
||||
- Refactor Tesseract class for extensibility and thread-safety
|
||||
- Update English language data for Tesseract 3.02
|
||||
|
||||
Version 3.0 (25 December 2015)
|
||||
- Upgrade to Tesseract 3.04 (953523b)
|
||||
- Include Lept4J library
|
||||
- Incorporate slf4j and logback libraries for logging
|
||||
- Make GhostScript calls thread safe
|
||||
|
||||
Version 3.1 (21 March 2016)
|
||||
- Update Tesseract to 3.04.01 (4ef68a0)
|
||||
- Use Lept4J-1.1.2 (Leptonica 1.72)
|
||||
- Update JNA to 4.2.2
|
||||
- Update Ghost4J to 1.0.1
|
||||
- Delete ResultRenderer after use to release PDF file handler
|
||||
|
||||
Version 3.2 (15 May 2016)
|
||||
- Revert JNA to 4.1.0 due to "Invalid calling convention 63" errors invoking GhostScript via Ghost4J on Linux
|
||||
- Update Lept4J to 1.2.2 (Leptonica 1.73)
|
||||
- Recompile Tesseract 3.04.01 DLL against Leptonica 1.73
|
||||
- Update GhostScript Windows binary to 9.19
|
||||
|
||||
Version 3.2.1 (29 May 2016)
|
||||
- Properly release Box and Boxa resources
|
||||
- Update Lept4J to 1.2.3
|
||||
|
||||
Version 3.2.2 (16 February 2017)
|
||||
- Update GhostScript to 9.20
|
||||
- Fix possible NPE with PDF-related codes
|
||||
- Update dependencies
|
||||
- Additional image utility methods
|
||||
|
||||
Version 3.3.0 (16 February 2017)
|
||||
- Upgrade to Tesseract 3.05 (2ca5d0a)
|
||||
- Update Lept4J to 1.3.0 (Leptonica 1.74.1)
|
||||
|
||||
Version 3.3.1 (23 March 2017)
|
||||
- Update Lept4J to 1.3.1
|
||||
- Update other dependencies
|
||||
|
||||
Version 3.4.0 (1 June 2017)
|
||||
- Upgrade to Tesseract 3.05.01 (2158661)
|
||||
- Update Lept4J to 1.4.0
|
||||
- Add support for jboss-vfs protocol
|
||||
|
||||
Version 3.4.1 (22 September 2017)
|
||||
- Not extract/copy native resource if it exists and has same file size
|
||||
- Update Tesseract 3.05.01 (e2e79c4); link against Leptonica 1.74.4
|
||||
- Update Lept4J to 1.6.1
|
||||
|
||||
Version 3.4.2 (14 November 2017)
|
||||
- Update Lept4J to 1.6.2
|
||||
- Update GhostScript to 9.22
|
||||
- Improve handling of PDF files in multi-threaded environment
|
||||
- Lift limits on number of pages in PDF
|
||||
- Use TESSDATA_PREFIX environment variable by default, if defined
|
||||
|
||||
Version 3.4.3 (14 January 2018)
|
||||
- Not extract/copy resource if it exists and has same file size
|
||||
|
||||
Version 3.4.4 (22 February 2018)
|
||||
- Exclude logback.xml from JAR
|
||||
- Add image rotate and deskew methods
|
||||
- Update Lept4J to 1.6.3
|
||||
|
||||
Version 3.4.5 (21 March 2018)
|
||||
- Remove GS DLL due to license incompatibility
|
||||
- Use PDFBox
|
||||
|
||||
Version 3.4.6 (25 March 2018)
|
||||
- Update PDFBox dependencies
|
||||
|
||||
Version 3.4.7 (16 April 2018)
|
||||
- Update dependencies for Java 9 fixes
|
||||
|
||||
Version 3.4.8 (2 May 2018)
|
||||
- Fix a path issue when extracting resources from JAR to temp directory on Windows server
|
||||
|
||||
Version 4.0.0 (28 April 2018)
|
||||
- Upgrade to Tesseract 4.0.0-beta.1 (45bb942)
|
||||
- Update Lept4J to 1.9.3 (Leptonica 1.75.3)
|
||||
|
||||
Version 4.0.1 (2 May 2018)
|
||||
- Fix a path issue when extracting resources from JAR to temp directory on Windows server
|
||||
|
||||
Version 4.0.2 (3 May 2018)
|
||||
- Replace JNA string constant Platform.RESOURCE_PREFIX
|
||||
- Update jai-imageio url
|
||||
- Update Lept4J to 1.9.4
|
||||
|
||||
Version 4.1.0 (20 July 2018)
|
||||
- Upgrade to Tesseract 4.0.0-beta.3 (b502bbf)
|
||||
- Update Lept4J to 1.10.0
|
||||
- Improve handling of PDF
|
||||
- Refactor
|
||||
|
||||
Version 4.1.1 (28 July 2018)
|
||||
- Properly dispose of resources and temporary image files
|
||||
- Clean up code and test output resources
|
||||
- Fix NPE in Java 10
|
||||
|
||||
Version 4.2.0 (11 August 2018)
|
||||
- Upgrade to Tesseract 4.0.0-beta.4 (fd49206)
|
||||
|
||||
Version 4.2.1 (11 August 2018)
|
||||
- Recompile using JDK8 to avoid NoSuchMethodError: Method flip() does not exist in class java.nio.ByteBuffer
|
||||
- Use explicit cast for compatibility with covariant return type on JDK 9's ByteBuffer methods, e.g., flip()
|
||||
|
||||
Version 4.2.2 (3 September 2018)
|
||||
- Fix Invalid memory access exception due of incorrect bit depth value
|
||||
|
||||
Version 4.2.3 (17 October 2018)
|
||||
- Update pdfbox dependencies
|
||||
|
||||
Version 4.3.0 (29 October 2018)
|
||||
- Upgrade to Tesseract 4.0.0 (5131699)
|
||||
|
||||
Version 4.3.1 (26 December 2018)
|
||||
- Fix Windows build
|
||||
- Improve RenderedImage to ByteBuffer conversion
|
||||
|
||||
Version 4.4.0 (13 July 2019)
|
||||
- Upgrade to Tesseract 4.1.0 (5280bbc)
|
||||
- Upgrade to Leptonica 1.78.0 (lept4j-1.12.2)
|
||||
- Update dependencies
|
||||
|
||||
Version 4.4.1 (7 October 2019)
|
||||
- Use tessdata_fast data
|
||||
- Use Native.loadLibrary method for backward compatibility with older JNA versions
|
||||
|
||||
Version 4.5.0 (27 December 2019)
|
||||
- Upgrade to Tesseract 4.1.1 (7510304)
|
||||
|
||||
Version 4.5.1 (3 January 2020)
|
||||
- Update Leptonica 1.79.0 (lept4j-1.13.0)
|
||||
- Fix Permission denied issue with Ghostscript 9.50
|
||||
|
||||
Version 5.0.0-SNAPSHOT (11 July 2020)
|
||||
- Upgrade to Tesseract 5.0.0-alpha (135c8a4)
|
BIN
d4dj/src/main/resources/win32-x86-64/libtesseract500.dll
Normal file
BIN
d4dj/src/main/resources/win32-x86/libtesseract500.dll
Normal file
20
d4dj/src/test/java/d4dj/d4dj/AppTest.java
Normal file
@ -0,0 +1,20 @@
|
||||
package d4dj.d4dj;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class AppTest
|
||||
{
|
||||
/**
|
||||
* Rigorous Test :-)
|
||||
*/
|
||||
@Test
|
||||
public void shouldAnswerWithTrue()
|
||||
{
|
||||
assertTrue( true );
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright @ 2014 Quan Nguyen
|
||||
*
|
||||
* 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 net.sourceforge.tess4j;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import net.sourceforge.tess4j.util.LoggHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static net.sourceforge.tess4j.ITessAPI.TRUE;
|
||||
|
||||
class ProgressMonitor extends Thread {
|
||||
|
||||
ITessAPI.ETEXT_DESC monitor;
|
||||
StringBuilder outputMessage = new StringBuilder();
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
|
||||
public ProgressMonitor(ITessAPI.ETEXT_DESC monitor) {
|
||||
this.monitor = monitor;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return outputMessage.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
logger.info("ocr alive: " + (monitor.ocr_alive == TRUE));
|
||||
logger.info("progress: " + monitor.progress);
|
||||
outputMessage.append(monitor.more_to_come);
|
||||
if (monitor.progress >= 100) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (Exception ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels OCR operation.
|
||||
*/
|
||||
public void cancel() {
|
||||
monitor.cancel = new ITessAPI.CANCEL_FUNC() {
|
||||
@Override
|
||||
public boolean invoke(Pointer cancel_this, int words) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets cancel flag.
|
||||
*/
|
||||
public void reset() {
|
||||
monitor.cancel = null;
|
||||
}
|
||||
}
|
704
d4dj/src/test/java/net/sourceforge/tess4j/TessAPI1Test.java
Normal file
@ -0,0 +1,704 @@
|
||||
/**
|
||||
* Copyright @ 2012 Quan Nguyen
|
||||
*
|
||||
* 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 net.sourceforge.tess4j;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import net.sourceforge.tess4j.util.LoggHelper;
|
||||
import net.sourceforge.tess4j.util.Utils;
|
||||
import net.sourceforge.tess4j.util.ImageIOHelper;
|
||||
|
||||
import com.ochafik.lang.jnaerator.runtime.NativeSize;
|
||||
import com.sun.jna.NativeLong;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.StringArray;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import net.sourceforge.lept4j.Box;
|
||||
import net.sourceforge.lept4j.Boxa;
|
||||
import static net.sourceforge.lept4j.ILeptonica.L_CLONE;
|
||||
import net.sourceforge.lept4j.Leptonica1;
|
||||
import net.sourceforge.lept4j.Pix;
|
||||
import net.sourceforge.lept4j.util.LeptUtils;
|
||||
|
||||
import net.sourceforge.tess4j.ITessAPI.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static net.sourceforge.tess4j.ITessAPI.FALSE;
|
||||
import static net.sourceforge.tess4j.ITessAPI.TRUE;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TessAPI1Test {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
private final String datapath = "src/main/resources/tessdata";
|
||||
private final String testResourcesDataPath = "src/test/resources/test-data";
|
||||
String language = "eng";
|
||||
String expOCRResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
|
||||
TessBaseAPI handle;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
handle = TessAPI1.TessBaseAPICreate();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
TessAPI1.TessBaseAPIDelete(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIRect method, of class TessAPI1.
|
||||
*
|
||||
* @throws Exception while processing the image
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIRect() throws Exception {
|
||||
logger.info("TessBaseAPIRect");
|
||||
String expResult = expOCRResult;
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage image = ImageIO.read(tiff); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
Pointer utf8Text = TessAPI1.TessBaseAPIRect(handle, buf, bytespp, bytespl, 0, 0, image.getWidth(), image.getHeight());
|
||||
String result = utf8Text.getString(0);
|
||||
TessAPI1.TessDeleteText(utf8Text);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetUTF8Text method, of class TessAPI1.
|
||||
*
|
||||
* @throws Exception while processing the image
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetUTF8Text() throws Exception {
|
||||
logger.info("TessBaseAPIGetUTF8Text");
|
||||
String expResult = expOCRResult;
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff)); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
TessAPI1.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
TessAPI1.TessBaseAPISetRectangle(handle, 0, 0, 1024, 800);
|
||||
Pointer utf8Text = TessAPI1.TessBaseAPIGetUTF8Text(handle);
|
||||
String result = utf8Text.getString(0);
|
||||
TessAPI1.TessDeleteText(utf8Text);
|
||||
logger.info(result);
|
||||
assertTrue(result.startsWith(expResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetUTF8Text method, of class TessAPI1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetUTF8Text_Pix() throws Exception {
|
||||
logger.info("TessBaseAPIGetUTF8Text_Pix");
|
||||
String expResult = expOCRResult;
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
Pix pix = Leptonica1.pixRead(tiff.getPath());
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetImage2(handle, pix);
|
||||
Pointer utf8Text = TessAPI1.TessBaseAPIGetUTF8Text(handle);
|
||||
String result = utf8Text.getString(0);
|
||||
TessAPI1.TessDeleteText(utf8Text);
|
||||
logger.info(result);
|
||||
|
||||
//release Pix resource
|
||||
PointerByReference pRef = new PointerByReference();
|
||||
pRef.setValue(pix.getPointer());
|
||||
Leptonica1.pixDestroy(pRef);
|
||||
|
||||
assertTrue(result.startsWith(expResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetComponentImages method, of class TessAPI1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetComponentImages() throws Exception {
|
||||
logger.info("TessBaseAPIGetComponentImages");
|
||||
File image = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
int expResult = 12; // number of lines in the test image
|
||||
Pix pix = Leptonica1.pixRead(image.getPath());
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetImage2(handle, pix);
|
||||
PointerByReference pixa = null;
|
||||
PointerByReference blockids = null;
|
||||
Boxa boxes = TessAPI1.TessBaseAPIGetComponentImages(handle, TessPageIteratorLevel.RIL_TEXTLINE, TRUE, pixa, blockids);
|
||||
// boxes = TessAPI1.TessBaseAPIGetRegions(handle, pixa); // equivalent to TessPageIteratorLevel.RIL_BLOCK
|
||||
int boxCount = Leptonica1.boxaGetCount(boxes);
|
||||
for (int i = 0; i < boxCount; i++) {
|
||||
Box box = Leptonica1.boxaGetBox(boxes, i, L_CLONE);
|
||||
if (box == null) {
|
||||
continue;
|
||||
}
|
||||
TessAPI1.TessBaseAPISetRectangle(handle, box.x, box.y, box.w, box.h);
|
||||
Pointer utf8Text = TessAPI1.TessBaseAPIGetUTF8Text(handle);
|
||||
String ocrResult = utf8Text.getString(0);
|
||||
TessAPI1.TessDeleteText(utf8Text);
|
||||
int conf = TessAPI1.TessBaseAPIMeanTextConf(handle);
|
||||
System.out.print(String.format("Box[%d]: x=%d, y=%d, w=%d, h=%d, confidence: %d, text: %s", i, box.x, box.y, box.w, box.h, conf, ocrResult));
|
||||
LeptUtils.dispose(box);
|
||||
}
|
||||
|
||||
// release Pix and Boxa resources
|
||||
LeptUtils.dispose(pix);
|
||||
LeptUtils.dispose(boxes);
|
||||
|
||||
assertEquals(expResult, boxCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessVersion method, of class TessAPI1.
|
||||
*/
|
||||
@Test
|
||||
public void testTessVersion() {
|
||||
logger.info("TessVersion");
|
||||
String expResult = "5.0.0";
|
||||
String result = TessAPI1.TessVersion();
|
||||
logger.info(result);
|
||||
assertTrue(result.startsWith(expResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPISetVariable method, of class TessAPI1.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPISetVariable() {
|
||||
logger.info("TessBaseAPISetVariable");
|
||||
String name = "tessedit_create_hocr";
|
||||
String value = "1";
|
||||
int expResult = 1;
|
||||
int result = TessAPI1.TessBaseAPISetVariable(handle, name, value);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetBoolVariable method, of class TessAPI1.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetBoolVariable() {
|
||||
logger.info("TessBaseAPIGetBoolVariable");
|
||||
String name = "tessedit_create_hocr";
|
||||
TessAPI1.TessBaseAPISetVariable(handle, name, "1");
|
||||
IntBuffer value = IntBuffer.allocate(1);
|
||||
int result = -1;
|
||||
if (TessAPI1.TessBaseAPIGetBoolVariable(handle, "tessedit_create_hocr", value) == TRUE) {
|
||||
result = value.get(0);
|
||||
}
|
||||
int expResult = 1;
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIPrintVariables method, of class TessAPI1.
|
||||
*
|
||||
* @throws Exception while persisting variables into a file.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIPrintVariablesToFile() throws Exception {
|
||||
logger.info("TessBaseAPIPrintVariablesToFile");
|
||||
String var = "tessedit_char_whitelist";
|
||||
String value = "0123456789";
|
||||
TessAPI1.TessBaseAPISetVariable(handle, var, value);
|
||||
String filename = "printvar.txt";
|
||||
TessAPI1.TessBaseAPIPrintVariablesToFile(handle, filename); // will crash if not invoked after some method
|
||||
File file = new File(filename);
|
||||
BufferedReader input = new BufferedReader(new FileReader(file));
|
||||
StringBuilder strB = new StringBuilder();
|
||||
String line;
|
||||
String EOL = System.getProperty("line.separator");
|
||||
while ((line = input.readLine()) != null) {
|
||||
strB.append(line).append(EOL);
|
||||
}
|
||||
input.close();
|
||||
file.delete();
|
||||
assertTrue(strB.toString().contains(var + "\t" + value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIInit4 method, of class TessAPI1.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIInit4() {
|
||||
logger.info("TessBaseAPIInit4");
|
||||
int oem = TessOcrEngineMode.OEM_DEFAULT;
|
||||
PointerByReference configs = null;
|
||||
int configs_size = 0;
|
||||
// disable loading dictionaries
|
||||
String[] args = new String[]{"load_system_dawg", "load_freq_dawg"};
|
||||
StringArray sarray = new StringArray(args);
|
||||
PointerByReference vars_vec = new PointerByReference();
|
||||
vars_vec.setPointer(sarray);
|
||||
|
||||
args = new String[]{"F", "F"};
|
||||
sarray = new StringArray(args);
|
||||
PointerByReference vars_values = new PointerByReference();
|
||||
vars_values.setPointer(sarray);
|
||||
|
||||
NativeSize vars_vec_size = new NativeSize(args.length);
|
||||
|
||||
int expResult = 0;
|
||||
int result = TessAPI1.TessBaseAPIInit4(handle, datapath, language, oem, configs, configs_size, vars_vec, vars_values, vars_vec_size, FALSE);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetInitLanguagesAsString method, of class TessAPI1.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetInitLanguagesAsString() {
|
||||
logger.info("TessBaseAPIGetInitLanguagesAsString");
|
||||
String expResult = "";
|
||||
String result = TessAPI1.TessBaseAPIGetInitLanguagesAsString(handle);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetLoadedLanguagesAsVector method, of class TessAPI1.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetLoadedLanguagesAsVector() {
|
||||
logger.info("TessBaseAPIGetLoadedLanguagesAsVector");
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
String[] expResult = {"eng"};
|
||||
String[] result = TessAPI1.TessBaseAPIGetLoadedLanguagesAsVector(handle).getPointer().getStringArray(0);
|
||||
assertArrayEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetAvailableLanguagesAsVector method, of class
|
||||
* TessAPI1.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetAvailableLanguagesAsVector() {
|
||||
logger.info("TessBaseAPIGetAvailableLanguagesAsVector");
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
String[] expResult = {"eng"};
|
||||
String[] result = TessAPI1.TessBaseAPIGetAvailableLanguagesAsVector(handle).getPointer().getStringArray(0);
|
||||
assertTrue(Arrays.asList(result).containsAll(Arrays.asList(expResult)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetHOCRText method, of class TessAPI1.
|
||||
*
|
||||
* @throws Exception while getting ocr text from image.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetHOCRText() throws Exception {
|
||||
logger.info("TessBaseAPIGetHOCRText");
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff)); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
TessAPI1.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
int page_number = 0;
|
||||
Pointer utf8Text = TessAPI1.TessBaseAPIGetHOCRText(handle, page_number);
|
||||
String result = utf8Text.getString(0);
|
||||
TessAPI1.TessDeleteText(utf8Text);
|
||||
assertTrue(result.contains("<div class='ocr_page'"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetAltoText method, of class TessAPI.
|
||||
*
|
||||
* @throws Exception while getting Alto text
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetAltoText() throws Exception {
|
||||
logger.info("TessBaseAPIGetAltoText");
|
||||
String filename = String.format("%s/%s", this.testResourcesDataPath, "eurotext.tif");
|
||||
File tiff = new File(filename);
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff));
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
TessAPI1.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
int page_number = 0;
|
||||
Pointer textPtr = TessAPI1.TessBaseAPIGetAltoText(handle, page_number);
|
||||
String result = textPtr.getString(0);
|
||||
TessAPI1.TessDeleteText(textPtr);
|
||||
assertTrue(result.contains("<Page WIDTH=\"1024\" HEIGHT=\"800\" PHYSICAL_IMG_NR=\"0\" ID=\"page_0\">"));
|
||||
|
||||
// WordStr Box output
|
||||
textPtr = TessAPI1.TessBaseAPIGetWordStrBoxText(handle, page_number);
|
||||
result = textPtr.getString(0);
|
||||
TessAPI1.TessDeleteText(textPtr);
|
||||
assertTrue(result.contains("WordStr"));
|
||||
|
||||
// TSV output
|
||||
textPtr = TessAPI1.TessBaseAPIGetTsvText(handle, page_number);
|
||||
result = textPtr.getString(0);
|
||||
TessAPI1.TessDeleteText(textPtr);
|
||||
assertTrue(result.contains("1\t"));
|
||||
|
||||
// LSTM Box output
|
||||
textPtr = TessAPI1.TessBaseAPIGetLSTMBoxText(handle, page_number);
|
||||
result = textPtr.getString(0);
|
||||
TessAPI1.TessDeleteText(textPtr);
|
||||
assertTrue(result.contains("\t"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIAnalyseLayout method, of class TessAPI1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIAnalyseLayout() throws Exception {
|
||||
logger.info("TessBaseAPIAnalyseLayout");
|
||||
File image = new File(testResourcesDataPath, "eurotext.png");
|
||||
int expResult = 12; // number of lines in the test image
|
||||
Pix pix = Leptonica1.pixRead(image.getPath());
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetImage2(handle, pix);
|
||||
int pageIteratorLevel = TessPageIteratorLevel.RIL_TEXTLINE;
|
||||
logger.info("PageIteratorLevel: " + Utils.getConstantName(pageIteratorLevel, TessPageIteratorLevel.class));
|
||||
int i = 0;
|
||||
TessPageIterator pi = TessAPI1.TessBaseAPIAnalyseLayout(handle);
|
||||
|
||||
do {
|
||||
IntBuffer leftB = IntBuffer.allocate(1);
|
||||
IntBuffer topB = IntBuffer.allocate(1);
|
||||
IntBuffer rightB = IntBuffer.allocate(1);
|
||||
IntBuffer bottomB = IntBuffer.allocate(1);
|
||||
TessAPI1.TessPageIteratorBoundingBox(pi, pageIteratorLevel, leftB, topB, rightB, bottomB);
|
||||
int left = leftB.get();
|
||||
int top = topB.get();
|
||||
int right = rightB.get();
|
||||
int bottom = bottomB.get();
|
||||
logger.info(String.format("Box[%d]: x=%d, y=%d, w=%d, h=%d", i++, left, top, right - left, bottom - top));
|
||||
} while (TessAPI1.TessPageIteratorNext(pi, pageIteratorLevel) == TRUE);
|
||||
TessAPI1.TessPageIteratorDelete(pi);
|
||||
PointerByReference pRef = new PointerByReference();
|
||||
pRef.setValue(pix.getPointer());
|
||||
Leptonica1.pixDestroy(pRef);
|
||||
assertEquals(expResult, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIDetectOrientationScript method, of class TessAPI1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIDetectOrientationScript() throws Exception {
|
||||
logger.info("TessBaseAPIDetectOrientationScript");
|
||||
File image = new File(testResourcesDataPath, "eurotext90.png");
|
||||
int expResult = TRUE;
|
||||
Pix pix = Leptonica1.pixRead(image.getPath());
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, "osd");
|
||||
TessAPI1.TessBaseAPISetImage2(handle, pix);
|
||||
|
||||
IntBuffer orient_degB = IntBuffer.allocate(1);
|
||||
FloatBuffer orient_confB = FloatBuffer.allocate(1);
|
||||
PointerByReference script_nameB = new PointerByReference();
|
||||
FloatBuffer script_confB = FloatBuffer.allocate(1);
|
||||
|
||||
int result = TessAPI1.TessBaseAPIDetectOrientationScript(handle, orient_degB, orient_confB, script_nameB, script_confB);
|
||||
if (result == TRUE) {
|
||||
int orient_deg = orient_degB.get();
|
||||
float orient_conf = orient_confB.get();
|
||||
String script_name = script_nameB.getValue().getString(0);
|
||||
float script_conf = script_confB.get();
|
||||
logger.info(String.format("OrientationScript: orient_deg=%d, orient_conf=%f, script_name=%s, script_conf=%f", orient_deg, orient_conf, script_name, script_conf));
|
||||
}
|
||||
|
||||
PointerByReference pRef = new PointerByReference();
|
||||
pRef.setValue(pix.getPointer());
|
||||
Leptonica1.pixDestroy(pRef);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of Orientation and script detection (OSD).
|
||||
*
|
||||
* @throws Exception while processing the image.
|
||||
*/
|
||||
@Test
|
||||
public void testOSD() throws Exception {
|
||||
logger.info("OSD");
|
||||
int expResult = TessPageSegMode.PSM_AUTO_OSD;
|
||||
IntBuffer orientation = IntBuffer.allocate(1);
|
||||
IntBuffer direction = IntBuffer.allocate(1);
|
||||
IntBuffer order = IntBuffer.allocate(1);
|
||||
FloatBuffer deskew_angle = FloatBuffer.allocate(1);
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext90.png");
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(imageFile));
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetPageSegMode(handle, expResult);
|
||||
int actualResult = TessAPI1.TessBaseAPIGetPageSegMode(handle);
|
||||
logger.info("PSM: " + Utils.getConstantName(actualResult, TessPageSegMode.class));
|
||||
TessAPI1.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
int success = TessAPI1.TessBaseAPIRecognize(handle, null);
|
||||
if (success == 0) {
|
||||
TessAPI1.TessPageIterator pi = TessAPI1.TessBaseAPIAnalyseLayout(handle);
|
||||
TessAPI1.TessPageIteratorOrientation(pi, orientation, direction, order, deskew_angle);
|
||||
logger.info(String.format(
|
||||
"Orientation: %s\nWritingDirection: %s\nTextlineOrder: %s\nDeskew angle: %.4f\n",
|
||||
Utils.getConstantName(orientation.get(), TessOrientation.class),
|
||||
Utils.getConstantName(direction.get(), TessWritingDirection.class),
|
||||
Utils.getConstantName(order.get(), TessTextlineOrder.class),
|
||||
deskew_angle.get()));
|
||||
}
|
||||
assertEquals(expResult, actualResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of ResultIterator and PageIterator.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testResultIterator() throws Exception {
|
||||
logger.info("TessBaseAPIGetIterator");
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff)); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
TessAPI1.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
ETEXT_DESC monitor = new ETEXT_DESC();
|
||||
ITessAPI.TimeVal timeout = new ITessAPI.TimeVal();
|
||||
timeout.tv_sec = new NativeLong(0L); // time > 0 causes blank ouput
|
||||
monitor.end_time = timeout;
|
||||
ProgressMonitor pmo = new ProgressMonitor(monitor);
|
||||
pmo.start();
|
||||
TessAPI1.TessBaseAPIRecognize(handle, monitor);
|
||||
logger.info("Message: " + pmo.getMessage());
|
||||
TessResultIterator ri = TessAPI1.TessBaseAPIGetIterator(handle);
|
||||
TessPageIterator pi = TessAPI1.TessResultIteratorGetPageIterator(ri);
|
||||
TessAPI1.TessPageIteratorBegin(pi);
|
||||
logger.info("Bounding boxes:\nchar(s) left top right bottom confidence font-attributes");
|
||||
int level = TessPageIteratorLevel.RIL_WORD;
|
||||
|
||||
// int height = image.getHeight();
|
||||
do {
|
||||
Pointer ptr = TessAPI1.TessResultIteratorGetUTF8Text(ri, level);
|
||||
String word = ptr.getString(0);
|
||||
TessAPI1.TessDeleteText(ptr);
|
||||
float confidence = TessAPI1.TessResultIteratorConfidence(ri, level);
|
||||
IntBuffer leftB = IntBuffer.allocate(1);
|
||||
IntBuffer topB = IntBuffer.allocate(1);
|
||||
IntBuffer rightB = IntBuffer.allocate(1);
|
||||
IntBuffer bottomB = IntBuffer.allocate(1);
|
||||
TessAPI1.TessPageIteratorBoundingBox(pi, level, leftB, topB, rightB, bottomB);
|
||||
int left = leftB.get();
|
||||
int top = topB.get();
|
||||
int right = rightB.get();
|
||||
int bottom = bottomB.get();
|
||||
System.out.print(String.format("%s %d %d %d %d %f", word, left, top, right, bottom, confidence));
|
||||
// logger.info(String.format("%s %d %d %d %d", str, left, height - bottom, right, height - top)); //
|
||||
// training box coordinates
|
||||
|
||||
IntBuffer boldB = IntBuffer.allocate(1);
|
||||
IntBuffer italicB = IntBuffer.allocate(1);
|
||||
IntBuffer underlinedB = IntBuffer.allocate(1);
|
||||
IntBuffer monospaceB = IntBuffer.allocate(1);
|
||||
IntBuffer serifB = IntBuffer.allocate(1);
|
||||
IntBuffer smallcapsB = IntBuffer.allocate(1);
|
||||
IntBuffer pointSizeB = IntBuffer.allocate(1);
|
||||
IntBuffer fontIdB = IntBuffer.allocate(1);
|
||||
String fontName = TessAPI1.TessResultIteratorWordFontAttributes(ri, boldB, italicB, underlinedB,
|
||||
monospaceB, serifB, smallcapsB, pointSizeB, fontIdB);
|
||||
boolean bold = boldB.get() == TRUE;
|
||||
boolean italic = italicB.get() == TRUE;
|
||||
boolean underlined = underlinedB.get() == TRUE;
|
||||
boolean monospace = monospaceB.get() == TRUE;
|
||||
boolean serif = serifB.get() == TRUE;
|
||||
boolean smallcaps = smallcapsB.get() == TRUE;
|
||||
int pointSize = pointSizeB.get();
|
||||
int fontId = fontIdB.get();
|
||||
logger.info(String.format(" font: %s, size: %d, font id: %d, bold: %b,"
|
||||
+ " italic: %b, underlined: %b, monospace: %b, serif: %b, smallcap: %b", fontName, pointSize,
|
||||
fontId, bold, italic, underlined, monospace, serif, smallcaps));
|
||||
} while (TessAPI1.TessPageIteratorNext(pi, level) == TRUE);
|
||||
// TessAPI1.TessPageIteratorDelete(pi);
|
||||
TessAPI1.TessResultIteratorDelete(ri);
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of ChoiceIterator.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testChoiceIterator() throws Exception {
|
||||
logger.info("TessResultIteratorGetChoiceIterator");
|
||||
String filename = String.format("%s/%s", this.testResourcesDataPath, "eurotext.tif");
|
||||
File tiff = new File(filename);
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff)); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
TessAPI1.TessBaseAPIInit3(handle, datapath, language);
|
||||
TessAPI1.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
TessAPI1.TessBaseAPISetVariable(handle, "save_blob_choices", "T");
|
||||
TessAPI1.TessBaseAPISetRectangle(handle, 37, 228, 548, 31);
|
||||
ETEXT_DESC monitor = new ETEXT_DESC();
|
||||
ProgressMonitor pmo = new ProgressMonitor(monitor);
|
||||
pmo.start();
|
||||
TessAPI1.TessBaseAPIRecognize(handle, monitor);
|
||||
logger.info("Message: " + pmo.getMessage());
|
||||
TessResultIterator ri = TessAPI1.TessBaseAPIGetIterator(handle);
|
||||
int level = TessPageIteratorLevel.RIL_SYMBOL;
|
||||
|
||||
if (ri != null) {
|
||||
do {
|
||||
Pointer symbol = TessAPI1.TessResultIteratorGetUTF8Text(ri, level);
|
||||
float conf = TessAPI1.TessResultIteratorConfidence(ri, level);
|
||||
if (symbol != null) {
|
||||
logger.info(String.format("symbol %s, conf: %f", symbol.getString(0), conf));
|
||||
boolean indent = false;
|
||||
TessChoiceIterator ci = TessAPI1.TessResultIteratorGetChoiceIterator(ri);
|
||||
do {
|
||||
if (indent) {
|
||||
System.out.print("\t");
|
||||
}
|
||||
System.out.print("\t- ");
|
||||
String choice = TessAPI1.TessChoiceIteratorGetUTF8Text(ci);
|
||||
logger.info(String.format("%s conf: %f", choice, TessAPI1.TessChoiceIteratorConfidence(ci)));
|
||||
indent = true;
|
||||
} while (TessAPI1.TessChoiceIteratorNext(ci) == TessAPI1.TRUE);
|
||||
TessAPI1.TessChoiceIteratorDelete(ci);
|
||||
}
|
||||
logger.info("---------------------------------------------");
|
||||
TessAPI1.TessDeleteText(symbol);
|
||||
} while (TessAPI1.TessResultIteratorNext(ri, level) == TessAPI1.TRUE);
|
||||
TessAPI1.TessResultIteratorDelete(ri);
|
||||
}
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of ResultRenderer method, of class TessAPI1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testResultRenderer() throws Exception {
|
||||
logger.info("TessResultRenderer");
|
||||
String image = String.format("%s/%s", this.testResourcesDataPath, "eurotext.tif");
|
||||
String output = "capi-test.txt";
|
||||
int set_only_init_params = ITessAPI.FALSE;
|
||||
int oem = TessOcrEngineMode.OEM_DEFAULT;
|
||||
PointerByReference configs = null;
|
||||
int configs_size = 0;
|
||||
|
||||
String[] params = {"load_system_dawg", "tessedit_char_whitelist"};
|
||||
String vals[] = {"F", ""}; //0123456789-.IThisalotfpnex
|
||||
PointerByReference vars_vec = new PointerByReference();
|
||||
vars_vec.setPointer(new StringArray(params));
|
||||
PointerByReference vars_values = new PointerByReference();
|
||||
vars_values.setPointer(new StringArray(vals));
|
||||
NativeSize vars_vec_size = new NativeSize(params.length);
|
||||
|
||||
TessAPI1.TessBaseAPISetOutputName(handle, output);
|
||||
|
||||
int rc = TessAPI1.TessBaseAPIInit4(handle, datapath, language,
|
||||
oem, configs, configs_size, vars_vec, vars_values, vars_vec_size, set_only_init_params);
|
||||
|
||||
if (rc != 0) {
|
||||
TessAPI1.TessBaseAPIDelete(handle);
|
||||
logger.error("Could not initialize tesseract.");
|
||||
return;
|
||||
}
|
||||
|
||||
String outputbase = "target/test-classes/test-results/ResultRenderer1";
|
||||
TessResultRenderer renderer = TessAPI1.TessHOcrRendererCreate(outputbase);
|
||||
TessAPI1.TessResultRendererInsert(renderer, TessAPI1.TessBoxTextRendererCreate(outputbase));
|
||||
TessAPI1.TessResultRendererInsert(renderer, TessAPI1.TessTextRendererCreate(outputbase));
|
||||
String dataPath = TessAPI1.TessBaseAPIGetDatapath(handle);
|
||||
TessAPI1.TessResultRendererInsert(renderer, TessAPI1.TessPDFRendererCreate(outputbase, dataPath, FALSE));
|
||||
int result = TessAPI1.TessBaseAPIProcessPages(handle, image, null, 0, renderer);
|
||||
|
||||
// if (result == FALSE) {
|
||||
// logger.error("Error during processing.");
|
||||
// return;
|
||||
// }
|
||||
while ((renderer = TessAPI1.TessResultRendererNext(renderer)) != null) {
|
||||
String ext = TessAPI1.TessResultRendererExtention(renderer).getString(0);
|
||||
logger.info(String.format("TessResultRendererExtention: %s\nTessResultRendererTitle: %s\nTessResultRendererImageNum: %d",
|
||||
ext,
|
||||
TessAPI1.TessResultRendererTitle(renderer).getString(0),
|
||||
TessAPI1.TessResultRendererImageNum(renderer)));
|
||||
}
|
||||
|
||||
TessAPI1.TessDeleteResultRenderer(renderer);
|
||||
assertTrue(new File(outputbase + ".pdf").exists());
|
||||
}
|
||||
}
|
695
d4dj/src/test/java/net/sourceforge/tess4j/TessAPIImpl.java
Normal file
@ -0,0 +1,695 @@
|
||||
/*
|
||||
* Copyright @ 2017 Quan Nguyen
|
||||
*
|
||||
* 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 net.sourceforge.tess4j;
|
||||
|
||||
import com.ochafik.lang.jnaerator.runtime.NativeSize;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import net.sourceforge.lept4j.Boxa;
|
||||
import net.sourceforge.lept4j.Pix;
|
||||
|
||||
public class TessAPIImpl implements TessAPI {
|
||||
|
||||
public TessAPI getInstance() {
|
||||
return TessAPI.INSTANCE;
|
||||
}
|
||||
|
||||
public void TessAPIEndPage() {
|
||||
}
|
||||
|
||||
public void TessAPIRelease() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessVersion() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessDeleteText(Pointer text) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessDeleteTextArray(PointerByReference arr) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessDeleteIntArray(IntBuffer arr) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultRenderer TessTextRendererCreate(String outputbase) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultRenderer TessHOcrRendererCreate(String outputbase) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultRenderer TessHOcrRendererCreate2(String outputbase, int font_info) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultRenderer TessPDFRendererCreate(String outputbase, String datadir, int textonly) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultRenderer TessUnlvRendererCreate(String outputbase) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultRenderer TessBoxTextRendererCreate(String outputbase) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessDeleteResultRenderer(ITessAPI.TessResultRenderer renderer) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessResultRendererInsert(ITessAPI.TessResultRenderer renderer, ITessAPI.TessResultRenderer next) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultRenderer TessResultRendererNext(ITessAPI.TessResultRenderer renderer) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultRendererBeginDocument(ITessAPI.TessResultRenderer renderer, String title) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultRendererAddImage(ITessAPI.TessResultRenderer renderer, PointerByReference api) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultRendererEndDocument(ITessAPI.TessResultRenderer renderer) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessResultRendererExtention(ITessAPI.TessResultRenderer renderer) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessResultRendererTitle(ITessAPI.TessResultRenderer renderer) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultRendererImageNum(ITessAPI.TessResultRenderer renderer) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessBaseAPI TessBaseAPICreate() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPIDelete(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPISetInputName(ITessAPI.TessBaseAPI handle, String name) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessBaseAPIGetInputName(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPISetInputImage(ITessAPI.TessBaseAPI handle, Pix pix) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pix TessBaseAPIGetInputImage(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIGetSourceYResolution(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessBaseAPIGetDatapath(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPISetOutputName(ITessAPI.TessBaseAPI handle, String name) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPISetVariable(ITessAPI.TessBaseAPI handle, String name, String value) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIGetIntVariable(ITessAPI.TessBaseAPI handle, String name, IntBuffer value) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIGetBoolVariable(ITessAPI.TessBaseAPI handle, String name, IntBuffer value) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIGetDoubleVariable(ITessAPI.TessBaseAPI handle, String name, DoubleBuffer value) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessBaseAPIGetStringVariable(ITessAPI.TessBaseAPI handle, String name) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPIPrintVariablesToFile(ITessAPI.TessBaseAPI handle, String filename) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIInit1(ITessAPI.TessBaseAPI handle, String datapath, String language, int oem, PointerByReference configs, int configs_size) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIInit2(ITessAPI.TessBaseAPI handle, String datapath, String language, int oem) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIInit3(ITessAPI.TessBaseAPI handle, String datapath, String language) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIInit4(ITessAPI.TessBaseAPI handle, String datapath, String language, int oem, PointerByReference configs, int configs_size, PointerByReference vars_vec, PointerByReference vars_values, NativeSize vars_vec_size, int set_only_non_debug_params) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessBaseAPIGetInitLanguagesAsString(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointerByReference TessBaseAPIGetLoadedLanguagesAsVector(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointerByReference TessBaseAPIGetAvailableLanguagesAsVector(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIInitLangMod(ITessAPI.TessBaseAPI handle, String datapath, String language) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPIInitForAnalysePage(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPIReadConfigFile(ITessAPI.TessBaseAPI handle, String filename, int init_only) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPISetPageSegMode(ITessAPI.TessBaseAPI handle, int mode) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIGetPageSegMode(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIRect(ITessAPI.TessBaseAPI handle, ByteBuffer imagedata, int bytes_per_pixel, int bytes_per_line, int left, int top, int width, int height) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPIClearAdaptiveClassifier(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPISetImage(ITessAPI.TessBaseAPI handle, ByteBuffer imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPISetImage2(ITessAPI.TessBaseAPI handle, Pix pix) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPISetSourceResolution(ITessAPI.TessBaseAPI handle, int ppi) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPISetRectangle(ITessAPI.TessBaseAPI handle, int left, int top, int width, int height) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pix TessBaseAPIGetThresholdedImage(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boxa TessBaseAPIGetRegions(ITessAPI.TessBaseAPI handle, PointerByReference pixa) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boxa TessBaseAPIGetTextlines(ITessAPI.TessBaseAPI handle, PointerByReference pixa, PointerByReference blockids) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boxa TessBaseAPIGetTextlines1(ITessAPI.TessBaseAPI handle, int raw_image, int raw_padding, PointerByReference pixa, PointerByReference blockids, PointerByReference paraids) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boxa TessBaseAPIGetStrips(ITessAPI.TessBaseAPI handle, PointerByReference pixa, PointerByReference blockids) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boxa TessBaseAPIGetWords(ITessAPI.TessBaseAPI handle, PointerByReference pixa) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boxa TessBaseAPIGetConnectedComponents(ITessAPI.TessBaseAPI handle, PointerByReference cc) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boxa TessBaseAPIGetComponentImages(ITessAPI.TessBaseAPI handle, int level, int text_only, PointerByReference pixa, PointerByReference blockids) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boxa TessBaseAPIGetComponentImages1(ITessAPI.TessBaseAPI handle, int level, int text_only, int raw_image, int raw_padding, PointerByReference pixa, PointerByReference blockids, PointerByReference paraids) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIGetThresholdedImageScaleFactor(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessPageIterator TessBaseAPIAnalyseLayout(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIRecognize(ITessAPI.TessBaseAPI handle, ITessAPI.ETEXT_DESC monitor) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIRecognizeForChopTest(ITessAPI.TessBaseAPI handle, ITessAPI.ETEXT_DESC monitor) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultIterator TessBaseAPIGetIterator(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessMutableIterator TessBaseAPIGetMutableIterator(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIProcessPages(ITessAPI.TessBaseAPI handle, String filename, String retry_config, int timeout_millisec, ITessAPI.TessResultRenderer renderer) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIProcessPage(ITessAPI.TessBaseAPI handle, Pix pix, int page_index, String filename, String retry_config, int timeout_millisec, ITessAPI.TessResultRenderer renderer) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIGetUTF8Text(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIGetHOCRText(ITessAPI.TessBaseAPI handle, int page_number) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIGetBoxText(ITessAPI.TessBaseAPI handle, int page_number) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIGetUNLVText(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIMeanTextConf(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntByReference TessBaseAPIAllWordConfidences(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIAdaptToWordStr(ITessAPI.TessBaseAPI handle, int mode, String wordstr) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPIClear(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPIEnd(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIIsValidWord(ITessAPI.TessBaseAPI handle, String word) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIGetTextDirection(ITessAPI.TessBaseAPI handle, IntBuffer out_offset, FloatBuffer out_slope) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessBaseAPIClearPersistentCache(ITessAPI.TessBaseAPI handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessBaseAPIDetectOrientationScript(TessBaseAPI handle, IntBuffer orient_deg, FloatBuffer orient_conf, PointerByReference script_name, FloatBuffer script_conf) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessBaseAPIGetUnichar(ITessAPI.TessBaseAPI handle, int unichar_id) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessPageIteratorDelete(ITessAPI.TessPageIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessPageIterator TessPageIteratorCopy(ITessAPI.TessPageIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessPageIteratorBegin(ITessAPI.TessPageIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessPageIteratorNext(ITessAPI.TessPageIterator handle, int level) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessPageIteratorIsAtBeginningOf(ITessAPI.TessPageIterator handle, int level) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessPageIteratorIsAtFinalElement(ITessAPI.TessPageIterator handle, int level, int element) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessPageIteratorBoundingBox(ITessAPI.TessPageIterator handle, int level, IntBuffer left, IntBuffer top, IntBuffer right, IntBuffer bottom) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessPageIteratorBlockType(ITessAPI.TessPageIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pix TessPageIteratorGetBinaryImage(ITessAPI.TessPageIterator handle, int level) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pix TessPageIteratorGetImage(ITessAPI.TessPageIterator handle, int level, int padding, Pix original_image, IntBuffer left, IntBuffer top) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessPageIteratorBaseline(ITessAPI.TessPageIterator handle, int level, IntBuffer x1, IntBuffer y1, IntBuffer x2, IntBuffer y2) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessPageIteratorOrientation(ITessAPI.TessPageIterator handle, IntBuffer orientation, IntBuffer writing_direction, IntBuffer textline_order, FloatBuffer deskew_angle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessPageIteratorParagraphInfo(ITessAPI.TessPageIterator handle, IntBuffer justification, IntBuffer is_list_item, IntBuffer is_crown, IntBuffer first_line_indent) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessResultIteratorDelete(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessResultIterator TessResultIteratorCopy(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessPageIterator TessResultIteratorGetPageIterator(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessPageIterator TessResultIteratorGetPageIteratorConst(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultIteratorNext(ITessAPI.TessResultIterator handle, int level) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessResultIteratorGetUTF8Text(ITessAPI.TessResultIterator handle, int level) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float TessResultIteratorConfidence(ITessAPI.TessResultIterator handle, int level) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessResultIteratorWordRecognitionLanguage(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessResultIteratorWordFontAttributes(ITessAPI.TessResultIterator handle, IntBuffer is_bold, IntBuffer is_italic, IntBuffer is_underlined, IntBuffer is_monospace, IntBuffer is_serif, IntBuffer is_smallcaps, IntBuffer pointsize, IntBuffer font_id) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultIteratorWordIsFromDictionary(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultIteratorWordIsNumeric(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultIteratorSymbolIsSuperscript(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultIteratorSymbolIsSubscript(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessResultIteratorSymbolIsDropcap(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITessAPI.TessChoiceIterator TessResultIteratorGetChoiceIterator(ITessAPI.TessResultIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessChoiceIteratorDelete(ITessAPI.TessChoiceIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessChoiceIteratorNext(ITessAPI.TessChoiceIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String TessChoiceIteratorGetUTF8Text(ITessAPI.TessChoiceIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float TessChoiceIteratorConfidence(ITessAPI.TessChoiceIterator handle) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ETEXT_DESC TessMonitorCreate() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessMonitorDelete(ETEXT_DESC monitor) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessMonitorSetCancelFunc(ETEXT_DESC monitor, TessCancelFunc cancelFunc) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessMonitorSetCancelThis(ETEXT_DESC monitor, Pointer cancelThis) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessMonitorGetCancelThis(ETEXT_DESC monitor) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessMonitorSetProgressFunc(ETEXT_DESC monitor, TessProgressFunc progressFunc) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int TessMonitorGetProgress(ETEXT_DESC monitor) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void TessMonitorSetDeadlineMSecs(ETEXT_DESC monitor, int deadline) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TessResultRenderer TessAltoRendererCreate(String outputbase) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIGetAltoText(TessBaseAPI handle, int page_number) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TessResultRenderer TessLSTMBoxRendererCreate(String outputbase) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TessResultRenderer TessWordStrBoxRendererCreate(String outputbase) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIGetLSTMBoxText(TessBaseAPI handle, int page_number) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIGetWordStrBoxText(TessBaseAPI handle, int page_number) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TessResultRenderer TessTsvRendererCreate(String outputbase) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer TessBaseAPIGetTsvText(TessBaseAPI handle, int page_number) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
711
d4dj/src/test/java/net/sourceforge/tess4j/TessAPITest.java
Normal file
@ -0,0 +1,711 @@
|
||||
/**
|
||||
* Copyright @ 2012 Quan Nguyen
|
||||
*
|
||||
* 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 net.sourceforge.tess4j;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import net.sourceforge.tess4j.util.ImageIOHelper;
|
||||
import net.sourceforge.tess4j.util.LoggHelper;
|
||||
import net.sourceforge.tess4j.util.Utils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.ochafik.lang.jnaerator.runtime.NativeSize;
|
||||
import com.sun.jna.NativeLong;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.StringArray;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import net.sourceforge.lept4j.Box;
|
||||
import net.sourceforge.lept4j.Boxa;
|
||||
import static net.sourceforge.lept4j.ILeptonica.L_CLONE;
|
||||
import net.sourceforge.lept4j.Leptonica;
|
||||
import net.sourceforge.lept4j.Pix;
|
||||
import net.sourceforge.lept4j.util.LeptUtils;
|
||||
|
||||
import net.sourceforge.tess4j.ITessAPI.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static net.sourceforge.tess4j.ITessAPI.FALSE;
|
||||
import static net.sourceforge.tess4j.ITessAPI.TRUE;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TessAPITest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
private final String datapath = "src/main/resources/tessdata";
|
||||
private final String testResourcesDataPath = "src/test/resources/test-data";
|
||||
String language = "eng";
|
||||
String expOCRResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
|
||||
TessAPI api;
|
||||
TessBaseAPI handle;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
api = new TessAPIImpl().getInstance();
|
||||
handle = api.TessBaseAPICreate();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
api.TessBaseAPIDelete(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIRect method, of class TessAPI.
|
||||
*
|
||||
* @throws Exception while processing the image
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIRect() throws Exception {
|
||||
logger.info("TessBaseAPIRect");
|
||||
String expResult = expOCRResult;
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage image = ImageIO.read(tiff); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
Pointer utf8Text = api.TessBaseAPIRect(handle, buf, bytespp, bytespl, 0, 0, 1024, 800);
|
||||
String result = utf8Text.getString(0);
|
||||
api.TessDeleteText(utf8Text);
|
||||
logger.info(result);
|
||||
assertTrue(result.startsWith(expResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetUTF8Text method, of class TessAPI.
|
||||
*
|
||||
* @throws Exception while processing the image
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetUTF8Text() throws Exception {
|
||||
logger.info("TessBaseAPIGetUTF8Text");
|
||||
String expResult = expOCRResult;
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff)); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
api.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
api.TessBaseAPISetRectangle(handle, 0, 0, 1024, 800);
|
||||
Pointer utf8Text = api.TessBaseAPIGetUTF8Text(handle);
|
||||
String result = utf8Text.getString(0);
|
||||
api.TessDeleteText(utf8Text);
|
||||
logger.info(result);
|
||||
assertTrue(result.startsWith(expResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetUTF8Text method, of class TessAPI.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetUTF8Text_Pix() throws Exception {
|
||||
logger.info("TessBaseAPIGetUTF8Text_Pix");
|
||||
String expResult = expOCRResult;
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
Leptonica leptInstance = Leptonica.INSTANCE;
|
||||
Pix pix = leptInstance.pixRead(tiff.getPath());
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetImage2(handle, pix);
|
||||
Pointer utf8Text = api.TessBaseAPIGetUTF8Text(handle);
|
||||
String result = utf8Text.getString(0);
|
||||
api.TessDeleteText(utf8Text);
|
||||
logger.info(result);
|
||||
|
||||
//release Pix resource
|
||||
PointerByReference pRef = new PointerByReference();
|
||||
pRef.setValue(pix.getPointer());
|
||||
leptInstance.pixDestroy(pRef);
|
||||
|
||||
assertTrue(result.startsWith(expResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetComponentImages method, of class TessAPI.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetComponentImages() throws Exception {
|
||||
logger.info("TessBaseAPIGetComponentImages");
|
||||
File image = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
int expResult = 12; // number of lines in the test image
|
||||
Leptonica leptInstance = Leptonica.INSTANCE;
|
||||
Pix pix = leptInstance.pixRead(image.getPath());
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetImage2(handle, pix);
|
||||
PointerByReference pixa = null;
|
||||
PointerByReference blockids = null;
|
||||
Boxa boxes = api.TessBaseAPIGetComponentImages(handle, TessPageIteratorLevel.RIL_TEXTLINE, TRUE, pixa, blockids);
|
||||
// boxes = api.TessBaseAPIGetRegions(handle, pixa); // equivalent to TessPageIteratorLevel.RIL_BLOCK
|
||||
int boxCount = leptInstance.boxaGetCount(boxes);
|
||||
for (int i = 0; i < boxCount; i++) {
|
||||
Box box = leptInstance.boxaGetBox(boxes, i, L_CLONE);
|
||||
if (box == null) {
|
||||
continue;
|
||||
}
|
||||
api.TessBaseAPISetRectangle(handle, box.x, box.y, box.w, box.h);
|
||||
Pointer utf8Text = api.TessBaseAPIGetUTF8Text(handle);
|
||||
String ocrResult = utf8Text.getString(0);
|
||||
api.TessDeleteText(utf8Text);
|
||||
int conf = api.TessBaseAPIMeanTextConf(handle);
|
||||
System.out.print(String.format("Box[%d]: x=%d, y=%d, w=%d, h=%d, confidence: %d, text: %s", i, box.x, box.y, box.w, box.h, conf, ocrResult));
|
||||
LeptUtils.dispose(box);
|
||||
}
|
||||
|
||||
// release Pix and Boxa resources
|
||||
LeptUtils.dispose(pix);
|
||||
LeptUtils.dispose(boxes);
|
||||
|
||||
assertEquals(expResult, boxCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessVersion method, of class TessAPI.
|
||||
*/
|
||||
@Test
|
||||
public void testTessVersion() {
|
||||
logger.info("TessVersion");
|
||||
String expResult = "5.0.0";
|
||||
String result = api.TessVersion();
|
||||
logger.info(result);
|
||||
assertTrue(result.startsWith(expResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPISetVariable method, of class TessAPI.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPISetVariable() {
|
||||
logger.info("TessBaseAPISetVariable");
|
||||
String name = "tessedit_create_hocr";
|
||||
String value = "1";
|
||||
int expResult = 1;
|
||||
int result = api.TessBaseAPISetVariable(handle, name, value);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetBoolVariable method, of class TessAPI.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetBoolVariable() {
|
||||
logger.info("TessBaseAPIGetBoolVariable");
|
||||
String name = "tessedit_create_hocr";
|
||||
api.TessBaseAPISetVariable(handle, name, "1");
|
||||
IntBuffer value = IntBuffer.allocate(1);
|
||||
int result = -1;
|
||||
if (api.TessBaseAPIGetBoolVariable(handle, "tessedit_create_hocr", value) == TRUE) {
|
||||
result = value.get(0);
|
||||
}
|
||||
int expResult = 1;
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIPrintVariables method, of class TessAPI.
|
||||
*
|
||||
* @throws Exception while persisting variables to file
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIPrintVariablesToFile() throws Exception {
|
||||
logger.info("TessBaseAPIPrintVariablesToFile");
|
||||
String var = "tessedit_char_whitelist";
|
||||
String value = "0123456789";
|
||||
api.TessBaseAPISetVariable(handle, var, value);
|
||||
String filename = "printvar.txt";
|
||||
api.TessBaseAPIPrintVariablesToFile(handle, filename); // will crash if not invoked after some method
|
||||
File file = new File(filename);
|
||||
BufferedReader input = new BufferedReader(new FileReader(file));
|
||||
StringBuilder strB = new StringBuilder();
|
||||
String line;
|
||||
String EOL = System.getProperty("line.separator");
|
||||
while ((line = input.readLine()) != null) {
|
||||
strB.append(line).append(EOL);
|
||||
}
|
||||
input.close();
|
||||
file.delete();
|
||||
assertTrue(strB.toString().contains(var + "\t" + value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIInit4 method, of class TessAPI.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIInit4() {
|
||||
logger.info("TessBaseAPIInit4");
|
||||
int oem = TessOcrEngineMode.OEM_DEFAULT;
|
||||
PointerByReference configs = null;
|
||||
int configs_size = 0;
|
||||
// disable loading dictionaries
|
||||
String[] args = new String[]{"load_system_dawg", "load_freq_dawg"};
|
||||
StringArray sarray = new StringArray(args);
|
||||
PointerByReference vars_vec = new PointerByReference();
|
||||
vars_vec.setPointer(sarray);
|
||||
|
||||
args = new String[]{"F", "F"};
|
||||
sarray = new StringArray(args);
|
||||
PointerByReference vars_values = new PointerByReference();
|
||||
vars_values.setPointer(sarray);
|
||||
|
||||
NativeSize vars_vec_size = new NativeSize(args.length);
|
||||
|
||||
int expResult = 0;
|
||||
int result = api.TessBaseAPIInit4(handle, datapath, language, oem, configs, configs_size, vars_vec, vars_values, vars_vec_size, FALSE);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetInitLanguagesAsString method, of class TessAPI.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetInitLanguagesAsString() {
|
||||
logger.info("TessBaseAPIGetInitLanguagesAsString");
|
||||
String expResult = "";
|
||||
String result = api.TessBaseAPIGetInitLanguagesAsString(handle);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetLoadedLanguagesAsVector method, of class TessAPI.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetLoadedLanguagesAsVector() {
|
||||
logger.info("TessBaseAPIGetLoadedLanguagesAsVector");
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
String[] expResult = {"eng"};
|
||||
String[] result = api.TessBaseAPIGetLoadedLanguagesAsVector(handle).getPointer().getStringArray(0);
|
||||
assertArrayEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetAvailableLanguagesAsVector method, of class
|
||||
* TessAPI.
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetAvailableLanguagesAsVector() {
|
||||
logger.info("TessBaseAPIGetAvailableLanguagesAsVector");
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
String[] expResult = {"eng"};
|
||||
String[] result = api.TessBaseAPIGetAvailableLanguagesAsVector(handle).getPointer().getStringArray(0);
|
||||
assertTrue(Arrays.asList(result).containsAll(Arrays.asList(expResult)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetHOCRText method, of class TessAPI.
|
||||
*
|
||||
* @throws Exception while getting hocr text
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetHOCRText() throws Exception {
|
||||
logger.info("TessBaseAPIGetHOCRText");
|
||||
String filename = String.format("%s/%s", this.testResourcesDataPath, "eurotext.tif");
|
||||
File tiff = new File(filename);
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff)); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
api.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
int page_number = 0;
|
||||
Pointer utf8Text = api.TessBaseAPIGetHOCRText(handle, page_number);
|
||||
String result = utf8Text.getString(0);
|
||||
api.TessDeleteText(utf8Text);
|
||||
assertTrue(result.contains("<div class='ocr_page'"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIGetAltoText method, of class TessAPI.
|
||||
*
|
||||
* @throws Exception while getting Alto text
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIGetAltoText() throws Exception {
|
||||
logger.info("TessBaseAPIGetAltoText");
|
||||
String filename = String.format("%s/%s", this.testResourcesDataPath, "eurotext.tif");
|
||||
File tiff = new File(filename);
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff));
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
api.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
int page_number = 0;
|
||||
Pointer textPtr = api.TessBaseAPIGetAltoText(handle, page_number);
|
||||
String result = textPtr.getString(0);
|
||||
api.TessDeleteText(textPtr);
|
||||
assertTrue(result.contains("<Page WIDTH=\"1024\" HEIGHT=\"800\" PHYSICAL_IMG_NR=\"0\" ID=\"page_0\">"));
|
||||
|
||||
// WordStr Box output
|
||||
textPtr = api.TessBaseAPIGetWordStrBoxText(handle, page_number);
|
||||
result = textPtr.getString(0);
|
||||
api.TessDeleteText(textPtr);
|
||||
assertTrue(result.contains("WordStr"));
|
||||
|
||||
// TSV output
|
||||
textPtr = api.TessBaseAPIGetTsvText(handle, page_number);
|
||||
result = textPtr.getString(0);
|
||||
api.TessDeleteText(textPtr);
|
||||
assertTrue(result.contains("1\t"));
|
||||
|
||||
// LSTM Box output
|
||||
textPtr = api.TessBaseAPIGetLSTMBoxText(handle, page_number);
|
||||
result = textPtr.getString(0);
|
||||
api.TessDeleteText(textPtr);
|
||||
assertTrue(result.contains("\t"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIAnalyseLayout method, of class TessAPI.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIAnalyseLayout() throws Exception {
|
||||
logger.info("TessBaseAPIAnalyseLayout");
|
||||
File image = new File(testResourcesDataPath, "eurotext.png");
|
||||
int expResult = 12; // number of lines in the test image
|
||||
Leptonica leptInstance = Leptonica.INSTANCE;
|
||||
Pix pix = leptInstance.pixRead(image.getPath());
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetImage2(handle, pix);
|
||||
int pageIteratorLevel = TessPageIteratorLevel.RIL_TEXTLINE;
|
||||
logger.info("PageIteratorLevel: " + Utils.getConstantName(pageIteratorLevel, TessPageIteratorLevel.class));
|
||||
int i = 0;
|
||||
TessPageIterator pi = api.TessBaseAPIAnalyseLayout(handle);
|
||||
|
||||
do {
|
||||
IntBuffer leftB = IntBuffer.allocate(1);
|
||||
IntBuffer topB = IntBuffer.allocate(1);
|
||||
IntBuffer rightB = IntBuffer.allocate(1);
|
||||
IntBuffer bottomB = IntBuffer.allocate(1);
|
||||
api.TessPageIteratorBoundingBox(pi, pageIteratorLevel, leftB, topB, rightB, bottomB);
|
||||
int left = leftB.get();
|
||||
int top = topB.get();
|
||||
int right = rightB.get();
|
||||
int bottom = bottomB.get();
|
||||
logger.info(String.format("Box[%d]: x=%d, y=%d, w=%d, h=%d", i++, left, top, right - left, bottom - top));
|
||||
} while (api.TessPageIteratorNext(pi, pageIteratorLevel) == TRUE);
|
||||
api.TessPageIteratorDelete(pi);
|
||||
PointerByReference pRef = new PointerByReference();
|
||||
pRef.setValue(pix.getPointer());
|
||||
leptInstance.pixDestroy(pRef);
|
||||
assertEquals(expResult, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of TessBaseAPIDetectOrientationScript method, of class TessAPI.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTessBaseAPIDetectOrientationScript() throws Exception {
|
||||
logger.info("TessBaseAPIDetectOrientationScript");
|
||||
File image = new File(testResourcesDataPath, "eurotext90.png");
|
||||
int expResult = TRUE;
|
||||
Leptonica leptInstance = Leptonica.INSTANCE;
|
||||
Pix pix = leptInstance.pixRead(image.getPath());
|
||||
api.TessBaseAPIInit3(handle, datapath, "osd");
|
||||
api.TessBaseAPISetImage2(handle, pix);
|
||||
|
||||
IntBuffer orient_degB = IntBuffer.allocate(1);
|
||||
FloatBuffer orient_confB = FloatBuffer.allocate(1);
|
||||
PointerByReference script_nameB = new PointerByReference();
|
||||
FloatBuffer script_confB = FloatBuffer.allocate(1);
|
||||
|
||||
int result = api.TessBaseAPIDetectOrientationScript(handle, orient_degB, orient_confB, script_nameB, script_confB);
|
||||
if (result == TRUE) {
|
||||
int orient_deg = orient_degB.get();
|
||||
float orient_conf = orient_confB.get();
|
||||
String script_name = script_nameB.getValue().getString(0);
|
||||
float script_conf = script_confB.get();
|
||||
logger.info(String.format("OrientationScript: orient_deg=%d, orient_conf=%f, script_name=%s, script_conf=%f", orient_deg, orient_conf, script_name, script_conf));
|
||||
}
|
||||
|
||||
PointerByReference pRef = new PointerByReference();
|
||||
pRef.setValue(pix.getPointer());
|
||||
leptInstance.pixDestroy(pRef);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of Orientation and script detection (OSD).
|
||||
*
|
||||
* @throws Exception while processing image
|
||||
*/
|
||||
@Test
|
||||
public void testOSD() throws Exception {
|
||||
logger.info("OSD");
|
||||
int expResult = TessPageSegMode.PSM_AUTO_OSD;
|
||||
IntBuffer orientation = IntBuffer.allocate(1);
|
||||
IntBuffer direction = IntBuffer.allocate(1);
|
||||
IntBuffer order = IntBuffer.allocate(1);
|
||||
FloatBuffer deskew_angle = FloatBuffer.allocate(1);
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext90.png");
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(imageFile));
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO_OSD);
|
||||
int actualResult = api.TessBaseAPIGetPageSegMode(handle);
|
||||
logger.info("PSM: " + Utils.getConstantName(actualResult, TessPageSegMode.class));
|
||||
api.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
int success = api.TessBaseAPIRecognize(handle, null);
|
||||
if (success == 0) {
|
||||
TessPageIterator pi = api.TessBaseAPIAnalyseLayout(handle);
|
||||
api.TessPageIteratorOrientation(pi, orientation, direction, order, deskew_angle);
|
||||
logger.info(String.format(
|
||||
"Orientation: %s\nWritingDirection: %s\nTextlineOrder: %s\nDeskew angle: %.4f\n",
|
||||
Utils.getConstantName(orientation.get(), TessOrientation.class),
|
||||
Utils.getConstantName(direction.get(), TessWritingDirection.class),
|
||||
Utils.getConstantName(order.get(), TessTextlineOrder.class),
|
||||
deskew_angle.get()));
|
||||
}
|
||||
assertEquals(expResult, actualResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of ResultIterator and PageIterator.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testResultIterator() throws Exception {
|
||||
logger.info("TessBaseAPIGetIterator");
|
||||
File tiff = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff)); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO);
|
||||
api.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
ETEXT_DESC monitor = new ETEXT_DESC();
|
||||
TimeVal timeout = new TimeVal();
|
||||
timeout.tv_sec = new NativeLong(0L); // time > 0 causes blank ouput
|
||||
monitor.end_time = timeout;
|
||||
ProgressMonitor pmo = new ProgressMonitor(monitor);
|
||||
pmo.start();
|
||||
api.TessBaseAPIRecognize(handle, monitor);
|
||||
logger.info("Message: " + pmo.getMessage());
|
||||
TessResultIterator ri = api.TessBaseAPIGetIterator(handle);
|
||||
TessPageIterator pi = api.TessResultIteratorGetPageIterator(ri);
|
||||
api.TessPageIteratorBegin(pi);
|
||||
logger.info("Bounding boxes:\nchar(s) left top right bottom confidence font-attributes");
|
||||
int level = TessPageIteratorLevel.RIL_WORD;
|
||||
|
||||
// int height = image.getHeight();
|
||||
do {
|
||||
Pointer ptr = api.TessResultIteratorGetUTF8Text(ri, level);
|
||||
String word = ptr.getString(0);
|
||||
api.TessDeleteText(ptr);
|
||||
float confidence = api.TessResultIteratorConfidence(ri, level);
|
||||
IntBuffer leftB = IntBuffer.allocate(1);
|
||||
IntBuffer topB = IntBuffer.allocate(1);
|
||||
IntBuffer rightB = IntBuffer.allocate(1);
|
||||
IntBuffer bottomB = IntBuffer.allocate(1);
|
||||
api.TessPageIteratorBoundingBox(pi, level, leftB, topB, rightB, bottomB);
|
||||
int left = leftB.get();
|
||||
int top = topB.get();
|
||||
int right = rightB.get();
|
||||
int bottom = bottomB.get();
|
||||
System.out.print(String.format("%s %d %d %d %d %f", word, left, top, right, bottom, confidence));
|
||||
// logger.info(String.format("%s %d %d %d %d", str, left, height - bottom, right, height - top)); //
|
||||
// training box coordinates
|
||||
|
||||
IntBuffer boldB = IntBuffer.allocate(1);
|
||||
IntBuffer italicB = IntBuffer.allocate(1);
|
||||
IntBuffer underlinedB = IntBuffer.allocate(1);
|
||||
IntBuffer monospaceB = IntBuffer.allocate(1);
|
||||
IntBuffer serifB = IntBuffer.allocate(1);
|
||||
IntBuffer smallcapsB = IntBuffer.allocate(1);
|
||||
IntBuffer pointSizeB = IntBuffer.allocate(1);
|
||||
IntBuffer fontIdB = IntBuffer.allocate(1);
|
||||
String fontName = api.TessResultIteratorWordFontAttributes(ri, boldB, italicB, underlinedB, monospaceB,
|
||||
serifB, smallcapsB, pointSizeB, fontIdB);
|
||||
boolean bold = boldB.get() == TRUE;
|
||||
boolean italic = italicB.get() == TRUE;
|
||||
boolean underlined = underlinedB.get() == TRUE;
|
||||
boolean monospace = monospaceB.get() == TRUE;
|
||||
boolean serif = serifB.get() == TRUE;
|
||||
boolean smallcaps = smallcapsB.get() == TRUE;
|
||||
int pointSize = pointSizeB.get();
|
||||
int fontId = fontIdB.get();
|
||||
logger.info(String.format(" font: %s, size: %d, font id: %d, bold: %b,"
|
||||
+ " italic: %b, underlined: %b, monospace: %b, serif: %b, smallcap: %b", fontName, pointSize,
|
||||
fontId, bold, italic, underlined, monospace, serif, smallcaps));
|
||||
} while (api.TessPageIteratorNext(pi, level) == TRUE);
|
||||
// api.TessPageIteratorDelete(pi);
|
||||
api.TessResultIteratorDelete(ri);
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of ChoiceIterator.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testChoiceIterator() throws Exception {
|
||||
logger.info("TessResultIteratorGetChoiceIterator");
|
||||
String filename = String.format("%s/%s", this.testResourcesDataPath, "eurotext.tif");
|
||||
File tiff = new File(filename);
|
||||
BufferedImage image = ImageIO.read(new FileInputStream(tiff)); // require jai-imageio lib to read TIFF
|
||||
ByteBuffer buf = ImageIOHelper.convertImageData(image);
|
||||
int bpp = image.getColorModel().getPixelSize();
|
||||
int bytespp = bpp / 8;
|
||||
int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
|
||||
api.TessBaseAPIInit3(handle, datapath, language);
|
||||
api.TessBaseAPISetImage(handle, buf, image.getWidth(), image.getHeight(), bytespp, bytespl);
|
||||
api.TessBaseAPISetVariable(handle, "save_blob_choices", "T");
|
||||
api.TessBaseAPISetRectangle(handle, 37, 228, 548, 31);
|
||||
ETEXT_DESC monitor = new ETEXT_DESC();
|
||||
ProgressMonitor pmo = new ProgressMonitor(monitor);
|
||||
pmo.start();
|
||||
api.TessBaseAPIRecognize(handle, monitor);
|
||||
logger.info("Message: " + pmo.getMessage());
|
||||
TessResultIterator ri = api.TessBaseAPIGetIterator(handle);
|
||||
int level = TessPageIteratorLevel.RIL_SYMBOL;
|
||||
|
||||
if (ri != null) {
|
||||
do {
|
||||
Pointer symbol = api.TessResultIteratorGetUTF8Text(ri, level);
|
||||
float conf = api.TessResultIteratorConfidence(ri, level);
|
||||
if (symbol != null) {
|
||||
logger.info(String.format("symbol %s, conf: %f", symbol.getString(0), conf));
|
||||
boolean indent = false;
|
||||
TessChoiceIterator ci = api.TessResultIteratorGetChoiceIterator(ri);
|
||||
do {
|
||||
if (indent) {
|
||||
System.out.print("\t");
|
||||
}
|
||||
System.out.print("\t- ");
|
||||
String choice = api.TessChoiceIteratorGetUTF8Text(ci);
|
||||
logger.info(String.format("%s conf: %f", choice, api.TessChoiceIteratorConfidence(ci)));
|
||||
indent = true;
|
||||
} while (api.TessChoiceIteratorNext(ci) == ITessAPI.TRUE);
|
||||
api.TessChoiceIteratorDelete(ci);
|
||||
}
|
||||
logger.info("---------------------------------------------");
|
||||
api.TessDeleteText(symbol);
|
||||
} while (api.TessResultIteratorNext(ri, level) == ITessAPI.TRUE);
|
||||
api.TessResultIteratorDelete(ri);
|
||||
}
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of ResultRenderer method, of class TessAPI.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testResultRenderer() throws Exception {
|
||||
logger.info("TessResultRenderer");
|
||||
String image = String.format("%s/%s", this.testResourcesDataPath, "eurotext.tif");
|
||||
String output = "capi-test.txt";
|
||||
int set_only_init_params = FALSE;
|
||||
int oem = TessOcrEngineMode.OEM_DEFAULT;
|
||||
PointerByReference configs = null;
|
||||
int configs_size = 0;
|
||||
|
||||
String[] params = {"load_system_dawg", "tessedit_char_whitelist"};
|
||||
String vals[] = {"F", ""}; //0123456789-.IThisalotfpnex
|
||||
PointerByReference vars_vec = new PointerByReference();
|
||||
vars_vec.setPointer(new StringArray(params));
|
||||
PointerByReference vars_values = new PointerByReference();
|
||||
vars_values.setPointer(new StringArray(vals));
|
||||
NativeSize vars_vec_size = new NativeSize(params.length);
|
||||
|
||||
api.TessBaseAPISetOutputName(handle, output);
|
||||
|
||||
int rc = api.TessBaseAPIInit4(handle, datapath, language,
|
||||
oem, configs, configs_size, vars_vec, vars_values, vars_vec_size, set_only_init_params);
|
||||
|
||||
if (rc != 0) {
|
||||
api.TessBaseAPIDelete(handle);
|
||||
logger.error("Could not initialize tesseract.");
|
||||
return;
|
||||
}
|
||||
|
||||
String outputbase = "target/test-classes/test-results/ResultRenderer";
|
||||
TessResultRenderer renderer = api.TessHOcrRendererCreate(outputbase);
|
||||
api.TessResultRendererInsert(renderer, api.TessBoxTextRendererCreate(outputbase));
|
||||
api.TessResultRendererInsert(renderer, api.TessTextRendererCreate(outputbase));
|
||||
String dataPath = api.TessBaseAPIGetDatapath(handle);
|
||||
api.TessResultRendererInsert(renderer, api.TessPDFRendererCreate(outputbase, dataPath, FALSE));
|
||||
int result = api.TessBaseAPIProcessPages(handle, image, null, 0, renderer);
|
||||
|
||||
if (result == FALSE) {
|
||||
logger.error("Error during processing.");
|
||||
return;
|
||||
}
|
||||
|
||||
while ((renderer = api.TessResultRendererNext(renderer)) != null) {
|
||||
String ext = api.TessResultRendererExtention(renderer).getString(0);
|
||||
logger.info(String.format("TessResultRendererExtention: %s\nTessResultRendererTitle: %s\nTessResultRendererImageNum: %d",
|
||||
ext,
|
||||
api.TessResultRendererTitle(renderer).getString(0),
|
||||
api.TessResultRendererImageNum(renderer)));
|
||||
}
|
||||
|
||||
api.TessDeleteResultRenderer(renderer);
|
||||
assertTrue(new File(outputbase + ".pdf").exists());
|
||||
}
|
||||
}
|
336
d4dj/src/test/java/net/sourceforge/tess4j/Tesseract1Test.java
Normal file
@ -0,0 +1,336 @@
|
||||
/**
|
||||
* Copyright @ 2010 Quan Nguyen
|
||||
*
|
||||
* 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 net.sourceforge.tess4j;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import net.sourceforge.tess4j.util.ImageHelper;
|
||||
import net.sourceforge.tess4j.util.LoggHelper;
|
||||
import net.sourceforge.tess4j.util.Utils;
|
||||
|
||||
import net.sourceforge.tess4j.ITesseract.RenderedFormat;
|
||||
import net.sourceforge.tess4j.ITessAPI.TessPageIteratorLevel;
|
||||
|
||||
import com.recognition.software.jdeskew.ImageDeskew;
|
||||
import java.awt.Graphics2D;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Tesseract1Test {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
static final double MINIMUM_DESKEW_THRESHOLD = 0.05d;
|
||||
ITesseract instance;
|
||||
|
||||
private final String datapath = "src/main/resources/tessdata";
|
||||
private final String testResourcesDataPath = "src/test/resources/test-data";
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
instance = new Tesseract1();
|
||||
instance.setDatapath(new File(datapath).getPath());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract1.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_File() throws Exception {
|
||||
logger.info("doOCR on a PNG image");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(imageFile);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_UNLV_Zone_File() throws Exception {
|
||||
logger.info("doOCR on a PNG image with UNLV zone file .uzn");
|
||||
//UNLV zone format: left top width height label
|
||||
String filename = String.format("%s/%s", this.testResourcesDataPath, "eurotext_unlv.png");
|
||||
File imageFile = new File(filename);
|
||||
String expResult = "& duck/goose, as 12.5% of E-mail\n\n"
|
||||
+ "from aspammer@website.com is spam.\n\n"
|
||||
+ "The (quick) [brown] {fox} jumps!\n"
|
||||
+ "Over the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(imageFile);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.trim().replace('—', '-'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_File_With_Configs() throws Exception {
|
||||
logger.info("doOCR with configs");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
String expResult = "[-0123456789.\n ]+";
|
||||
List<String> configs = Arrays.asList("digits");
|
||||
instance.setConfigs(configs);
|
||||
String result = instance.doOCR(imageFile);
|
||||
logger.info(result);
|
||||
assertTrue(result.matches(expResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract1.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_File_Rectangle() throws Exception {
|
||||
logger.info("doOCR on a BMP image with bounding rectangle");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.bmp");
|
||||
Rectangle rect = new Rectangle(0, 0, 1024, 800); // define an equal or smaller region of interest on the image
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(imageFile, rect);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract1.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_PDF() throws Exception {
|
||||
logger.info("doOCR on a PDF document");
|
||||
File inputFile = new File(this.testResourcesDataPath, "eurotext.pdf");
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(inputFile, null);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract1.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_BufferedImage() throws Exception {
|
||||
logger.info("doOCR on a buffered image of a PNG");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
|
||||
Map<String, Integer> types = new HashMap<>();
|
||||
types.put("TYPE_INT_RGB", BufferedImage.TYPE_INT_RGB);
|
||||
types.put("TYPE_INT_ARGB", BufferedImage.TYPE_INT_ARGB);
|
||||
// types.put("TYPE_INT_ARGB_PRE", BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
// types.put("TYPE_INT_BGR", BufferedImage.TYPE_INT_BGR);
|
||||
// types.put("TYPE_3BYTE_BGR", BufferedImage.TYPE_3BYTE_BGR);
|
||||
// types.put("TYPE_4BYTE_ABGR", BufferedImage.TYPE_4BYTE_ABGR);
|
||||
// types.put("TYPE_4BYTE_ABGR_PRE", BufferedImage.TYPE_4BYTE_ABGR_PRE);
|
||||
// types.put("TYPE_USHORT_565_RGB", BufferedImage.TYPE_USHORT_565_RGB);
|
||||
// types.put("TYPE_USHORT_555_RGB", BufferedImage.TYPE_USHORT_555_RGB);
|
||||
// types.put("TYPE_BYTE_GRAY", BufferedImage.TYPE_BYTE_GRAY);
|
||||
// types.put("TYPE_USHORT_GRAY", BufferedImage.TYPE_USHORT_GRAY);
|
||||
// types.put("TYPE_BYTE_BINARY", BufferedImage.TYPE_BYTE_BINARY);
|
||||
// types.put("TYPE_BYTE_INDEXED", BufferedImage.TYPE_BYTE_INDEXED);
|
||||
|
||||
for (Map.Entry<String, Integer> entry : types.entrySet()) {
|
||||
if (entry.getValue() == bi.getType()) {
|
||||
String result = instance.doOCR(bi);
|
||||
logger.info("BufferedImage type: " + entry.getKey() + " (Original)");
|
||||
logger.info(result);
|
||||
logger.info("");
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
} else {
|
||||
BufferedImage imageWithType = new BufferedImage(bi.getWidth(), bi.getHeight(), entry.getValue());
|
||||
Graphics2D g = imageWithType.createGraphics();
|
||||
g.drawImage(bi, 0, 0, null);
|
||||
g.dispose();
|
||||
|
||||
String result = instance.doOCR(imageWithType);
|
||||
logger.info("BufferedImage type: " + entry.getKey());
|
||||
logger.info(result);
|
||||
logger.info("");
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of deskew algorithm.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_SkewedImage() throws Exception {
|
||||
logger.info("doOCR on a skewed PNG image");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext_deskew.png");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
ImageDeskew id = new ImageDeskew(bi);
|
||||
double imageSkewAngle = id.getSkewAngle(); // determine skew angle
|
||||
if ((imageSkewAngle > MINIMUM_DESKEW_THRESHOLD || imageSkewAngle < -(MINIMUM_DESKEW_THRESHOLD))) {
|
||||
bi = ImageHelper.rotateImage(bi, -imageSkewAngle); // deskew image
|
||||
}
|
||||
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(bi);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of createDocuments method, of class Tesseract1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCreateDocuments() throws Exception {
|
||||
logger.info("createDocuments for an image");
|
||||
File imageFile1 = new File(this.testResourcesDataPath, "eurotext.pdf");
|
||||
File imageFile2 = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
String outputbase1 = "target/test-classes/test-results/docrenderer1-1";
|
||||
String outputbase2 = "target/test-classes/test-results/docrenderer1-2";
|
||||
List<RenderedFormat> formats = new ArrayList<RenderedFormat>(Arrays.asList(RenderedFormat.HOCR, RenderedFormat.PDF, RenderedFormat.TEXT));
|
||||
instance.createDocuments(new String[]{imageFile1.getPath(), imageFile2.getPath()}, new String[]{outputbase1, outputbase2}, formats);
|
||||
assertTrue(new File(outputbase1 + ".pdf").exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getWords method, of class Tesseract1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetWords() throws Exception {
|
||||
logger.info("getWords");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String[] expResults = expResult.split("\\s");
|
||||
|
||||
int pageIteratorLevel = TessPageIteratorLevel.RIL_WORD;
|
||||
logger.info("PageIteratorLevel: " + Utils.getConstantName(pageIteratorLevel, TessPageIteratorLevel.class));
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
List<Word> result = instance.getWords(bi, pageIteratorLevel);
|
||||
|
||||
// print the complete results
|
||||
for (Word word : result) {
|
||||
logger.info(word.toString());
|
||||
}
|
||||
|
||||
List<String> text = new ArrayList<String>();
|
||||
for (Word word : result.subList(0, expResults.length)) {
|
||||
text.add(word.getText().trim());
|
||||
}
|
||||
|
||||
assertArrayEquals(expResults, text.toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getSegmentedRegions method, of class Tesseract1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetSegmentedRegions() throws Exception {
|
||||
logger.info("getSegmentedRegions at given TessPageIteratorLevel");
|
||||
File imageFile = new File(testResourcesDataPath, "eurotext.png");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
int level = TessPageIteratorLevel.RIL_SYMBOL;
|
||||
logger.info("PageIteratorLevel: " + Utils.getConstantName(level, TessPageIteratorLevel.class));
|
||||
List<Rectangle> result = instance.getSegmentedRegions(bi, level);
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
Rectangle rect = result.get(i);
|
||||
logger.info(String.format("Box[%d]: x=%d, y=%d, w=%d, h=%d", i, rect.x, rect.y, rect.width, rect.height));
|
||||
}
|
||||
|
||||
assertTrue(result.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of createDocumentsWithResults method, of class Tesseract1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCreateDocumentsWithResults() throws Exception {
|
||||
logger.info("createDocumentsWithResults for multiple images at given TessPageIteratorLevel");
|
||||
File imageFile1 = new File(this.testResourcesDataPath, "eurotext.pdf");
|
||||
File imageFile2 = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
String outputbase1 = "target/test-classes/test-results/docrenderer1-3";
|
||||
String outputbase2 = "target/test-classes/test-results/docrenderer1-4";
|
||||
List<RenderedFormat> formats = new ArrayList<RenderedFormat>(Arrays.asList(RenderedFormat.HOCR, RenderedFormat.PDF, RenderedFormat.TEXT));
|
||||
List<OCRResult> results = instance.createDocumentsWithResults(new String[]{imageFile1.getPath(), imageFile2.getPath()}, new String[]{outputbase1, outputbase2}, formats, TessPageIteratorLevel.RIL_WORD);
|
||||
assertTrue(new File(outputbase1 + ".pdf").exists());
|
||||
assertEquals(2, results.size());
|
||||
// Not work on Linux because unable to load pdf.ttf
|
||||
// assertTrue(results.get(0).getConfidence() > 0);
|
||||
// assertEquals(66, results.get(0).getWords().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of createDocumentsWithResults method, of class Tesseract1.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCreateDocumentsWithResults1() throws Exception {
|
||||
logger.info("createDocumentsWithResults for a buffered image at given TessPageIteratorLevel");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
String outputbase = "target/test-classes/test-results/docrenderer-5";
|
||||
List<RenderedFormat> formats = new ArrayList<RenderedFormat>(Arrays.asList(RenderedFormat.HOCR, RenderedFormat.PDF, RenderedFormat.TEXT));
|
||||
OCRResult result = instance.createDocumentsWithResults(bi, imageFile.getName(), outputbase, formats, TessPageIteratorLevel.RIL_WORD);
|
||||
assertTrue(new File(outputbase + ".pdf").exists());
|
||||
assertTrue(result.getConfidence() > 0);
|
||||
assertEquals(66, result.getWords().size());
|
||||
}
|
||||
}
|
341
d4dj/src/test/java/net/sourceforge/tess4j/TesseractTest.java
Normal file
@ -0,0 +1,341 @@
|
||||
/**
|
||||
* Copyright @ 2010 Quan Nguyen
|
||||
*
|
||||
* 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 net.sourceforge.tess4j;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import net.sourceforge.tess4j.util.ImageHelper;
|
||||
import net.sourceforge.tess4j.util.LoggHelper;
|
||||
import net.sourceforge.tess4j.util.Utils;
|
||||
|
||||
import net.sourceforge.tess4j.ITesseract.RenderedFormat;
|
||||
import net.sourceforge.tess4j.ITessAPI.TessPageIteratorLevel;
|
||||
|
||||
import com.recognition.software.jdeskew.ImageDeskew;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TesseractTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
static final double MINIMUM_DESKEW_THRESHOLD = 0.05d;
|
||||
ITesseract instance;
|
||||
|
||||
private final String datapath = "src/main/resources/tessdata";
|
||||
private final String testResourcesDataPath = "src/test/resources/test-data";
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
instance = new Tesseract();
|
||||
instance.setDatapath(new File(datapath).getPath());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_File() throws Exception {
|
||||
logger.info("doOCR on a PNG image");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(imageFile);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_UNLV_Zone_File() throws Exception {
|
||||
logger.info("doOCR on a PNG image with UNLV zone file .uzn");
|
||||
//UNLV zone format: left top width height label
|
||||
String filename = String.format("%s/%s", this.testResourcesDataPath, "eurotext_unlv.png");
|
||||
File imageFile = new File(filename);
|
||||
String expResult = "& duck/goose, as 12.5% of E-mail\n\n"
|
||||
+ "from aspammer@website.com is spam.\n\n"
|
||||
+ "The (quick) [brown] {fox} jumps!\n"
|
||||
+ "Over the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(imageFile);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.trim().replace('—', '-'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_File_With_Configs() throws Exception {
|
||||
logger.info("doOCR with configs");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
String expResult = "[-0123456789.\n ]+";
|
||||
List<String> configs = Arrays.asList("digits");
|
||||
instance.setConfigs(configs);
|
||||
String result = instance.doOCR(imageFile);
|
||||
logger.info(result);
|
||||
assertTrue(result.matches(expResult));
|
||||
instance.setConfigs(null); // since Tesseract instance is a singleton, clear configs so the effects do not carry on into subsequent runs.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_File_Rectangle() throws Exception {
|
||||
logger.info("doOCR on a BMP image with bounding rectangle");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.bmp");
|
||||
Rectangle rect = new Rectangle(0, 0, 1024, 800); // define an equal or smaller region of interest on the image
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(imageFile, rect);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_PDF() throws Exception {
|
||||
logger.info("doOCR on a PDF document");
|
||||
File inputFile = new File(this.testResourcesDataPath, "eurotext.pdf");
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
try {
|
||||
String result = instance.doOCR(inputFile, null);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
} catch (TesseractException e) {
|
||||
logger.error("Exception-Message: '{}'. Imagefile: '{}'", e.getMessage(), inputFile.getAbsoluteFile(), e);
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of doOCR method, of class Tesseract.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_BufferedImage() throws Exception {
|
||||
logger.info("doOCR on a buffered image of a PNG");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
|
||||
Map<String, Integer> types = new HashMap<>();
|
||||
types.put("TYPE_INT_RGB", BufferedImage.TYPE_INT_RGB);
|
||||
types.put("TYPE_INT_ARGB", BufferedImage.TYPE_INT_ARGB);
|
||||
types.put("TYPE_INT_ARGB_PRE", BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
types.put("TYPE_INT_BGR", BufferedImage.TYPE_INT_BGR);
|
||||
types.put("TYPE_3BYTE_BGR", BufferedImage.TYPE_3BYTE_BGR);
|
||||
types.put("TYPE_4BYTE_ABGR", BufferedImage.TYPE_4BYTE_ABGR);
|
||||
types.put("TYPE_4BYTE_ABGR_PRE", BufferedImage.TYPE_4BYTE_ABGR_PRE);
|
||||
types.put("TYPE_USHORT_565_RGB", BufferedImage.TYPE_USHORT_565_RGB);
|
||||
types.put("TYPE_USHORT_555_RGB", BufferedImage.TYPE_USHORT_555_RGB);
|
||||
types.put("TYPE_BYTE_GRAY", BufferedImage.TYPE_BYTE_GRAY);
|
||||
types.put("TYPE_USHORT_GRAY", BufferedImage.TYPE_USHORT_GRAY);
|
||||
types.put("TYPE_BYTE_BINARY", BufferedImage.TYPE_BYTE_BINARY);
|
||||
types.put("TYPE_BYTE_INDEXED", BufferedImage.TYPE_BYTE_INDEXED);
|
||||
|
||||
for (Map.Entry<String, Integer> entry : types.entrySet()) {
|
||||
if (entry.getValue() == bi.getType()) {
|
||||
String result = instance.doOCR(bi);
|
||||
logger.info("BufferedImage type: " + entry.getKey() + " (Original)");
|
||||
logger.info(result);
|
||||
logger.info("");
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
} else {
|
||||
BufferedImage imageWithType = new BufferedImage(bi.getWidth(), bi.getHeight(), entry.getValue());
|
||||
Graphics2D g = imageWithType.createGraphics();
|
||||
g.drawImage(bi, 0, 0, null);
|
||||
g.dispose();
|
||||
|
||||
String result = instance.doOCR(imageWithType);
|
||||
logger.info("BufferedImage type: " + entry.getKey());
|
||||
logger.info(result);
|
||||
logger.info("");
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of deskew algorithm.
|
||||
*
|
||||
* @throws Exception while processing image.
|
||||
*/
|
||||
@Test
|
||||
public void testDoOCR_SkewedImage() throws Exception {
|
||||
logger.info("doOCR on a skewed PNG image");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext_deskew.png");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
ImageDeskew id = new ImageDeskew(bi);
|
||||
double imageSkewAngle = id.getSkewAngle(); // determine skew angle
|
||||
if ((imageSkewAngle > MINIMUM_DESKEW_THRESHOLD || imageSkewAngle < -(MINIMUM_DESKEW_THRESHOLD))) {
|
||||
bi = ImageHelper.rotateImage(bi, -imageSkewAngle); // deskew image
|
||||
}
|
||||
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String result = instance.doOCR(bi);
|
||||
logger.info(result);
|
||||
assertEquals(expResult, result.substring(0, expResult.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of createDocuments method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCreateDocuments() throws Exception {
|
||||
logger.info("createDocuments for multiple images");
|
||||
File imageFile1 = new File(this.testResourcesDataPath, "eurotext.pdf");
|
||||
File imageFile2 = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
String outputbase1 = "target/test-classes/test-results/docrenderer-1";
|
||||
String outputbase2 = "target/test-classes/test-results/docrenderer-2";
|
||||
List<RenderedFormat> formats = new ArrayList<RenderedFormat>(Arrays.asList(RenderedFormat.HOCR, RenderedFormat.PDF, RenderedFormat.TEXT));
|
||||
instance.createDocuments(new String[]{imageFile1.getPath(), imageFile2.getPath()}, new String[]{outputbase1, outputbase2}, formats);
|
||||
assertTrue(new File(outputbase1 + ".pdf").exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getWords method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetWords() throws Exception {
|
||||
logger.info("getWords");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
|
||||
String expResult = "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog";
|
||||
String[] expResults = expResult.split("\\s");
|
||||
|
||||
int pageIteratorLevel = TessPageIteratorLevel.RIL_WORD;
|
||||
logger.info("PageIteratorLevel: " + Utils.getConstantName(pageIteratorLevel, TessPageIteratorLevel.class));
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
List<Word> result = instance.getWords(bi, pageIteratorLevel);
|
||||
|
||||
//print the complete results
|
||||
for (Word word : result) {
|
||||
logger.info(word.toString());
|
||||
}
|
||||
|
||||
List<String> text = new ArrayList<String>();
|
||||
for (Word word : result.subList(0, expResults.length)) {
|
||||
text.add(word.getText().trim());
|
||||
}
|
||||
|
||||
assertArrayEquals(expResults, text.toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getSegmentedRegions method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetSegmentedRegions() throws Exception {
|
||||
logger.info("getSegmentedRegions at given TessPageIteratorLevel");
|
||||
File imageFile = new File(testResourcesDataPath, "eurotext.png");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
int level = TessPageIteratorLevel.RIL_SYMBOL;
|
||||
logger.info("PageIteratorLevel: " + Utils.getConstantName(level, TessPageIteratorLevel.class));
|
||||
List<Rectangle> result = instance.getSegmentedRegions(bi, level);
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
Rectangle rect = result.get(i);
|
||||
logger.info(String.format("Box[%d]: x=%d, y=%d, w=%d, h=%d", i, rect.x, rect.y, rect.width, rect.height));
|
||||
}
|
||||
|
||||
assertTrue(result.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of createDocumentsWithResults method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCreateDocumentsWithResults() throws Exception {
|
||||
logger.info("createDocumentsWithResults for multiple images at given TessPageIteratorLevel");
|
||||
File imageFile1 = new File(this.testResourcesDataPath, "eurotext.pdf");
|
||||
File imageFile2 = new File(this.testResourcesDataPath, "eurotext.png");
|
||||
String outputbase1 = "target/test-classes/test-results/docrenderer-3";
|
||||
String outputbase2 = "target/test-classes/test-results/docrenderer-4";
|
||||
List<RenderedFormat> formats = new ArrayList<RenderedFormat>(Arrays.asList(RenderedFormat.HOCR, RenderedFormat.PDF, RenderedFormat.TEXT));
|
||||
List<OCRResult> results = instance.createDocumentsWithResults(new String[]{imageFile1.getPath(), imageFile2.getPath()}, new String[]{outputbase1, outputbase2}, formats, TessPageIteratorLevel.RIL_WORD);
|
||||
assertTrue(new File(outputbase1 + ".pdf").exists());
|
||||
assertEquals(2, results.size());
|
||||
assertTrue(results.get(0).getConfidence() > 0);
|
||||
assertEquals(66, results.get(0).getWords().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of createDocumentsWithResults method, of class Tesseract.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCreateDocumentsWithResults1() throws Exception {
|
||||
logger.info("createDocumentsWithResults for a buffered image at given TessPageIteratorLevel");
|
||||
File imageFile = new File(this.testResourcesDataPath, "eurotext.tif");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
String outputbase = "target/test-classes/test-results/docrenderer-5";
|
||||
List<RenderedFormat> formats = new ArrayList<RenderedFormat>(Arrays.asList(RenderedFormat.HOCR, RenderedFormat.PDF, RenderedFormat.TEXT));
|
||||
OCRResult result = instance.createDocumentsWithResults(bi, imageFile.getName(), outputbase, formats, TessPageIteratorLevel.RIL_WORD);
|
||||
assertTrue(new File(outputbase + ".pdf").exists());
|
||||
assertTrue(result.getConfidence() > 0);
|
||||
assertEquals(66, result.getWords().size());
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright @ 2008 Quan Nguyen
|
||||
*
|
||||
* 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 net.sourceforge.tess4j;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import net.sourceforge.tess4j.util.LoadLibs;
|
||||
import net.sourceforge.tess4j.util.LoggHelper;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TestFolderExtraction {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
|
||||
@Test
|
||||
public void testFolderExtraction() {
|
||||
File tessDataFolder = null;
|
||||
|
||||
try {
|
||||
/**
|
||||
* Loads the image from resources.
|
||||
*/
|
||||
String filename = String.format("%s/%s", "/test-data", "eurotext.pdf");
|
||||
URL defaultImage = getClass().getResource(filename);
|
||||
File imageFile = new File(defaultImage.toURI());
|
||||
|
||||
/**
|
||||
* Extracts <code>tessdata</code> folder into a temp folder.
|
||||
*/
|
||||
logger.info("Loading the tessdata folder into a temporary folder.");
|
||||
tessDataFolder = LoadLibs.extractTessResources("tessdata");
|
||||
|
||||
/**
|
||||
* Gets tesseract instance and sets data path.
|
||||
*/
|
||||
ITesseract instance = new Tesseract();
|
||||
|
||||
if (tessDataFolder != null) {
|
||||
logger.info(tessDataFolder.getAbsolutePath());
|
||||
instance.setDatapath(tessDataFolder.getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs OCR on the image.
|
||||
*/
|
||||
String result = instance.doOCR(imageFile);
|
||||
logger.info(result);
|
||||
} catch (TesseractException e) {
|
||||
logger.error(e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (URISyntaxException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
// checks if tessdata folder exists
|
||||
assertTrue(tessDataFolder != null && tessDataFolder.exists());
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright @ 2008 Quan Nguyen
|
||||
*
|
||||
* 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 net.sourceforge.tess4j.util;
|
||||
|
||||
import com.recognition.software.jdeskew.ImageDeskew;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ImageIOHelperTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
private static final String TEST_RESOURCES_DATA_PATH = "src/test/resources/test-data/";
|
||||
private static final String TEST_RESOURCES_RESULTS_PATH = "src/test/resources/test-results/";
|
||||
private static final double MINIMUM_DESKEW_THRESHOLD = 0.05d;
|
||||
|
||||
public ImageIOHelperTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of createTiffFiles method, of class ImageIOHelper.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCreateTiffFiles_File_int() throws Exception {
|
||||
logger.info("createTiffFiles");
|
||||
File imageFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.png");
|
||||
int index = 0;
|
||||
int expResult = 1;
|
||||
List<File> result = ImageIOHelper.createTiffFiles(imageFile, index);
|
||||
assertEquals(expResult, result.size());
|
||||
|
||||
// cleanup
|
||||
for (File f : result) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getImageFileFormat method, of class ImageIOHelper.
|
||||
*/
|
||||
@Test
|
||||
public void testGetImageFileFormat() {
|
||||
logger.info("getImageFileFormat");
|
||||
File imageFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.png");
|
||||
String expResult = "png";
|
||||
String result = ImageIOHelper.getImageFileFormat(imageFile);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getImageFile method, of class ImageIOHelper.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetImageFile() throws Exception {
|
||||
logger.info("getImageFile");
|
||||
File inputFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.png");
|
||||
File expResult = new File(TEST_RESOURCES_DATA_PATH, "eurotext.png");
|
||||
File result = ImageIOHelper.getImageFile(inputFile);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getImageList method, of class ImageIOHelper.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetImageList() throws Exception {
|
||||
logger.info("getImageList");
|
||||
File imageFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.pdf");
|
||||
int expResult = 1;
|
||||
List<BufferedImage> result = ImageIOHelper.getImageList(imageFile);
|
||||
assertEquals(expResult, result.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getIIOImageList method, of class ImageIOHelper.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetIIOImageList_File() throws Exception {
|
||||
logger.info("getIIOImageList");
|
||||
File imageFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.pdf");
|
||||
int expResult = 1;
|
||||
List<IIOImage> result = ImageIOHelper.getIIOImageList(imageFile);
|
||||
assertEquals(expResult, result.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getIIOImageList method, of class ImageIOHelper.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetIIOImageList_BufferedImage() throws Exception {
|
||||
logger.info("getIIOImageList");
|
||||
File imageFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.png");
|
||||
BufferedImage bi = ImageIO.read(imageFile);
|
||||
int expResult = 1;
|
||||
List<IIOImage> result = ImageIOHelper.getIIOImageList(bi);
|
||||
assertEquals(expResult, result.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of mergeTiff method, of class ImageIOHelper.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testMergeTiff_FileArr_File() throws Exception {
|
||||
logger.info("mergeTiff");
|
||||
File imageFile1 = new File(TEST_RESOURCES_DATA_PATH, "eurotext.png"); // filesize: 14,854 bytes
|
||||
File imageFile2 = new File(TEST_RESOURCES_DATA_PATH, "eurotext_deskew.png"); // filesize: 204,383 bytes
|
||||
File[] inputImages = {imageFile1, imageFile2};
|
||||
File outputTiff = new File(TEST_RESOURCES_RESULTS_PATH, "mergedTiff.tif");
|
||||
long expResult = 224337L; // filesize: 224,337 bytes
|
||||
ImageIOHelper.mergeTiff(inputImages, outputTiff);
|
||||
assertEquals(expResult, outputTiff.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of deskewImage method, of class ImageIOHelper.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testDeskewImage() throws Exception {
|
||||
logger.info("deskewImage");
|
||||
File imageFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext_deskew.png");
|
||||
double minimumDeskewThreshold = MINIMUM_DESKEW_THRESHOLD;
|
||||
double initAngle = new ImageDeskew(ImageIO.read(imageFile)).getSkewAngle();
|
||||
File result = ImageIOHelper.deskewImage(imageFile, minimumDeskewThreshold);
|
||||
double resultAngle = new ImageDeskew(ImageIO.read(result)).getSkewAngle();
|
||||
assertTrue(Math.abs(resultAngle) < Math.abs(initAngle));
|
||||
// cleanup
|
||||
result.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of readImageData method, of class ImageIOHelper.
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Test
|
||||
public void testReadImageData() throws IOException {
|
||||
logger.info("readImageData");
|
||||
File imageFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.png");
|
||||
List<IIOImage> oimages = ImageIOHelper.getIIOImageList(imageFile);
|
||||
IIOImage oimage = oimages.get(0);
|
||||
int expResultDpiX = 300;
|
||||
int expResultDpiY = 300;
|
||||
Map<String, String> result = ImageIOHelper.readImageData(oimage);
|
||||
assertEquals(String.valueOf(expResultDpiX), result.get("dpiX"));
|
||||
assertEquals(String.valueOf(expResultDpiY), result.get("dpiY"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2014 Quan Nguyen.
|
||||
*
|
||||
* 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 net.sourceforge.tess4j.util;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
|
||||
public class PdfUtilitiesTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
|
||||
private static final String TEST_RESOURCES_DATA_PATH = "src/test/resources/test-data/";
|
||||
private static final String TEST_RESOURCES_RESULTS_PATH = "src/test/resources/test-results/";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
System.setProperty(PdfUtilities.PDF_LIBRARY, PdfUtilities.PDFBOX); // Note: comment out to test Ghostscript
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of convertPdf2Tiff method, of class PdfUtilities.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Test
|
||||
public void testConvertPdf2Tiff() throws Exception {
|
||||
logger.info("convertPdf2Tiff");
|
||||
File inputPdfFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.pdf");
|
||||
File result = PdfUtilities.convertPdf2Tiff(inputPdfFile);
|
||||
result.deleteOnExit();
|
||||
assertTrue(result.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of convertPdf2Png method, of class PdfUtilities.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Test
|
||||
public void testConvertPdf2Png() throws IOException {
|
||||
logger.info("convertPdf2Png");
|
||||
File inputPdfFile = new File(TEST_RESOURCES_DATA_PATH, "eurotext.pdf");
|
||||
File[] results = PdfUtilities.convertPdf2Png(inputPdfFile);
|
||||
assertTrue(results.length > 0);
|
||||
|
||||
//clean up
|
||||
File parentDir = results[0].getParentFile();
|
||||
for (File result : results) {
|
||||
result.delete();
|
||||
}
|
||||
parentDir.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of splitPdf method, of class PdfUtilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSplitPdf() {
|
||||
logger.info("splitPdf");
|
||||
File inputPdfFile = new File(String.format("%s/%s", TEST_RESOURCES_DATA_PATH, "multipage-pdf.pdf"));
|
||||
File outputPdfFile = new File(String.format("%s/%s", TEST_RESOURCES_RESULTS_PATH, "multipage-pdf_splitted.pdf"));
|
||||
int startPage = 2;
|
||||
int endPage = 3;
|
||||
int expResult = 2;
|
||||
PdfUtilities.splitPdf(inputPdfFile, outputPdfFile, startPage, endPage);
|
||||
int pageCount = PdfUtilities.getPdfPageCount(outputPdfFile);
|
||||
assertEquals(expResult, pageCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getPdfPageCount method, of class PdfUtilities.
|
||||
*/
|
||||
@Test
|
||||
public void testGetPdfPageCount() {
|
||||
logger.info("getPdfPageCount");
|
||||
File inputPdfFile = new File(TEST_RESOURCES_DATA_PATH, "multipage-pdf.pdf");
|
||||
int expResult = 5;
|
||||
int result = PdfUtilities.getPdfPageCount(inputPdfFile);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of mergePdf method, of class PdfUtilities.
|
||||
*/
|
||||
@Test
|
||||
public void testMergePdf() {
|
||||
logger.info("mergePdf");
|
||||
File pdfPartOne = new File(String.format("%s/%s", TEST_RESOURCES_DATA_PATH, "eurotext.pdf"));
|
||||
File pdfPartTwo = new File(String.format("%s/%s", TEST_RESOURCES_DATA_PATH, "multipage-pdf.pdf"));
|
||||
int expResult = 6;
|
||||
File outputPdfFile = new File(String.format("%s/%s", TEST_RESOURCES_RESULTS_PATH, "multipage-pdf_merged.pdf"));
|
||||
File[] inputPdfFiles = {pdfPartOne, pdfPartTwo};
|
||||
PdfUtilities.mergePdf(inputPdfFiles, outputPdfFile);
|
||||
assertEquals(expResult, PdfUtilities.getPdfPageCount(outputPdfFile));
|
||||
}
|
||||
|
||||
}
|
9
d4dj/src/test/resources/log4j.properties
Normal file
@ -0,0 +1,9 @@
|
||||
# Set root logger level to DEBUG and its only appender to A1.
|
||||
log4j.rootLogger=DEBUG, A1
|
||||
|
||||
# A1 is set to be a ConsoleAppender.
|
||||
log4j.appender.A1=org.apache.log4j.ConsoleAppender
|
||||
|
||||
# A1 uses PatternLayout.
|
||||
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
|
15
d4dj/src/test/resources/logback-test.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.levigo" level="info" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
BIN
d4dj/src/test/resources/test-data/eurotext.bmp
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
d4dj/src/test/resources/test-data/eurotext.pdf
Normal file
BIN
d4dj/src/test/resources/test-data/eurotext.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
d4dj/src/test/resources/test-data/eurotext.tif
Normal file
BIN
d4dj/src/test/resources/test-data/eurotext90.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
d4dj/src/test/resources/test-data/eurotext_deskew.png
Normal file
After Width: | Height: | Size: 200 KiB |
BIN
d4dj/src/test/resources/test-data/eurotext_unlv.png
Normal file
After Width: | Height: | Size: 14 KiB |
3
d4dj/src/test/resources/test-data/eurotext_unlv.uzn
Normal file
@ -0,0 +1,3 @@
|
||||
97 162 747 50 ThirdLine
|
||||
97 209 828 55 FourthLine
|
||||
92 56 810 107 First2Lines
|
BIN
d4dj/src/test/resources/test-data/multipage-pdf.pdf
Normal file
4
d4dj/src/test/resources/test-results/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|