After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 235 B |
@ -0,0 +1,101 @@ |
|||||||
|
<?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> |
||||||
|
<dependencyManagement> |
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>com.google.cloud</groupId> |
||||||
|
<artifactId>libraries-bom</artifactId> |
||||||
|
<version>18.0.0</version> |
||||||
|
<type>pom</type> |
||||||
|
<scope>import</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
</dependencyManagement> |
||||||
|
|
||||||
|
<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>com.google.cloud</groupId> |
||||||
|
<artifactId>google-cloud-vision</artifactId> |
||||||
|
</dependency> |
||||||
|
<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,343 @@ |
|||||||
|
package d4dj.d4dj; |
||||||
|
|
||||||
|
import java.awt.Graphics2D; |
||||||
|
import java.awt.Image; |
||||||
|
import java.awt.Point; |
||||||
|
import java.awt.Rectangle; |
||||||
|
import java.awt.image.BufferedImage; |
||||||
|
import java.awt.image.ImageObserver; |
||||||
|
import java.io.File; |
||||||
|
import java.io.FileInputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.io.UnsupportedEncodingException; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.nio.file.Paths; |
||||||
|
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 com.google.cloud.vision.v1.ImageAnnotatorClient; |
||||||
|
import com.google.cloud.vision.v1.AnnotateImageRequest; |
||||||
|
import com.google.cloud.vision.v1.AnnotateImageResponse; |
||||||
|
import com.google.cloud.vision.v1.BatchAnnotateImagesResponse; |
||||||
|
import com.google.cloud.vision.v1.EntityAnnotation; |
||||||
|
import com.google.cloud.vision.v1.Feature; |
||||||
|
import com.google.cloud.vision.v1.Feature.Type; |
||||||
|
import com.google.cloud.vision.v1.ImageAnnotatorClient; |
||||||
|
import com.google.protobuf.ByteString; |
||||||
|
import java.nio.file.Files; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.nio.file.Paths; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
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("Rank "+rank+": "+result); |
||||||
|
instream.close(); |
||||||
|
} catch (UnsupportedOperationException | IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
public class App |
||||||
|
{ |
||||||
|
public static Image paragraph; |
||||||
|
final static int EVENT = 11; |
||||||
|
|
||||||
|
public static void main( String[] args ) throws IOException |
||||||
|
{ |
||||||
|
Rectangle[] cropPoints1 = { |
||||||
|
new Rectangle(295,164,200,26), |
||||||
|
new Rectangle(295,240,200,26), |
||||||
|
new Rectangle(295,318,200,26), |
||||||
|
new Rectangle(295,396,200,26), |
||||||
|
new Rectangle(295,474,200,26), |
||||||
|
new Rectangle(295,551,200,26), |
||||||
|
new Rectangle(295,628,200,26), |
||||||
|
new Rectangle(295,705,200,26), |
||||||
|
new Rectangle(295,783,200,26), |
||||||
|
}; |
||||||
|
Rectangle[] cropPoints2 = { |
||||||
|
new Rectangle(295,537,200,26), |
||||||
|
new Rectangle(295,614,200,26) |
||||||
|
}; |
||||||
|
Rectangle[] cropPoints3 = { |
||||||
|
new Rectangle(295,183,200,26), |
||||||
|
new Rectangle(295,259,200,26), |
||||||
|
new Rectangle(295,338,200,26), |
||||||
|
new Rectangle(295,415,200,26), |
||||||
|
new Rectangle(295,493,200,26), |
||||||
|
new Rectangle(295,570,200,26), |
||||||
|
new Rectangle(295,647,200,26), |
||||||
|
new Rectangle(295,724,200,26), |
||||||
|
new Rectangle(295,802,200,26) |
||||||
|
}; |
||||||
|
|
||||||
|
File folder = new File("screenshots"); |
||||||
|
File[] list2 = folder.listFiles(); |
||||||
|
for (File fff : list2) { |
||||||
|
fff.delete(); |
||||||
|
} |
||||||
|
while (true) { |
||||||
|
File f = new File("screenshots"); |
||||||
|
if (f.listFiles().length==5) { |
||||||
|
//New files found!
|
||||||
|
|
||||||
|
|
||||||
|
//Grab the first 5 files and try to parse them.
|
||||||
|
File[] list = f.listFiles(); |
||||||
|
try { |
||||||
|
Image leaderboard = ImageIO.read(list[0]); |
||||||
|
Image leaderboard2 = ImageIO.read(list[1]); |
||||||
|
Image leaderboard3 = ImageIO.read(list[2]); |
||||||
|
Image leaderboard4 = ImageIO.read(list[3]); |
||||||
|
Image leaderboard5 = ImageIO.read(list[4]); |
||||||
|
paragraph = ImageIO.read(new File("paragraph.png")); |
||||||
|
BufferedImage cropped1 = new BufferedImage(360,26*114,BufferedImage.TYPE_INT_ARGB); |
||||||
|
Graphics2D g = cropped1.createGraphics(); |
||||||
|
//For comments: down by 40, width is 340.
|
||||||
|
for (int i=0;i<cropPoints1.length;i++) { |
||||||
|
drawData(g,leaderboard, 20, i*26, 200, i*26+26, cropPoints1[i].x, cropPoints1[i].y, cropPoints1[i].x+cropPoints1[i].width, cropPoints1[i].y+cropPoints1[i].height, null); |
||||||
|
drawData(g,leaderboard, 20, (i+20)*26, 340, (i+20)*26+26, cropPoints1[i].x, cropPoints1[i].y+40, cropPoints1[i].x+340, cropPoints1[i].y+cropPoints1[i].height+40, null); |
||||||
|
drawData(g,leaderboard, 20, (i+40)*26, 130, (i+40)*26+24, cropPoints1[i].x+351, cropPoints1[i].y+34, cropPoints1[i].x+481, cropPoints1[i].y+58, null); |
||||||
|
} |
||||||
|
for (int i=0;i<cropPoints2.length;i++) { |
||||||
|
drawData(g,leaderboard2, 20, (i+9)*26, 200, (i+9)*26+26, cropPoints2[i].x, cropPoints2[i].y, cropPoints2[i].x+cropPoints2[i].width, cropPoints2[i].y+cropPoints2[i].height, null); |
||||||
|
drawData(g,leaderboard2, 20, (i+29)*26, 340, (i+29)*26+26, cropPoints2[i].x, cropPoints2[i].y+40, cropPoints2[i].x+340, cropPoints2[i].y+cropPoints2[i].height+40, null); |
||||||
|
drawData(g,leaderboard2, 20, (i+49)*26, 130, (i+49)*26+24, cropPoints2[i].x+351, cropPoints2[i].y+34, cropPoints2[i].x+481, cropPoints2[i].y+58, null); |
||||||
|
} |
||||||
|
for (int i=0;i<cropPoints3.length;i++) { |
||||||
|
drawData(g,leaderboard3, 20, (i+11)*26, 200, (i+11)*26+26, cropPoints3[i].x, cropPoints3[i].y, cropPoints3[i].x+cropPoints3[i].width, cropPoints3[i].y+cropPoints3[i].height, null); |
||||||
|
drawData(g,leaderboard3, 20, (i+31)*26, 340, (i+31)*26+26, cropPoints3[i].x, cropPoints3[i].y+40, cropPoints3[i].x+340, cropPoints3[i].y+cropPoints3[i].height+40, null); |
||||||
|
drawData(g,leaderboard3, 20, (i+51)*26, 130, (i+51)*26+24, cropPoints3[i].x+351, cropPoints3[i].y+34, cropPoints3[i].x+481, cropPoints3[i].y+58, null); |
||||||
|
} |
||||||
|
for (int i=0;i<cropPoints1.length;i++) { |
||||||
|
drawData(g,leaderboard4, 20, (i+60)*26, 200, (i+60)*26+26, cropPoints1[i].x, cropPoints1[i].y, cropPoints1[i].x+cropPoints1[i].width, cropPoints1[i].y+cropPoints1[i].height, null); |
||||||
|
drawData(g,leaderboard4, 20, (i+78)*26, 340, (i+78)*26+26, cropPoints1[i].x, cropPoints1[i].y+40, cropPoints1[i].x+340, cropPoints1[i].y+cropPoints1[i].height+40, null); |
||||||
|
drawData(g,leaderboard4, 20, (i+96)*26, 130, (i+96)*26+24, cropPoints1[i].x+351, cropPoints1[i].y+34, cropPoints1[i].x+481, cropPoints1[i].y+58, null); |
||||||
|
} |
||||||
|
for (int i=0;i<cropPoints3.length;i++) { |
||||||
|
drawData(g,leaderboard5, 20, (i+69)*26, 200, (i+69)*26+26, cropPoints3[i].x, cropPoints3[i].y, cropPoints3[i].x+cropPoints3[i].width, cropPoints3[i].y+cropPoints3[i].height, null); |
||||||
|
drawData(g,leaderboard5, 20, (i+87)*26, 340, (i+87)*26+26, cropPoints3[i].x, cropPoints3[i].y+40, cropPoints3[i].x+340, cropPoints3[i].y+cropPoints3[i].height+40, null); |
||||||
|
drawData(g,leaderboard5, 20, (i+105)*26, 130, (i+105)*26+24, cropPoints3[i].x+351, cropPoints3[i].y+34, cropPoints3[i].x+481, cropPoints3[i].y+58, null); |
||||||
|
} |
||||||
|
ImageIO.write(cropped1,"png",new File("testing_leaderboardnames.png")); |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
list[0].delete(); |
||||||
|
list[1].delete(); |
||||||
|
list[2].delete(); |
||||||
|
list[3].delete(); |
||||||
|
list[4].delete(); |
||||||
|
String filePath = "testing_leaderboardnames.png"; |
||||||
|
detectText(filePath); |
||||||
|
} else { |
||||||
|
if (f.listFiles().length>5) { |
||||||
|
File[] list = f.listFiles(); |
||||||
|
for (File ff : list) { |
||||||
|
ff.delete(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
try { |
||||||
|
Thread.sleep(10000); |
||||||
|
} catch (InterruptedException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void drawData(Graphics2D g, Image leaderboard, int i, int j, int k, int l, int x, int y, int m, |
||||||
|
int n, ImageObserver object) { |
||||||
|
g.drawImage(paragraph, 0, j, 18, l, 0, 0, 18, 23, object); |
||||||
|
g.drawImage(leaderboard, i, j, k, l, x, y, m, n, object); |
||||||
|
} |
||||||
|
|
||||||
|
// Detects text in the specified image.
|
||||||
|
public static void detectText(String filePath) throws IOException { |
||||||
|
List<AnnotateImageRequest> requests = new ArrayList<>(); |
||||||
|
|
||||||
|
ByteString imgBytes = ByteString.readFrom(new FileInputStream(filePath)); |
||||||
|
|
||||||
|
com.google.cloud.vision.v1.Image img = com.google.cloud.vision.v1.Image.newBuilder().setContent(imgBytes).build(); |
||||||
|
Feature feat = Feature.newBuilder().setType(Feature.Type.TEXT_DETECTION).build(); |
||||||
|
AnnotateImageRequest request = |
||||||
|
AnnotateImageRequest.newBuilder().addFeatures(feat).setImage(img).build(); |
||||||
|
requests.add(request); |
||||||
|
|
||||||
|
// Initialize client that will be used to send requests. This client only needs to be created
|
||||||
|
// once, and can be reused for multiple requests. After completing all of your requests, call
|
||||||
|
// the "close" method on the client to safely clean up any remaining background resources.
|
||||||
|
StringBuilder reader = new StringBuilder(); |
||||||
|
try (ImageAnnotatorClient client = ImageAnnotatorClient.create()) { |
||||||
|
BatchAnnotateImagesResponse response = client.batchAnnotateImages(requests); |
||||||
|
List<AnnotateImageResponse> responses = response.getResponsesList(); |
||||||
|
|
||||||
|
for (AnnotateImageResponse res : responses) { |
||||||
|
if (res.hasError()) { |
||||||
|
System.out.format("Error: %s%n", res.getError().getMessage()); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// For full list of available annotations, see http://g.co/cloud/vision/docs
|
||||||
|
for (EntityAnnotation annotation : res.getTextAnnotationsList()) { |
||||||
|
reader.append(annotation.getDescription()); |
||||||
|
break; |
||||||
|
//System.out.println(annotation.getDescription());
|
||||||
|
//System.out.format("Text: %s%n", annotation.getDescription());
|
||||||
|
//System.out.format("Position : %s%n", annotation.getBoundingPoly());
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
//System.out.println(reader);
|
||||||
|
|
||||||
|
String[] s = reader.toString().split("\n"); |
||||||
|
String[] data = new String[s.length]; |
||||||
|
int count=0; |
||||||
|
for (String ss : s) { |
||||||
|
//System.out.println(ss.replaceFirst("A","").trim());
|
||||||
|
String newString = ss.replaceFirst("A","").trim(); |
||||||
|
data[count++]=newString; |
||||||
|
} |
||||||
|
System.out.println(Arrays.toString(data)); |
||||||
|
String[] t20names = new String[20]; |
||||||
|
int arrayOffset = 0; |
||||||
|
for (int i=0;i<20;i++) { |
||||||
|
t20names[i]=data[arrayOffset++]; |
||||||
|
} |
||||||
|
String[] t20desc = new String[20]; |
||||||
|
for (int i=0;i<20;i++) { |
||||||
|
t20desc[i]=data[arrayOffset++]; |
||||||
|
} |
||||||
|
String[] t20scores = new String[20]; |
||||||
|
for (int i=0;i<20;i++) { |
||||||
|
if (data[arrayOffset+1].length()>0) { |
||||||
|
arrayOffset++; |
||||||
|
} |
||||||
|
t20scores[i]=data[arrayOffset++]; |
||||||
|
} |
||||||
|
String[] tempLowerTierNames = new String[18]; |
||||||
|
for (int i=0;i<18;i++) { |
||||||
|
tempLowerTierNames[i]=data[arrayOffset++]; |
||||||
|
} |
||||||
|
String[] tempLowerTierDesc = new String[18]; |
||||||
|
for (int i=0;i<18;i++) { |
||||||
|
tempLowerTierDesc[i]=data[arrayOffset++]; |
||||||
|
} |
||||||
|
String[] tempLowerTierScores = new String[18]; |
||||||
|
for (int i=0;i<18;i++) { |
||||||
|
if (data[arrayOffset+1].length()>0) { |
||||||
|
arrayOffset++; |
||||||
|
} |
||||||
|
tempLowerTierScores[i]=data[arrayOffset++]; |
||||||
|
} |
||||||
|
//System.out.println(Arrays.toString(t20scores));
|
||||||
|
//System.out.println(Arrays.toString(tempLowerTierScores));
|
||||||
|
//Lower tier order is: 50,100,500,1000,2000,5000,10000,20000,30000,50000
|
||||||
|
|
||||||
|
String[] lowerTierNames = new String[]{"","","","","","","","","",""}; |
||||||
|
String[] lowerTierDesc = new String[]{"","","","","","","","","",""}; |
||||||
|
String[] lowerTierScores = new String[]{"0","0","0","0","0","0","0","0","0","0"}; |
||||||
|
|
||||||
|
for (int i=0;i<9;i++) { |
||||||
|
lowerTierNames[i]=tempLowerTierNames[i]; |
||||||
|
lowerTierDesc[i]=tempLowerTierDesc[i]; |
||||||
|
lowerTierScores[i]=tempLowerTierScores[i]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
for (int i=9;i<18;i++) { |
||||||
|
//Look at the upper tier scores, if it exists we skip it.
|
||||||
|
boolean exists=false; |
||||||
|
for (int j=0;j<9;j++) { |
||||||
|
if (tempLowerTierScores[i].equalsIgnoreCase(tempLowerTierScores[j])) { |
||||||
|
exists=true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (!exists) { |
||||||
|
lowerTierNames[9]=tempLowerTierNames[i]; |
||||||
|
lowerTierDesc[9]=tempLowerTierDesc[i]; |
||||||
|
lowerTierScores[9]=tempLowerTierScores[i]; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//System.out.println(Arrays.toString(t20scores));
|
||||||
|
//System.out.println(Arrays.toString(lowerTierScores));
|
||||||
|
for (int i=0;i<20;i++) { |
||||||
|
new Thread( |
||||||
|
new SubmitThread(t20names[i],t20desc[i],t20scores[i],EVENT,i+1)) |
||||||
|
.start(); |
||||||
|
} |
||||||
|
int[] ranks = new int[] {50,100,500,1000,2000,5000,10000,20000,30000,50000}; |
||||||
|
for (int j=0;j<10;j++) { |
||||||
|
new Thread( |
||||||
|
new SubmitThread(lowerTierNames[j],lowerTierDesc[j],lowerTierScores[j],EVENT,ranks[j])) |
||||||
|
.start(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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> <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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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><[ [ ]]></code> are ignored. |
||||||
|
* @param string The source string. |
||||||
|
* @return A JSONArray containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a JSONArray |
||||||
|
*/ |
||||||
|
public static JSONArray toJSONArray(String string) throws JSONException { |
||||||
|
return (JSONArray)parse(new XMLTokener(string), true, null, false); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONArray using the JsonML transform. Each XML tag is represented as |
||||||
|
* a JSONArray in which the first element is the tag name. If the tag has |
||||||
|
* attributes, then the second element will be JSONObject containing the |
||||||
|
* name/value pairs. If the tag contains children, then strings and |
||||||
|
* JSONArrays will represent the child tags. |
||||||
|
* As opposed to toJSONArray this method does not attempt to convert |
||||||
|
* any text node or attribute value to any type |
||||||
|
* but just leaves it as a string. |
||||||
|
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||||
|
* @param string The source string. |
||||||
|
* @param keepStrings If true, then values will not be coerced into boolean |
||||||
|
* or numeric values and will instead be left as strings |
||||||
|
* @return A JSONArray containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a JSONArray |
||||||
|
*/ |
||||||
|
public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { |
||||||
|
return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONArray using the JsonML transform. Each XML tag is represented as |
||||||
|
* a JSONArray in which the first element is the tag name. If the tag has |
||||||
|
* attributes, then the second element will be JSONObject containing the |
||||||
|
* name/value pairs. If the tag contains children, then strings and |
||||||
|
* JSONArrays will represent the child content and tags. |
||||||
|
* As opposed to toJSONArray this method does not attempt to convert |
||||||
|
* any text node or attribute value to any type |
||||||
|
* but just leaves it as a string. |
||||||
|
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||||
|
* @param x An XMLTokener. |
||||||
|
* @param keepStrings If true, then values will not be coerced into boolean |
||||||
|
* or numeric values and will instead be left as strings |
||||||
|
* @return A JSONArray containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a JSONArray |
||||||
|
*/ |
||||||
|
public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { |
||||||
|
return (JSONArray)parse(x, true, null, keepStrings); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONArray using the JsonML transform. Each XML tag is represented as |
||||||
|
* a JSONArray in which the first element is the tag name. If the tag has |
||||||
|
* attributes, then the second element will be JSONObject containing the |
||||||
|
* name/value pairs. If the tag contains children, then strings and |
||||||
|
* JSONArrays will represent the child content and tags. |
||||||
|
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||||
|
* @param x An XMLTokener. |
||||||
|
* @return A JSONArray containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a JSONArray |
||||||
|
*/ |
||||||
|
public static JSONArray toJSONArray(XMLTokener x) throws JSONException { |
||||||
|
return (JSONArray)parse(x, true, null, false); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONObject using the JsonML transform. Each XML tag is represented as |
||||||
|
* a JSONObject with a "tagName" property. If the tag has attributes, then |
||||||
|
* the attributes will be in the JSONObject as properties. If the tag |
||||||
|
* contains children, the object will have a "childNodes" property which |
||||||
|
* will be an array of strings and JsonML JSONObjects. |
||||||
|
|
||||||
|
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||||
|
* @param string The XML source text. |
||||||
|
* @return A JSONObject containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a JSONObject |
||||||
|
*/ |
||||||
|
public static JSONObject toJSONObject(String string) throws JSONException { |
||||||
|
return (JSONObject)parse(new XMLTokener(string), false, null, false); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONObject using the JsonML transform. Each XML tag is represented as |
||||||
|
* a JSONObject with a "tagName" property. If the tag has attributes, then |
||||||
|
* the attributes will be in the JSONObject as properties. If the tag |
||||||
|
* contains children, the object will have a "childNodes" property which |
||||||
|
* will be an array of strings and JsonML JSONObjects. |
||||||
|
|
||||||
|
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||||
|
* @param string The XML source text. |
||||||
|
* @param keepStrings If true, then values will not be coerced into boolean |
||||||
|
* or numeric values and will instead be left as strings |
||||||
|
* @return A JSONObject containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a JSONObject |
||||||
|
*/ |
||||||
|
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { |
||||||
|
return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONObject using the JsonML transform. Each XML tag is represented as |
||||||
|
* a JSONObject with a "tagName" property. If the tag has attributes, then |
||||||
|
* the attributes will be in the JSONObject as properties. If the tag |
||||||
|
* contains children, the object will have a "childNodes" property which |
||||||
|
* will be an array of strings and JsonML JSONObjects. |
||||||
|
|
||||||
|
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||||
|
* @param x An XMLTokener of the XML source text. |
||||||
|
* @return A JSONObject containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a JSONObject |
||||||
|
*/ |
||||||
|
public static JSONObject toJSONObject(XMLTokener x) throws JSONException { |
||||||
|
return (JSONObject)parse(x, false, null, false); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONObject using the JsonML transform. Each XML tag is represented as |
||||||
|
* a JSONObject with a "tagName" property. If the tag has attributes, then |
||||||
|
* the attributes will be in the JSONObject as properties. If the tag |
||||||
|
* contains children, the object will have a "childNodes" property which |
||||||
|
* will be an array of strings and JsonML JSONObjects. |
||||||
|
|
||||||
|
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||||
|
* @param x An XMLTokener of the XML source text. |
||||||
|
* @param keepStrings If true, then values will not be coerced into boolean |
||||||
|
* or numeric values and will instead be left as strings |
||||||
|
* @return A JSONObject containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a JSONObject |
||||||
|
*/ |
||||||
|
public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { |
||||||
|
return (JSONObject)parse(x, false, null, keepStrings); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Reverse the JSONML transformation, making an XML text from a JSONArray. |
||||||
|
* @param ja A JSONArray. |
||||||
|
* @return An XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a string |
||||||
|
*/ |
||||||
|
public static String toString(JSONArray ja) throws JSONException { |
||||||
|
int i; |
||||||
|
JSONObject jo; |
||||||
|
String key; |
||||||
|
Iterator<String> keys; |
||||||
|
int length; |
||||||
|
Object object; |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
String tagName; |
||||||
|
String value; |
||||||
|
|
||||||
|
// Emit <tagName
|
||||||
|
|
||||||
|
tagName = ja.getString(0); |
||||||
|
XML.noSpace(tagName); |
||||||
|
tagName = XML.escape(tagName); |
||||||
|
sb.append('<'); |
||||||
|
sb.append(tagName); |
||||||
|
|
||||||
|
object = ja.opt(1); |
||||||
|
if (object instanceof JSONObject) { |
||||||
|
i = 2; |
||||||
|
jo = (JSONObject)object; |
||||||
|
|
||||||
|
// Emit the attributes
|
||||||
|
|
||||||
|
keys = jo.keys(); |
||||||
|
while (keys.hasNext()) { |
||||||
|
key = keys.next(); |
||||||
|
XML.noSpace(key); |
||||||
|
value = jo.optString(key); |
||||||
|
if (value != null) { |
||||||
|
sb.append(' '); |
||||||
|
sb.append(XML.escape(key)); |
||||||
|
sb.append('='); |
||||||
|
sb.append('"'); |
||||||
|
sb.append(XML.escape(value)); |
||||||
|
sb.append('"'); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
i = 1; |
||||||
|
} |
||||||
|
|
||||||
|
// Emit content in body
|
||||||
|
|
||||||
|
length = ja.length(); |
||||||
|
if (i >= length) { |
||||||
|
sb.append('/'); |
||||||
|
sb.append('>'); |
||||||
|
} else { |
||||||
|
sb.append('>'); |
||||||
|
do { |
||||||
|
object = ja.get(i); |
||||||
|
i += 1; |
||||||
|
if (object != null) { |
||||||
|
if (object instanceof String) { |
||||||
|
sb.append(XML.escape(object.toString())); |
||||||
|
} else if (object instanceof JSONObject) { |
||||||
|
sb.append(toString((JSONObject)object)); |
||||||
|
} else if (object instanceof JSONArray) { |
||||||
|
sb.append(toString((JSONArray)object)); |
||||||
|
} else { |
||||||
|
sb.append(object.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} while (i < length); |
||||||
|
sb.append('<'); |
||||||
|
sb.append('/'); |
||||||
|
sb.append(tagName); |
||||||
|
sb.append('>'); |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Reverse the JSONML transformation, making an XML text from a JSONObject. |
||||||
|
* The JSONObject must contain a "tagName" property. If it has children, |
||||||
|
* then it must have a "childNodes" property containing an array of objects. |
||||||
|
* The other properties are attributes with string values. |
||||||
|
* @param jo A JSONObject. |
||||||
|
* @return An XML string. |
||||||
|
* @throws JSONException Thrown on error converting to a string |
||||||
|
*/ |
||||||
|
public static String toString(JSONObject jo) throws JSONException { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
int i; |
||||||
|
JSONArray ja; |
||||||
|
String key; |
||||||
|
Iterator<String> keys; |
||||||
|
int length; |
||||||
|
Object object; |
||||||
|
String tagName; |
||||||
|
String value; |
||||||
|
|
||||||
|
//Emit <tagName
|
||||||
|
|
||||||
|
tagName = jo.optString("tagName"); |
||||||
|
if (tagName == null) { |
||||||
|
return XML.escape(jo.toString()); |
||||||
|
} |
||||||
|
XML.noSpace(tagName); |
||||||
|
tagName = XML.escape(tagName); |
||||||
|
sb.append('<'); |
||||||
|
sb.append(tagName); |
||||||
|
|
||||||
|
//Emit the attributes
|
||||||
|
|
||||||
|
keys = jo.keys(); |
||||||
|
while (keys.hasNext()) { |
||||||
|
key = keys.next(); |
||||||
|
if (!"tagName".equals(key) && !"childNodes".equals(key)) { |
||||||
|
XML.noSpace(key); |
||||||
|
value = jo.optString(key); |
||||||
|
if (value != null) { |
||||||
|
sb.append(' '); |
||||||
|
sb.append(XML.escape(key)); |
||||||
|
sb.append('='); |
||||||
|
sb.append('"'); |
||||||
|
sb.append(XML.escape(value)); |
||||||
|
sb.append('"'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//Emit content in body
|
||||||
|
|
||||||
|
ja = jo.optJSONArray("childNodes"); |
||||||
|
if (ja == null) { |
||||||
|
sb.append('/'); |
||||||
|
sb.append('>'); |
||||||
|
} else { |
||||||
|
sb.append('>'); |
||||||
|
length = ja.length(); |
||||||
|
for (i = 0; i < length; i += 1) { |
||||||
|
object = ja.get(i); |
||||||
|
if (object != null) { |
||||||
|
if (object instanceof String) { |
||||||
|
sb.append(XML.escape(object.toString())); |
||||||
|
} else if (object instanceof JSONObject) { |
||||||
|
sb.append(toString((JSONObject)object)); |
||||||
|
} else if (object instanceof JSONArray) { |
||||||
|
sb.append(toString((JSONArray)object)); |
||||||
|
} else { |
||||||
|
sb.append(object.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
sb.append('<'); |
||||||
|
sb.append('/'); |
||||||
|
sb.append(tagName); |
||||||
|
sb.append('>'); |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
} |
@ -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> <small>(double quote)</small> or |
||||||
|
* <code>'</code> <small>(single quote)</small>. |
||||||
|
* @return A String. |
||||||
|
* @throws JSONException Unterminated string. |
||||||
|
*/ |
||||||
|
public String nextString(char quote) throws JSONException { |
||||||
|
char c; |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
for (;;) { |
||||||
|
c = this.next(); |
||||||
|
switch (c) { |
||||||
|
case 0: |
||||||
|
case '\n': |
||||||
|
case '\r': |
||||||
|
throw this.syntaxError("Unterminated string"); |
||||||
|
case '\\': |
||||||
|
c = this.next(); |
||||||
|
switch (c) { |
||||||
|
case 'b': |
||||||
|
sb.append('\b'); |
||||||
|
break; |
||||||
|
case 't': |
||||||
|
sb.append('\t'); |
||||||
|
break; |
||||||
|
case 'n': |
||||||
|
sb.append('\n'); |
||||||
|
break; |
||||||
|
case 'f': |
||||||
|
sb.append('\f'); |
||||||
|
break; |
||||||
|
case 'r': |
||||||
|
sb.append('\r'); |
||||||
|
break; |
||||||
|
case 'u': |
||||||
|
try { |
||||||
|
sb.append((char)Integer.parseInt(this.next(4), 16)); |
||||||
|
} catch (NumberFormatException e) { |
||||||
|
throw this.syntaxError("Illegal escape.", e); |
||||||
|
} |
||||||
|
break; |
||||||
|
case '"': |
||||||
|
case '\'': |
||||||
|
case '\\': |
||||||
|
case '/': |
||||||
|
sb.append(c); |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw this.syntaxError("Illegal escape."); |
||||||
|
} |
||||||
|
break; |
||||||
|
default: |
||||||
|
if (c == quote) { |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Get the text up but not including the specified character or the |
||||||
|
* end of line, whichever comes first. |
||||||
|
* @param delimiter A delimiter character. |
||||||
|
* @return A string. |
||||||
|
* @throws JSONException Thrown if there is an error while searching |
||||||
|
* for the delimiter |
||||||
|
*/ |
||||||
|
public String nextTo(char delimiter) throws JSONException { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
for (;;) { |
||||||
|
char c = this.next(); |
||||||
|
if (c == delimiter || c == 0 || c == '\n' || c == '\r') { |
||||||
|
if (c != 0) { |
||||||
|
this.back(); |
||||||
|
} |
||||||
|
return sb.toString().trim(); |
||||||
|
} |
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Get the text up but not including one of the specified delimiter |
||||||
|
* characters or the end of line, whichever comes first. |
||||||
|
* @param delimiters A set of delimiter characters. |
||||||
|
* @return A string, trimmed. |
||||||
|
* @throws JSONException Thrown if there is an error while searching |
||||||
|
* for the delimiter |
||||||
|
*/ |
||||||
|
public String nextTo(String delimiters) throws JSONException { |
||||||
|
char c; |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
for (;;) { |
||||||
|
c = this.next(); |
||||||
|
if (delimiters.indexOf(c) >= 0 || c == 0 || |
||||||
|
c == '\n' || c == '\r') { |
||||||
|
if (c != 0) { |
||||||
|
this.back(); |
||||||
|
} |
||||||
|
return sb.toString().trim(); |
||||||
|
} |
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Get the next value. The value can be a Boolean, Double, Integer, |
||||||
|
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. |
||||||
|
* @throws JSONException If syntax error. |
||||||
|
* |
||||||
|
* @return An object. |
||||||
|
*/ |
||||||
|
public Object nextValue() throws JSONException { |
||||||
|
char c = this.nextClean(); |
||||||
|
String string; |
||||||
|
|
||||||
|
switch (c) { |
||||||
|
case '"': |
||||||
|
case '\'': |
||||||
|
return this.nextString(c); |
||||||
|
case '{': |
||||||
|
this.back(); |
||||||
|
return new JSONObject(this); |
||||||
|
case '[': |
||||||
|
this.back(); |
||||||
|
return new JSONArray(this); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Handle unquoted text. This could be the values true, false, or |
||||||
|
* null, or it can be a number. An implementation (such as this one) |
||||||
|
* is allowed to also accept non-standard forms. |
||||||
|
* |
||||||
|
* Accumulate characters until we reach the end of the text or a |
||||||
|
* formatting character. |
||||||
|
*/ |
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { |
||||||
|
sb.append(c); |
||||||
|
c = this.next(); |
||||||
|
} |
||||||
|
this.back(); |
||||||
|
|
||||||
|
string = sb.toString().trim(); |
||||||
|
if ("".equals(string)) { |
||||||
|
throw this.syntaxError("Missing value"); |
||||||
|
} |
||||||
|
return JSONObject.stringToValue(string); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Skip characters until the next character is the requested character. |
||||||
|
* If the requested character is not found, no characters are skipped. |
||||||
|
* @param to A character to skip to. |
||||||
|
* @return The requested character, or zero if the requested character |
||||||
|
* is not found. |
||||||
|
* @throws JSONException Thrown if there is an error while searching |
||||||
|
* for the to character |
||||||
|
*/ |
||||||
|
public char skipTo(char to) throws JSONException { |
||||||
|
char c; |
||||||
|
try { |
||||||
|
long startIndex = this.index; |
||||||
|
long startCharacter = this.character; |
||||||
|
long startLine = this.line; |
||||||
|
this.reader.mark(1000000); |
||||||
|
do { |
||||||
|
c = this.next(); |
||||||
|
if (c == 0) { |
||||||
|
this.reader.reset(); |
||||||
|
this.index = startIndex; |
||||||
|
this.character = startCharacter; |
||||||
|
this.line = startLine; |
||||||
|
return c; |
||||||
|
} |
||||||
|
} while (c != to); |
||||||
|
} catch (IOException exception) { |
||||||
|
throw new JSONException(exception); |
||||||
|
} |
||||||
|
this.back(); |
||||||
|
return c; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Make a JSONException to signal a syntax error. |
||||||
|
* |
||||||
|
* @param message The error message. |
||||||
|
* @return A JSONException object, suitable for throwing |
||||||
|
*/ |
||||||
|
public JSONException syntaxError(String message) { |
||||||
|
return new JSONException(message + this.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make a JSONException to signal a syntax error. |
||||||
|
* |
||||||
|
* @param message The error message. |
||||||
|
* @param causedBy The throwable that caused the error. |
||||||
|
* @return A JSONException object, suitable for throwing |
||||||
|
*/ |
||||||
|
public JSONException syntaxError(String message, Throwable causedBy) { |
||||||
|
return new JSONException(message + this.toString(), causedBy); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make a printable string of this JSONTokener. |
||||||
|
* |
||||||
|
* @return " at {index} [character {character} line {line}]" |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return " at " + this.index + " [character " + this.character + " line " + |
||||||
|
this.line + "]"; |
||||||
|
} |
||||||
|
} |
@ -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 '&'. */ |
||||||
|
public static final Character AMP = '&'; |
||||||
|
|
||||||
|
/** The Character '''. */ |
||||||
|
public static final Character APOS = '\''; |
||||||
|
|
||||||
|
/** The Character '!'. */ |
||||||
|
public static final Character BANG = '!'; |
||||||
|
|
||||||
|
/** The Character '='. */ |
||||||
|
public static final Character EQ = '='; |
||||||
|
|
||||||
|
/** The Character '>'. */ |
||||||
|
public static final Character GT = '>'; |
||||||
|
|
||||||
|
/** The Character '<'. */ |
||||||
|
public static final Character LT = '<'; |
||||||
|
|
||||||
|
/** The Character '?'. */ |
||||||
|
public static final Character QUEST = '?'; |
||||||
|
|
||||||
|
/** The Character '"'. */ |
||||||
|
public static final Character QUOT = '"'; |
||||||
|
|
||||||
|
/** The Character '/'. */ |
||||||
|
public static final Character SLASH = '/'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an iterator for navigating Code Points in a string instead of |
||||||
|
* characters. Once Java7 support is dropped, this can be replaced with |
||||||
|
* <code> |
||||||
|
* string.codePoints() |
||||||
|
* </code> |
||||||
|
* which is available in Java8 and above. |
||||||
|
* |
||||||
|
* @see <a href= |
||||||
|
* "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a>
|
||||||
|
*/ |
||||||
|
private static Iterable<Integer> codePointIterator(final String string) { |
||||||
|
return new Iterable<Integer>() { |
||||||
|
@Override |
||||||
|
public Iterator<Integer> iterator() { |
||||||
|
return new Iterator<Integer>() { |
||||||
|
private int nextIndex = 0; |
||||||
|
private int length = string.length(); |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasNext() { |
||||||
|
return this.nextIndex < this.length; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Integer next() { |
||||||
|
int result = string.codePointAt(this.nextIndex); |
||||||
|
this.nextIndex += Character.charCount(result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void remove() { |
||||||
|
throw new UnsupportedOperationException(); |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Replace special characters with XML escapes: |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* & <small>(ampersand)</small> is replaced by &amp; |
||||||
|
* < <small>(less than)</small> is replaced by &lt; |
||||||
|
* > <small>(greater than)</small> is replaced by &gt; |
||||||
|
* " <small>(double quote)</small> is replaced by &quot; |
||||||
|
* ' <small>(single quote / apostrophe)</small> is replaced by &apos; |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* @param string |
||||||
|
* The string to be escaped. |
||||||
|
* @return The escaped string. |
||||||
|
*/ |
||||||
|
public static String escape(String string) { |
||||||
|
StringBuilder sb = new StringBuilder(string.length()); |
||||||
|
for (final int cp : codePointIterator(string)) { |
||||||
|
switch (cp) { |
||||||
|
case '&': |
||||||
|
sb.append("&"); |
||||||
|
break; |
||||||
|
case '<': |
||||||
|
sb.append("<"); |
||||||
|
break; |
||||||
|
case '>': |
||||||
|
sb.append(">"); |
||||||
|
break; |
||||||
|
case '"': |
||||||
|
sb.append("""); |
||||||
|
break; |
||||||
|
case '\'': |
||||||
|
sb.append("'"); |
||||||
|
break; |
||||||
|
default: |
||||||
|
if (mustEscape(cp)) { |
||||||
|
sb.append("&#x"); |
||||||
|
sb.append(Integer.toHexString(cp)); |
||||||
|
sb.append(";"); |
||||||
|
} else { |
||||||
|
sb.appendCodePoint(cp); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param cp code point to test |
||||||
|
* @return true if the code point is not valid for an XML |
||||||
|
*/ |
||||||
|
private static boolean mustEscape(int cp) { |
||||||
|
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets
|
||||||
|
* |
||||||
|
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] |
||||||
|
* |
||||||
|
* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. |
||||||
|
*/ |
||||||
|
// isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F)
|
||||||
|
// all ISO control characters are out of range except tabs and new lines
|
||||||
|
return (Character.isISOControl(cp) |
||||||
|
&& cp != 0x9 |
||||||
|
&& cp != 0xA |
||||||
|
&& cp != 0xD |
||||||
|
) || !( |
||||||
|
// valid the range of acceptable characters that aren't control
|
||||||
|
(cp >= 0x20 && cp <= 0xD7FF) |
||||||
|
|| (cp >= 0xE000 && cp <= 0xFFFD) |
||||||
|
|| (cp >= 0x10000 && cp <= 0x10FFFF) |
||||||
|
) |
||||||
|
; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes XML escapes from the string. |
||||||
|
* |
||||||
|
* @param string |
||||||
|
* string to remove escapes from |
||||||
|
* @return string with converted entities |
||||||
|
*/ |
||||||
|
public static String unescape(String string) { |
||||||
|
StringBuilder sb = new StringBuilder(string.length()); |
||||||
|
for (int i = 0, length = string.length(); i < length; i++) { |
||||||
|
char c = string.charAt(i); |
||||||
|
if (c == '&') { |
||||||
|
final int semic = string.indexOf(';', i); |
||||||
|
if (semic > i) { |
||||||
|
final String entity = string.substring(i + 1, semic); |
||||||
|
if (entity.charAt(0) == '#') { |
||||||
|
int cp; |
||||||
|
if (entity.charAt(1) == 'x') { |
||||||
|
// hex encoded unicode
|
||||||
|
cp = Integer.parseInt(entity.substring(2), 16); |
||||||
|
} else { |
||||||
|
// decimal encoded unicode
|
||||||
|
cp = Integer.parseInt(entity.substring(1)); |
||||||
|
} |
||||||
|
sb.appendCodePoint(cp); |
||||||
|
} else { |
||||||
|
if ("quot".equalsIgnoreCase(entity)) { |
||||||
|
sb.append('"'); |
||||||
|
} else if ("amp".equalsIgnoreCase(entity)) { |
||||||
|
sb.append('&'); |
||||||
|
} else if ("apos".equalsIgnoreCase(entity)) { |
||||||
|
sb.append('\''); |
||||||
|
} else if ("lt".equalsIgnoreCase(entity)) { |
||||||
|
sb.append('<'); |
||||||
|
} else if ("gt".equalsIgnoreCase(entity)) { |
||||||
|
sb.append('>'); |
||||||
|
} else { |
||||||
|
sb.append('&').append(entity).append(';'); |
||||||
|
} |
||||||
|
} |
||||||
|
// skip past the entity we just parsed.
|
||||||
|
i += entity.length() + 1; |
||||||
|
} else { |
||||||
|
// this shouldn't happen in most cases since the parser
|
||||||
|
// errors on unclosed enties.
|
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// not part of an entity
|
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Throw an exception if the string contains whitespace. Whitespace is not |
||||||
|
* allowed in tagNames and attributes. |
||||||
|
* |
||||||
|
* @param string |
||||||
|
* A string. |
||||||
|
* @throws JSONException Thrown if the string contains whitespace or is empty. |
||||||
|
*/ |
||||||
|
public static void noSpace(String string) throws JSONException { |
||||||
|
int i, length = string.length(); |
||||||
|
if (length == 0) { |
||||||
|
throw new JSONException("Empty string."); |
||||||
|
} |
||||||
|
for (i = 0; i < length; i += 1) { |
||||||
|
if (Character.isWhitespace(string.charAt(i))) { |
||||||
|
throw new JSONException("'" + string |
||||||
|
+ "' contains a space character."); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Scan the content following the named tag, attaching it to the context. |
||||||
|
* |
||||||
|
* @param x |
||||||
|
* The XMLTokener containing the source string. |
||||||
|
* @param context |
||||||
|
* The JSONObject that will include the new material. |
||||||
|
* @param name |
||||||
|
* The tag name. |
||||||
|
* @return true if the close tag is processed. |
||||||
|
* @throws JSONException |
||||||
|
*/ |
||||||
|
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) |
||||||
|
throws JSONException { |
||||||
|
char c; |
||||||
|
int i; |
||||||
|
JSONObject jsonobject = null; |
||||||
|
String string; |
||||||
|
String tagName; |
||||||
|
Object token; |
||||||
|
|
||||||
|
// Test for and skip past these forms:
|
||||||
|
// <!-- ... -->
|
||||||
|
// <! ... >
|
||||||
|
// <![ ... ]]>
|
||||||
|
// <? ... ?>
|
||||||
|
// Report errors for these forms:
|
||||||
|
// <>
|
||||||
|
// <=
|
||||||
|
// <<
|
||||||
|
|
||||||
|
token = x.nextToken(); |
||||||
|
|
||||||
|
// <!
|
||||||
|
|
||||||
|
if (token == BANG) { |
||||||
|
c = x.next(); |
||||||
|
if (c == '-') { |
||||||
|
if (x.next() == '-') { |
||||||
|
x.skipPast("-->"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
x.back(); |
||||||
|
} else if (c == '[') { |
||||||
|
token = x.nextToken(); |
||||||
|
if ("CDATA".equals(token)) { |
||||||
|
if (x.next() == '[') { |
||||||
|
string = x.nextCDATA(); |
||||||
|
if (string.length() > 0) { |
||||||
|
context.accumulate("content", string); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
throw x.syntaxError("Expected 'CDATA['"); |
||||||
|
} |
||||||
|
i = 1; |
||||||
|
do { |
||||||
|
token = x.nextMeta(); |
||||||
|
if (token == null) { |
||||||
|
throw x.syntaxError("Missing '>' after '<!'."); |
||||||
|
} else if (token == LT) { |
||||||
|
i += 1; |
||||||
|
} else if (token == GT) { |
||||||
|
i -= 1; |
||||||
|
} |
||||||
|
} while (i > 0); |
||||||
|
return false; |
||||||
|
} else if (token == QUEST) { |
||||||
|
|
||||||
|
// <?
|
||||||
|
x.skipPast("?>"); |
||||||
|
return false; |
||||||
|
} else if (token == SLASH) { |
||||||
|
|
||||||
|
// Close tag </
|
||||||
|
|
||||||
|
token = x.nextToken(); |
||||||
|
if (name == null) { |
||||||
|
throw x.syntaxError("Mismatched close tag " + token); |
||||||
|
} |
||||||
|
if (!token.equals(name)) { |
||||||
|
throw x.syntaxError("Mismatched " + name + " and " + token); |
||||||
|
} |
||||||
|
if (x.nextToken() != GT) { |
||||||
|
throw x.syntaxError("Misshaped close tag"); |
||||||
|
} |
||||||
|
return true; |
||||||
|
|
||||||
|
} else if (token instanceof Character) { |
||||||
|
throw x.syntaxError("Misshaped tag"); |
||||||
|
|
||||||
|
// Open tag <
|
||||||
|
|
||||||
|
} else { |
||||||
|
tagName = (String) token; |
||||||
|
token = null; |
||||||
|
jsonobject = new JSONObject(); |
||||||
|
for (;;) { |
||||||
|
if (token == null) { |
||||||
|
token = x.nextToken(); |
||||||
|
} |
||||||
|
// attribute = value
|
||||||
|
if (token instanceof String) { |
||||||
|
string = (String) token; |
||||||
|
token = x.nextToken(); |
||||||
|
if (token == EQ) { |
||||||
|
token = x.nextToken(); |
||||||
|
if (!(token instanceof String)) { |
||||||
|
throw x.syntaxError("Missing value"); |
||||||
|
} |
||||||
|
jsonobject.accumulate(string, |
||||||
|
keepStrings ? unescape((String)token) : stringToValue((String) token)); |
||||||
|
token = null; |
||||||
|
} else { |
||||||
|
jsonobject.accumulate(string, ""); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} else if (token == SLASH) { |
||||||
|
// Empty tag <.../>
|
||||||
|
if (x.nextToken() != GT) { |
||||||
|
throw x.syntaxError("Misshaped tag"); |
||||||
|
} |
||||||
|
if (jsonobject.length() > 0) { |
||||||
|
context.accumulate(tagName, jsonobject); |
||||||
|
} else { |
||||||
|
context.accumulate(tagName, ""); |
||||||
|
} |
||||||
|
return false; |
||||||
|
|
||||||
|
} else if (token == GT) { |
||||||
|
// Content, between <...> and </...>
|
||||||
|
for (;;) { |
||||||
|
token = x.nextContent(); |
||||||
|
if (token == null) { |
||||||
|
if (tagName != null) { |
||||||
|
throw x.syntaxError("Unclosed tag " + tagName); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} else if (token instanceof String) { |
||||||
|
string = (String) token; |
||||||
|
if (string.length() > 0) { |
||||||
|
jsonobject.accumulate("content", |
||||||
|
keepStrings ? unescape(string) : stringToValue(string)); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (token == LT) { |
||||||
|
// Nested element
|
||||||
|
if (parse(x, jsonobject, tagName,keepStrings)) { |
||||||
|
if (jsonobject.length() == 0) { |
||||||
|
context.accumulate(tagName, ""); |
||||||
|
} else if (jsonobject.length() == 1 |
||||||
|
&& jsonobject.opt("content") != null) { |
||||||
|
context.accumulate(tagName, |
||||||
|
jsonobject.opt("content")); |
||||||
|
} else { |
||||||
|
context.accumulate(tagName, jsonobject); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
throw x.syntaxError("Misshaped tag"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is the same as {@link JSONObject.stringToValue(String)} |
||||||
|
* except that this also tries to unescape String values. |
||||||
|
* |
||||||
|
* @param string String to convert |
||||||
|
* @return JSON value of this string or the string |
||||||
|
*/ |
||||||
|
public static Object stringToValue(String string) { |
||||||
|
Object ret = JSONObject.stringToValue(string); |
||||||
|
if(ret instanceof String){ |
||||||
|
return unescape((String)ret); |
||||||
|
} |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONObject. Some information may be lost in this transformation because |
||||||
|
* JSON is a data format and XML is a document format. XML uses elements, |
||||||
|
* attributes, and content text, while JSON uses unordered collections of |
||||||
|
* name/value pairs and arrays of values. JSON does not does not like to |
||||||
|
* distinguish between elements and attributes. Sequences of similar |
||||||
|
* elements are represented as JSONArrays. Content text may be placed in a |
||||||
|
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code> |
||||||
|
* are ignored. |
||||||
|
* |
||||||
|
* @param string |
||||||
|
* The source string. |
||||||
|
* @return A JSONObject containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown if there is an errors while parsing the string |
||||||
|
*/ |
||||||
|
public static JSONObject toJSONObject(String string) throws JSONException { |
||||||
|
return toJSONObject(string, false); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a well-formed (but not necessarily valid) XML string into a |
||||||
|
* JSONObject. Some information may be lost in this transformation because |
||||||
|
* JSON is a data format and XML is a document format. XML uses elements, |
||||||
|
* attributes, and content text, while JSON uses unordered collections of |
||||||
|
* name/value pairs and arrays of values. JSON does not does not like to |
||||||
|
* distinguish between elements and attributes. Sequences of similar |
||||||
|
* elements are represented as JSONArrays. Content text may be placed in a |
||||||
|
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code> |
||||||
|
* are ignored. |
||||||
|
* |
||||||
|
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to |
||||||
|
* numbers but will instead be the exact value as seen in the XML document. |
||||||
|
* |
||||||
|
* @param string |
||||||
|
* The source string. |
||||||
|
* @param keepStrings If true, then values will not be coerced into boolean |
||||||
|
* or numeric values and will instead be left as strings |
||||||
|
* @return A JSONObject containing the structured data from the XML string. |
||||||
|
* @throws JSONException Thrown if there is an errors while parsing the string |
||||||
|
*/ |
||||||
|
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { |
||||||
|
JSONObject jo = new JSONObject(); |
||||||
|
XMLTokener x = new XMLTokener(string); |
||||||
|
while (x.more() && x.skipPast("<")) { |
||||||
|
parse(x, jo, null, keepStrings); |
||||||
|
} |
||||||
|
return jo; |
||||||
|
} |
||||||
|
/** |
||||||
|
* Convert a JSONObject into a well-formed, element-normal XML string. |
||||||
|
* |
||||||
|
* @param object |
||||||
|
* A JSONObject. |
||||||
|
* @return A string. |
||||||
|
* @throws JSONException Thrown if there is an error parsing the string |
||||||
|
*/ |
||||||
|
public static String toString(Object object) throws JSONException { |
||||||
|
return toString(object, null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Convert a JSONObject into a well-formed, element-normal XML string. |
||||||
|
* |
||||||
|
* @param object |
||||||
|
* A JSONObject. |
||||||
|
* @param tagName |
||||||
|
* The optional name of the enclosing tag. |
||||||
|
* @return A string. |
||||||
|
* @throws JSONException Thrown if there is an error parsing the string |
||||||
|
*/ |
||||||
|
public static String toString(Object object, String tagName) |
||||||
|
throws JSONException { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
JSONArray ja; |
||||||
|
JSONObject jo; |
||||||
|
String key; |
||||||
|
Iterator<String> keys; |
||||||
|
String string; |
||||||
|
Object value; |
||||||
|
|
||||||
|
if (object instanceof JSONObject) { |
||||||
|
|
||||||
|
// Emit <tagName>
|
||||||
|
if (tagName != null) { |
||||||
|
sb.append('<'); |
||||||
|
sb.append(tagName); |
||||||
|
sb.append('>'); |
||||||
|
} |
||||||
|
|
||||||
|
// Loop thru the keys.
|
||||||
|
jo = (JSONObject) object; |
||||||
|
keys = jo.keys(); |
||||||
|
while (keys.hasNext()) { |
||||||
|
key = keys.next(); |
||||||
|
value = jo.opt(key); |
||||||
|
if (value == null) { |
||||||
|
value = ""; |
||||||
|
} else if (value.getClass().isArray()) { |
||||||
|
value = new JSONArray(value); |
||||||
|
} |
||||||
|
string = value instanceof String ? (String) value : null; |
||||||
|
|
||||||
|
// Emit content in body
|
||||||
|
if ("content".equals(key)) { |
||||||
|
if (value instanceof JSONArray) { |
||||||
|
ja = (JSONArray) value; |
||||||
|
int i = 0; |
||||||
|
for (Object val : ja) { |
||||||
|
if (i > 0) { |
||||||
|
sb.append('\n'); |
||||||
|
} |
||||||
|
sb.append(escape(val.toString())); |
||||||
|
i++; |
||||||
|
} |
||||||
|
} else { |
||||||
|
sb.append(escape(value.toString())); |
||||||
|
} |
||||||
|
|
||||||
|
// Emit an array of similar keys
|
||||||
|
|
||||||
|
} else if (value instanceof JSONArray) { |
||||||
|
ja = (JSONArray) value; |
||||||
|
for (Object val : ja) { |
||||||
|
if (val instanceof JSONArray) { |
||||||
|
sb.append('<'); |
||||||
|
sb.append(key); |
||||||
|
sb.append('>'); |
||||||
|
sb.append(toString(val)); |
||||||
|
sb.append("</"); |
||||||
|
sb.append(key); |
||||||
|
sb.append('>'); |
||||||
|
} else { |
||||||
|
sb.append(toString(val, key)); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if ("".equals(value)) { |
||||||
|
sb.append('<'); |
||||||
|
sb.append(key); |
||||||
|
sb.append("/>"); |
||||||
|
|
||||||
|
// Emit a new tag <k>
|
||||||
|
|
||||||
|
} else { |
||||||
|
sb.append(toString(value, key)); |
||||||
|
} |
||||||
|
} |
||||||
|
if (tagName != null) { |
||||||
|
|
||||||
|
// Emit the </tagname> close tag
|
||||||
|
sb.append("</"); |
||||||
|
sb.append(tagName); |
||||||
|
sb.append('>'); |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (object != null) { |
||||||
|
if (object.getClass().isArray()) { |
||||||
|
object = new JSONArray(object); |
||||||
|
} |
||||||
|
|
||||||
|
if (object instanceof JSONArray) { |
||||||
|
ja = (JSONArray) object; |
||||||
|
for (Object val : ja) { |
||||||
|
// XML does not have good support for arrays. If an array
|
||||||
|
// appears in a place where XML is lacking, synthesize an
|
||||||
|
// <array> element.
|
||||||
|
sb.append(toString(val, tagName == null ? "array" : tagName)); |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
string = (object == null) ? "null" : escape(object.toString()); |
||||||
|
return (tagName == null) ? "\"" + string + "\"" |
||||||
|
: (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName |
||||||
|
+ ">" + string + "</" + tagName + ">"; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,365 @@ |
|||||||
|
package org.json; |
||||||
|
|
||||||
|
/* |
||||||
|
Copyright (c) 2002 JSON.org |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||||
|
of this software and associated documentation files (the "Software"), to deal |
||||||
|
in the Software without restriction, including without limitation the rights |
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||||
|
copies of the Software, and to permit persons to whom the Software is |
||||||
|
furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all |
||||||
|
copies or substantial portions of the Software. |
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||||
|
SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* The XMLTokener extends the JSONTokener to provide additional methods |
||||||
|
* for the parsing of XML texts. |
||||||
|
* @author JSON.org |
||||||
|
* @version 2015-12-09 |
||||||
|
*/ |
||||||
|
public class XMLTokener extends JSONTokener { |
||||||
|
|
||||||
|
|
||||||
|
/** The table of entity values. It initially contains Character values for |
||||||
|
* amp, apos, gt, lt, quot. |
||||||
|
*/ |
||||||
|
public static final java.util.HashMap<String, Character> entity; |
||||||
|
|
||||||
|
static { |
||||||
|
entity = new java.util.HashMap<String, Character>(8); |
||||||
|
entity.put("amp", XML.AMP); |
||||||
|
entity.put("apos", XML.APOS); |
||||||
|
entity.put("gt", XML.GT); |
||||||
|
entity.put("lt", XML.LT); |
||||||
|
entity.put("quot", XML.QUOT); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Construct an XMLTokener from a string. |
||||||
|
* @param s A source string. |
||||||
|
*/ |
||||||
|
public XMLTokener(String s) { |
||||||
|
super(s); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the text in the CDATA block. |
||||||
|
* @return The string up to the <code>]]></code>. |
||||||
|
* @throws JSONException If the <code>]]></code> is not found. |
||||||
|
*/ |
||||||
|
public String nextCDATA() throws JSONException { |
||||||
|
char c; |
||||||
|
int i; |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
for (;;) { |
||||||
|
c = next(); |
||||||
|
if (end()) { |
||||||
|
throw syntaxError("Unclosed CDATA"); |
||||||
|
} |
||||||
|
sb.append(c); |
||||||
|
i = sb.length() - 3; |
||||||
|
if (i >= 0 && sb.charAt(i) == ']' && |
||||||
|
sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { |
||||||
|
sb.setLength(i); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Get the next XML outer token, trimming whitespace. There are two kinds |
||||||
|
* of tokens: the '<' character which begins a markup tag, and the content |
||||||
|
* text between markup tags. |
||||||
|
* |
||||||
|
* @return A string, or a '<' Character, or null if there is no more |
||||||
|
* source text. |
||||||
|
* @throws JSONException |
||||||
|
*/ |
||||||
|
public Object nextContent() throws JSONException { |
||||||
|
char c; |
||||||
|
StringBuilder sb; |
||||||
|
do { |
||||||
|
c = next(); |
||||||
|
} while (Character.isWhitespace(c)); |
||||||
|
if (c == 0) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (c == '<') { |
||||||
|
return XML.LT; |
||||||
|
} |
||||||
|
sb = new StringBuilder(); |
||||||
|
for (;;) { |
||||||
|
if (c == '<' || c == 0) { |
||||||
|
back(); |
||||||
|
return sb.toString().trim(); |
||||||
|
} |
||||||
|
if (c == '&') { |
||||||
|
sb.append(nextEntity(c)); |
||||||
|
} else { |
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
c = next(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Return the next entity. These entities are translated to Characters: |
||||||
|
* <code>& ' > < "</code>. |
||||||
|
* @param ampersand An ampersand character. |
||||||
|
* @return A Character or an entity String if the entity is not recognized. |
||||||
|
* @throws JSONException If missing ';' in XML entity. |
||||||
|
*/ |
||||||
|
public Object nextEntity(char ampersand) throws JSONException { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
for (;;) { |
||||||
|
char c = next(); |
||||||
|
if (Character.isLetterOrDigit(c) || c == '#') { |
||||||
|
sb.append(Character.toLowerCase(c)); |
||||||
|
} else if (c == ';') { |
||||||
|
break; |
||||||
|
} else { |
||||||
|
throw syntaxError("Missing ';' in XML entity: &" + sb); |
||||||
|
} |
||||||
|
} |
||||||
|
String string = sb.toString(); |
||||||
|
Object object = entity.get(string); |
||||||
|
return object != null ? object : ampersand + string + ";"; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the next XML meta token. This is used for skipping over <!...> |
||||||
|
* and <?...?> structures. |
||||||
|
* @return Syntax characters (<code>< > / = ! ?</code>) are returned as |
||||||
|
* Character, and strings and names are returned as Boolean. We don't care |
||||||
|
* what the values actually are. |
||||||
|
* @throws JSONException If a string is not properly closed or if the XML |
||||||
|
* is badly structured. |
||||||
|
*/ |
||||||
|
public Object nextMeta() throws JSONException { |
||||||
|
char c; |
||||||
|
char q; |
||||||
|
do { |
||||||
|
c = next(); |
||||||
|
} while (Character.isWhitespace(c)); |
||||||
|
switch (c) { |
||||||
|
case 0: |
||||||
|
throw syntaxError("Misshaped meta tag"); |
||||||
|
case '<': |
||||||
|
return XML.LT; |
||||||
|
case '>': |
||||||
|
return XML.GT; |
||||||
|
case '/': |
||||||
|
return XML.SLASH; |
||||||
|
case '=': |
||||||
|
return XML.EQ; |
||||||
|
case '!': |
||||||
|
return XML.BANG; |
||||||
|
case '?': |
||||||
|
return XML.QUEST; |
||||||
|
case '"': |
||||||
|
case '\'': |
||||||
|
q = c; |
||||||
|
for (;;) { |
||||||
|
c = next(); |
||||||
|
if (c == 0) { |
||||||
|
throw syntaxError("Unterminated string"); |
||||||
|
} |
||||||
|
if (c == q) { |
||||||
|
return Boolean.TRUE; |
||||||
|
} |
||||||
|
} |
||||||
|
default: |
||||||
|
for (;;) { |
||||||
|
c = next(); |
||||||
|
if (Character.isWhitespace(c)) { |
||||||
|
return Boolean.TRUE; |
||||||
|
} |
||||||
|
switch (c) { |
||||||
|
case 0: |
||||||
|
case '<': |
||||||
|
case '>': |
||||||
|
case '/': |
||||||
|
case '=': |
||||||
|
case '!': |
||||||
|
case '?': |
||||||
|
case '"': |
||||||
|
case '\'': |
||||||
|
back(); |
||||||
|
return Boolean.TRUE; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Get the next XML Token. These tokens are found inside of angle |
||||||
|
* brackets. It may be one of these characters: <code>/ > = ! ?</code> or it |
||||||
|
* may be a string wrapped in single quotes or double quotes, or it may be a |
||||||
|
* name. |
||||||
|
* @return a String or a Character. |
||||||
|
* @throws JSONException If the XML is not well formed. |
||||||
|
*/ |
||||||
|
public Object nextToken() throws JSONException { |
||||||
|
char c; |
||||||
|
char q; |
||||||
|
StringBuilder sb; |
||||||
|
do { |
||||||
|
c = next(); |
||||||
|
} while (Character.isWhitespace(c)); |
||||||
|
switch (c) { |
||||||
|
case 0: |
||||||
|
throw syntaxError("Misshaped element"); |
||||||
|
case '<': |
||||||
|
throw syntaxError("Misplaced '<'"); |
||||||
|
case '>': |
||||||
|
return XML.GT; |
||||||
|
case '/': |
||||||
|
return XML.SLASH; |
||||||
|
case '=': |
||||||
|
return XML.EQ; |
||||||
|
case '!': |
||||||
|
return XML.BANG; |
||||||
|
case '?': |
||||||
|
return XML.QUEST; |
||||||
|
|
||||||
|
// Quoted string
|
||||||
|
|
||||||
|
case '"': |
||||||
|
case '\'': |
||||||
|
q = c; |
||||||
|
sb = new StringBuilder(); |
||||||
|
for (;;) { |
||||||
|
c = next(); |
||||||
|
if (c == 0) { |
||||||
|
throw syntaxError("Unterminated string"); |
||||||
|
} |
||||||
|
if (c == q) { |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
if (c == '&') { |
||||||
|
sb.append(nextEntity(c)); |
||||||
|
} else { |
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
} |
||||||
|
default: |
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
sb = new StringBuilder(); |
||||||
|
for (;;) { |
||||||
|
sb.append(c); |
||||||
|
c = next(); |
||||||
|
if (Character.isWhitespace(c)) { |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
switch (c) { |
||||||
|
case 0: |
||||||
|
return sb.toString(); |
||||||
|
case '>': |
||||||
|
case '/': |
||||||
|
case '=': |
||||||
|
case '!': |
||||||
|
case '?': |
||||||
|
case '[': |
||||||
|
case ']': |
||||||
|
back(); |
||||||
|
return sb.toString(); |
||||||
|
case '<': |
||||||
|
case '"': |
||||||
|
case '\'': |
||||||
|
throw syntaxError("Bad character in a name"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Skip characters until past the requested string. |
||||||
|
* If it is not found, we are left at the end of the source with a result of false. |
||||||
|
* @param to A string to skip past. |
||||||
|
* @throws JSONException |
||||||
|
*/ |
||||||
|
public boolean skipPast(String to) throws JSONException { |
||||||
|
boolean b; |
||||||
|
char c; |
||||||
|
int i; |
||||||
|
int j; |
||||||
|
int offset = 0; |
||||||
|
int length = to.length(); |
||||||
|
char[] circle = new char[length]; |
||||||
|
|
||||||
|
/* |
||||||
|
* First fill the circle buffer with as many characters as are in the |
||||||
|
* to string. If we reach an early end, bail. |
||||||
|
*/ |
||||||
|
|
||||||
|
for (i = 0; i < length; i += 1) { |
||||||
|
c = next(); |
||||||
|
if (c == 0) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
circle[i] = c; |
||||||
|
} |
||||||
|
|
||||||
|
/* We will loop, possibly for all of the remaining characters. */ |
||||||
|
|
||||||
|
for (;;) { |
||||||
|
j = offset; |
||||||
|
b = true; |
||||||
|
|
||||||
|
/* Compare the circle buffer with the to string. */ |
||||||
|
|
||||||
|
for (i = 0; i < length; i += 1) { |
||||||
|
if (circle[j] != to.charAt(i)) { |
||||||
|
b = false; |
||||||
|
break; |
||||||
|
} |
||||||
|
j += 1; |
||||||
|
if (j >= length) { |
||||||
|
j -= length; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* If we exit the loop with b intact, then victory is ours. */ |
||||||
|
|
||||||
|
if (b) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/* Get the next character. If there isn't one, then defeat is ours. */ |
||||||
|
|
||||||
|
c = next(); |
||||||
|
if (c == 0) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
/* |
||||||
|
* Shove the character in the circle buffer and advance the |
||||||
|
* circle offset. The offset is mod n. |
||||||
|
*/ |
||||||
|
circle[offset] = c; |
||||||
|
offset += 1; |
||||||
|
if (offset >= length) { |
||||||
|
offset -= length; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 @@ |
|||||||
|
tessedit_create_alto 1 |
@ -0,0 +1 @@ |
|||||||
|
tessedit_zero_rejection T |
@ -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 @@ |
|||||||
|
tessedit_create_lstmbox 1 |
@ -0,0 +1 @@ |
|||||||
|
tessedit_create_pdf 1 |
@ -0,0 +1 @@ |
|||||||
|
debug_file /dev/null |
@ -0,0 +1 @@ |
|||||||
|
tessedit_create_tsv 1 |
@ -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 @@ |
|||||||
|
tessedit_create_wordstrbox 1 |
@ -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> |
After Width: | Height: | Size: 100 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 200 KiB |
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 |