Merge pull request #96 from rr83019/image-dpi

Set Image DPI for captcha providers
This commit is contained in:
hrj 2021-09-02 16:37:00 +05:30 committed by GitHub
commit 8f606da92f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 92 additions and 14 deletions

View File

@ -1,6 +1,5 @@
package lc.captchas; package lc.captchas;
import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -10,6 +9,7 @@ import java.util.Map;
import java.util.List; import java.util.List;
import lc.captchas.interfaces.Challenge; import lc.captchas.interfaces.Challenge;
import lc.captchas.interfaces.ChallengeProvider; import lc.captchas.interfaces.ChallengeProvider;
import lc.misc.PngImageWriter;
import lc.misc.HelperFunctions; import lc.misc.HelperFunctions;
public class FontFunCaptcha implements ChallengeProvider { public class FontFunCaptcha implements ChallengeProvider {
@ -74,7 +74,7 @@ public class FontFunCaptcha implements ChallengeProvider {
graphics2D.dispose(); graphics2D.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
try { try {
ImageIO.write(img, "png", baos); PngImageWriter.write(baos, img);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -1,6 +1,5 @@
package lc.captchas; package lc.captchas;
import javax.imageio.ImageIO;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.Color; import java.awt.Color;
@ -14,6 +13,7 @@ import java.util.Map;
import java.util.List; import java.util.List;
import lc.misc.HelperFunctions; import lc.misc.HelperFunctions;
import lc.misc.PngImageWriter;
import lc.captchas.interfaces.Challenge; import lc.captchas.interfaces.Challenge;
import lc.captchas.interfaces.ChallengeProvider; import lc.captchas.interfaces.ChallengeProvider;
@ -67,7 +67,7 @@ public class ShadowTextCaptcha implements ChallengeProvider {
g2d.dispose(); g2d.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
try { try {
ImageIO.write(img2, "png", baos); PngImageWriter.write(baos, img2);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -7,9 +7,9 @@ public class HelperFunctions {
private static Random random = new Random(); private static Random random = new Random();
synchronized public static void setSeed(long seed){ public static synchronized void setSeed(long seed) {
random.setSeed(seed); random.setSeed(seed);
} }
public static void setRenderingHints(Graphics2D g2d) { public static void setRenderingHints(Graphics2D g2d) {
g2d.setRenderingHint( g2d.setRenderingHint(
@ -38,12 +38,11 @@ public class HelperFunctions {
return stringBuilder.toString(); return stringBuilder.toString();
} }
synchronized public static int randomNumber(int min, int max) { public static synchronized int randomNumber(int min, int max) {
return random.nextInt((max - min) + 1) + min; return random.nextInt((max - min) + 1) + min;
} }
synchronized public static int randomNumber(int bound) { public static synchronized int randomNumber(int bound) {
return random.nextInt(bound); return random.nextInt(bound);
} }
} }

View File

@ -0,0 +1,68 @@
package lc.misc;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
public class PngImageWriter {
static final int DPI = 245;
static final double INCH_2_CM = 2.54;
public static void write(ByteArrayOutputStream boas, BufferedImage gridImage) throws IOException {
final String formatName = "png";
for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName(formatName);
iw.hasNext(); ) {
ImageWriter writer = iw.next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
continue;
}
setDPIMeta(metadata);
final ImageOutputStream stream = ImageIO.createImageOutputStream(boas);
try {
writer.setOutput(stream);
writer.write(metadata, new IIOImage(gridImage, null, metadata), writeParam);
} finally {
stream.close();
}
break;
}
}
private static void setDPIMeta(IIOMetadata metadata) throws IIOInvalidTreeException {
// for PNG, it's dots per millimeter
double dotsPerMilli = 1.0 * DPI / 10 / INCH_2_CM;
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
root.appendChild(dim);
metadata.mergeTree("javax_imageio_1.0", root);
}
}

View File

@ -1,6 +1,5 @@
package lc.captchas package lc.captchas
import javax.imageio.ImageIO
import java.awt.Color import java.awt.Color
import java.awt.Font import java.awt.Font
import java.awt.font.TextLayout import java.awt.font.TextLayout
@ -12,6 +11,7 @@ import java.util.List
import lc.misc.HelperFunctions import lc.misc.HelperFunctions
import lc.captchas.interfaces.Challenge import lc.captchas.interfaces.Challenge
import lc.captchas.interfaces.ChallengeProvider import lc.captchas.interfaces.ChallengeProvider
import lc.misc.PngImageWriter
/** This captcha is only for debugging purposes. It creates very simple captchas that are deliberately easy to solve with OCR engines */ /** This captcha is only for debugging purposes. It creates very simple captchas that are deliberately easy to solve with OCR engines */
class DebugCaptcha extends ChallengeProvider { class DebugCaptcha extends ChallengeProvider {
@ -53,7 +53,7 @@ class DebugCaptcha extends ChallengeProvider {
graphics2D.dispose() graphics2D.dispose()
val baos = new ByteArrayOutputStream() val baos = new ByteArrayOutputStream()
try { try {
ImageIO.write(img, "png", baos) PngImageWriter.write(baos, img);
} catch { } catch {
case e: Exception => case e: Exception =>
e.printStackTrace() e.printStackTrace()

View File

@ -8,6 +8,8 @@ import java.awt.Color
import lc.captchas.interfaces.ChallengeProvider import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge import lc.captchas.interfaces.Challenge
import java.util.{List => JavaList, Map => JavaMap} import java.util.{List => JavaList, Map => JavaMap}
import java.io.ByteArrayOutputStream
import lc.misc.PngImageWriter
class FilterChallenge extends ChallengeProvider { class FilterChallenge extends ChallengeProvider {
def getId = "FilterChallenge" def getId = "FilterChallenge"
@ -41,7 +43,15 @@ class FilterChallenge extends ChallengeProvider {
var image = ImmutableImage.fromAwt(canvas) var image = ImmutableImage.fromAwt(canvas)
val s = scala.util.Random.nextInt(2) val s = scala.util.Random.nextInt(2)
image = filterTypes(s).applyFilter(image) image = filterTypes(s).applyFilter(image)
new Challenge(image.bytes(new nio.PngWriter()), "image/png", secret) val img = image.awt()
val baos = new ByteArrayOutputStream()
try {
PngImageWriter.write(baos, img);
} catch {
case e: Exception =>
e.printStackTrace()
}
new Challenge(baos.toByteArray, "image/png", secret)
} }
def checkAnswer(secret: String, answer: String): Boolean = { def checkAnswer(secret: String, answer: String): Boolean = {
secret == answer secret == answer

View File

@ -10,6 +10,7 @@ import java.awt.Color
import lc.captchas.interfaces.ChallengeProvider import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge import lc.captchas.interfaces.Challenge
import java.util.{List => JavaList, Map => JavaMap} import java.util.{List => JavaList, Map => JavaMap}
import lc.misc.PngImageWriter
class LabelCaptcha extends ChallengeProvider { class LabelCaptcha extends ChallengeProvider {
private var knownFiles = new File("known").list.toList private var knownFiles = new File("known").list.toList
@ -49,7 +50,7 @@ class LabelCaptcha extends ChallengeProvider {
val token = encrypt(knownImageFile + "," + unknownImageFile) val token = encrypt(knownImageFile + "," + unknownImageFile)
val baos = new ByteArrayOutputStream() val baos = new ByteArrayOutputStream()
ImageIO.write(mergedImage, "png", baos) PngImageWriter.write(baos, mergedImage);
new Challenge(baos.toByteArray(), "image/png", token) new Challenge(baos.toByteArray(), "image/png", token)
} }