D4DJ leaderboard parsing bot

old
Joshua Sigona 4 years ago
commit fcc8861aa2
  1. 27
      d4dj/.classpath
  2. 23
      d4dj/.project
  3. 4
      d4dj/.settings/org.eclipse.core.resources.prefs
  4. 8
      d4dj/.settings/org.eclipse.jdt.core.prefs
  5. 4
      d4dj/.settings/org.eclipse.m2e.core.prefs
  6. BIN
      d4dj/imgtest1.png
  7. BIN
      d4dj/imgtest2.png
  8. BIN
      d4dj/imgtest3.png
  9. BIN
      d4dj/imgtest4.png
  10. BIN
      d4dj/imgtest5.png
  11. 86
      d4dj/pom.xml
  12. 180
      d4dj/src/main/java/com/recognition/software/jdeskew/ImageDeskew.java
  13. 138
      d4dj/src/main/java/com/recognition/software/jdeskew/ImageUtil.java
  14. 177
      d4dj/src/main/java/d4dj/d4dj/App.java
  15. 284
      d4dj/src/main/java/org/json/CDL.java
  16. 169
      d4dj/src/main/java/org/json/Cookie.java
  17. 89
      d4dj/src/main/java/org/json/CookieList.java
  18. 164
      d4dj/src/main/java/org/json/HTTP.java
  19. 77
      d4dj/src/main/java/org/json/HTTPTokener.java
  20. 1200
      d4dj/src/main/java/org/json/JSONArray.java
  21. 45
      d4dj/src/main/java/org/json/JSONException.java
  22. 552
      d4dj/src/main/java/org/json/JSONML.java
  23. 1938
      d4dj/src/main/java/org/json/JSONObject.java
  24. 267
      d4dj/src/main/java/org/json/JSONPointer.java
  25. 45
      d4dj/src/main/java/org/json/JSONPointerException.java
  26. 18
      d4dj/src/main/java/org/json/JSONString.java
  27. 78
      d4dj/src/main/java/org/json/JSONStringer.java
  28. 475
      d4dj/src/main/java/org/json/JSONTokener.java
  29. 326
      d4dj/src/main/java/org/json/JSONWriter.java
  30. 72
      d4dj/src/main/java/org/json/Property.java
  31. 621
      d4dj/src/main/java/org/json/XML.java
  32. 365
      d4dj/src/main/java/org/json/XMLTokener.java
  33. 219
      d4dj/src/main/java/sig/utils/Audio.java
  34. 17
      d4dj/src/main/java/sig/utils/DebugUtils.java
  35. 112
      d4dj/src/main/java/sig/utils/DrawUtils.java
  36. 380
      d4dj/src/main/java/sig/utils/FileUtils.java
  37. 35
      d4dj/src/main/java/sig/utils/GithubUtils.java
  38. 94
      d4dj/src/main/java/sig/utils/ImageUtils.java
  39. 39
      d4dj/src/main/java/sig/utils/JavaUtils.java
  40. 10
      d4dj/src/main/java/sig/utils/ReflectUtils.java
  41. 30
      d4dj/src/main/java/sig/utils/SoundUtils.java
  42. 85
      d4dj/src/main/java/sig/utils/TextUtils.java
  43. 32
      d4dj/src/main/java/sig/utils/TimeUtils.java
  44. 124
      d4dj/src/main/resources/readme.html
  45. 1
      d4dj/src/main/resources/tessdata/configs/alto
  46. 1
      d4dj/src/main/resources/tessdata/configs/api_config
  47. 4
      d4dj/src/main/resources/tessdata/configs/bazaar
  48. 1
      d4dj/src/main/resources/tessdata/configs/digits
  49. 2
      d4dj/src/main/resources/tessdata/configs/hocr
  50. 1
      d4dj/src/main/resources/tessdata/configs/lstmbox
  51. 1
      d4dj/src/main/resources/tessdata/configs/pdf
  52. 1
      d4dj/src/main/resources/tessdata/configs/quiet
  53. 1
      d4dj/src/main/resources/tessdata/configs/tsv
  54. 3
      d4dj/src/main/resources/tessdata/configs/txt
  55. 2
      d4dj/src/main/resources/tessdata/configs/unlv
  56. 1
      d4dj/src/main/resources/tessdata/configs/wordstrbox
  57. BIN
      d4dj/src/main/resources/tessdata/eng.traineddata
  58. BIN
      d4dj/src/main/resources/tessdata/osd.traineddata
  59. BIN
      d4dj/src/main/resources/tessdata/pdf.ttf
  60. 199
      d4dj/src/main/resources/versionchanges.txt
  61. BIN
      d4dj/src/main/resources/win32-x86-64/libtesseract500.dll
  62. BIN
      d4dj/src/main/resources/win32-x86/libtesseract500.dll
  63. 20
      d4dj/src/test/java/d4dj/d4dj/AppTest.java
  64. 75
      d4dj/src/test/java/net/sourceforge/tess4j/ProgressMonitor.java
  65. 704
      d4dj/src/test/java/net/sourceforge/tess4j/TessAPI1Test.java
  66. 695
      d4dj/src/test/java/net/sourceforge/tess4j/TessAPIImpl.java
  67. 711
      d4dj/src/test/java/net/sourceforge/tess4j/TessAPITest.java
  68. 336
      d4dj/src/test/java/net/sourceforge/tess4j/Tesseract1Test.java
  69. 341
      d4dj/src/test/java/net/sourceforge/tess4j/TesseractTest.java
  70. 79
      d4dj/src/test/java/net/sourceforge/tess4j/TestFolderExtraction.java
  71. 195
      d4dj/src/test/java/net/sourceforge/tess4j/util/ImageIOHelperTest.java
  72. 117
      d4dj/src/test/java/net/sourceforge/tess4j/util/PdfUtilitiesTest.java
  73. 9
      d4dj/src/test/resources/log4j.properties
  74. 15
      d4dj/src/test/resources/logback-test.xml
  75. BIN
      d4dj/src/test/resources/test-data/eurotext.bmp
  76. BIN
      d4dj/src/test/resources/test-data/eurotext.pdf
  77. BIN
      d4dj/src/test/resources/test-data/eurotext.png
  78. BIN
      d4dj/src/test/resources/test-data/eurotext.tif
  79. BIN
      d4dj/src/test/resources/test-data/eurotext90.png
  80. BIN
      d4dj/src/test/resources/test-data/eurotext_deskew.png
  81. BIN
      d4dj/src/test/resources/test-data/eurotext_unlv.png
  82. 3
      d4dj/src/test/resources/test-data/eurotext_unlv.uzn
  83. BIN
      d4dj/src/test/resources/test-data/multipage-pdf.pdf
  84. 4
      d4dj/src/test/resources/test-results/.gitignore
  85. BIN
      d4dj/target/classes/com/recognition/software/jdeskew/ImageDeskew$HoughLine.class
  86. BIN
      d4dj/target/classes/com/recognition/software/jdeskew/ImageDeskew.class
  87. BIN
      d4dj/target/classes/com/recognition/software/jdeskew/ImageUtil.class
  88. BIN
      d4dj/target/classes/d4dj/d4dj/App.class
  89. BIN
      d4dj/target/classes/d4dj/d4dj/SubmitThread.class
  90. BIN
      d4dj/target/classes/org/json/CDL.class
  91. BIN
      d4dj/target/classes/org/json/Cookie.class
  92. BIN
      d4dj/target/classes/org/json/CookieList.class
  93. BIN
      d4dj/target/classes/org/json/HTTP.class
  94. BIN
      d4dj/target/classes/org/json/HTTPTokener.class
  95. BIN
      d4dj/target/classes/org/json/JSONArray.class
  96. BIN
      d4dj/target/classes/org/json/JSONException.class
  97. BIN
      d4dj/target/classes/org/json/JSONML.class
  98. BIN
      d4dj/target/classes/org/json/JSONObject$Null.class
  99. BIN
      d4dj/target/classes/org/json/JSONObject.class
  100. BIN
      d4dj/target/classes/org/json/JSONPointer$Builder.class
  101. Some files were not shown because too many files have changed in this diff Show More

@ -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>

@ -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>

@ -0,0 +1,4 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8

@ -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

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

@ -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;
}
}

@ -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();
}
}
}
}

@ -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();
}
}

@ -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>&nbsp;<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();
}
}

@ -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();
}
}

@ -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();
}
}

@ -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();
}
}
}

File diff suppressed because it is too large Load Diff

@ -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);
}
}

@ -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>&lt;[ [ ]]></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>&lt;[ [ ]]></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>&lt;[ [ ]]></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>&lt;[ [ ]]></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>&lt;[ [ ]]></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>&lt;[ [ ]]></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>&lt;[ [ ]]></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>&lt;[ [ ]]></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();
}
}

File diff suppressed because it is too large Load Diff

@ -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);
}
}
}

@ -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);
}
}

@ -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();
}

@ -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;
}
}

@ -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>&nbsp;<small>(double quote)</small> or
* <code>'</code>&nbsp;<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 + "]";
}
}

@ -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));
}
}

@ -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;
}
}

@ -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 '&amp;'. */
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 '&lt;'. */
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>
* &amp; <small>(ampersand)</small> is replaced by &amp;amp;
* &lt; <small>(less than)</small> is replaced by &amp;lt;
* &gt; <small>(greater than)</small> is replaced by &amp;gt;
* &quot; <small>(double quote)</small> is replaced by &amp;quot;
* &apos; <small>(single quote / apostrophe)</small> is replaced by &amp;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("&amp;");
break;
case '<':
sb.append("&lt;");
break;
case '>':
sb.append("&gt;");
break;
case '"':
sb.append("&quot;");
break;
case '\'':
sb.append("&apos;");
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>&lt;[ [ ]]></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>&lt;[ [ ]]></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 + ">";
}
}

@ -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>]]&gt;</code>.
* @throws JSONException If the <code>]]&gt;</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>&amp; &apos; &gt; &lt; &quot;</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;
}
}
}
}

@ -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();
}
}

@ -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();
}
}

@ -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);
}
}

@ -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...");
}
}
}

@ -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;
}
}

@ -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));
}
}

@ -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();
}
}

@ -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;
}
}

@ -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();
}
}
}

@ -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]));
}
}

@ -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();
}
}

@ -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&amp;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&amp;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>

@ -0,0 +1,4 @@
load_system_dawg F
load_freq_dawg F
user_words_suffix user-words
user_patterns_suffix user-patterns

@ -0,0 +1 @@
tessedit_char_whitelist 0123456789-.

@ -0,0 +1,2 @@
tessedit_create_hocr 1
hocr_font_info 0

@ -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

@ -0,0 +1,2 @@
tessedit_write_unlv 1
unlv_tilde_crunching T

@ -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)

@ -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;
}
}

@ -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());
}
}

@ -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.");
}
}

@ -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());
}
}

@ -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());
}
}

@ -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));
}
}

@ -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

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

@ -0,0 +1,3 @@
97 162 747 50 ThirdLine
97 209 828 55 FourthLine
92 56 810 107 First2Lines

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save