Download server/zxing/ZxingServer.java from devmandan/qr-scan-difficulty-check: direct link, hf CLI and curl.
- Browser
- Download file 5.36 kB
-
https://huggingface.co/spaces/devmandan/qr-scan-difficulty-check/resolve/main/server/zxing/ZxingServer.java
- Command line
-
hf download hf://spaces/devmandan/qr-scan-difficulty-check/server/zxing/ZxingServer.java
-
curl -L -o ZxingServer.java https://huggingface.co/spaces/devmandan/qr-scan-difficulty-check/resolve/main/server/zxing/ZxingServer.java
5.36 kB
| import com.google.zxing.BarcodeFormat; | |
| import com.google.zxing.BinaryBitmap; | |
| import com.google.zxing.DecodeHintType; | |
| import com.google.zxing.LuminanceSource; | |
| import com.google.zxing.MultiFormatReader; | |
| import com.google.zxing.ReaderException; | |
| import com.google.zxing.Result; | |
| import com.google.zxing.ResultMetadataType; | |
| import com.google.zxing.common.HybridBinarizer; | |
| import javax.imageio.ImageIO; | |
| import java.awt.image.BufferedImage; | |
| import java.io.BufferedReader; | |
| import java.io.ByteArrayOutputStream; | |
| import java.io.File; | |
| import java.io.FileDescriptor; | |
| import java.io.FileOutputStream; | |
| import java.io.InputStreamReader; | |
| import java.io.PrintStream; | |
| import java.nio.charset.StandardCharsets; | |
| import java.util.Base64; | |
| import java.util.EnumMap; | |
| import java.util.LinkedHashSet; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Set; | |
| /** | |
| * ZXing core 3.5.2 as Android's Settings app calls it (SettingsLib QrCamera): QR only, HybridBinarizer, | |
| * decodeWithState on the frame, then on the inverted frame; no TRY_HARDER. | |
| * stdin: "id<TAB>path" lines, each an 8-bit gray PNG. stdout: one JSON line per input, flushed, with every byte | |
| * form of the content ZXing returns (its text as UTF-8 and, where it fits, ISO-8859-1, and its raw byte | |
| * segments), base64-encoded: a read counts when one of them is the picture's content. | |
| */ | |
| public class ZxingServer { | |
| /** A plain gray plane, as SettingsLib's QrYuvLuminanceSource hands ZXing the camera's Y plane. */ | |
| static final class GraySource extends LuminanceSource { | |
| private final byte[] data; | |
| GraySource(byte[] data, int width, int height) { | |
| super(width, height); | |
| this.data = data; | |
| } | |
| public byte[] getRow(int y, byte[] row) { | |
| int w = getWidth(); | |
| if (row == null || row.length < w) row = new byte[w]; | |
| System.arraycopy(data, y * w, row, 0, w); | |
| return row; | |
| } | |
| public byte[] getMatrix() { | |
| return data; | |
| } | |
| } | |
| static Result decode(MultiFormatReader reader, LuminanceSource source) { | |
| try { | |
| return reader.decodeWithState(new BinaryBitmap(new HybridBinarizer(source))); | |
| } catch (ReaderException e) { | |
| return null; | |
| } finally { | |
| reader.reset(); | |
| } | |
| } | |
| static Set<String> contents(Result r) throws Exception { | |
| Base64.Encoder b64 = Base64.getEncoder(); | |
| Set<String> out = new LinkedHashSet<>(); | |
| String text = r.getText() == null ? "" : r.getText(); | |
| out.add(b64.encodeToString(text.getBytes(StandardCharsets.UTF_8))); | |
| if (StandardCharsets.ISO_8859_1.newEncoder().canEncode(text)) { | |
| out.add(b64.encodeToString(text.getBytes(StandardCharsets.ISO_8859_1))); | |
| } | |
| Map<ResultMetadataType, Object> md = r.getResultMetadata(); | |
| if (md != null && md.get(ResultMetadataType.BYTE_SEGMENTS) instanceof List) { | |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
| for (byte[] seg : (List<byte[]>) md.get(ResultMetadataType.BYTE_SEGMENTS)) bos.write(seg); | |
| if (bos.size() > 0) out.add(b64.encodeToString(bos.toByteArray())); | |
| } | |
| return out; | |
| } | |
| public static void main(String[] args) throws Exception { | |
| Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class); | |
| hints.put(DecodeHintType.POSSIBLE_FORMATS, List.of(BarcodeFormat.QR_CODE)); | |
| MultiFormatReader reader = new MultiFormatReader(); | |
| reader.setHints(hints); | |
| PrintStream out = new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8); | |
| BufferedReader in = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); | |
| String line; | |
| while ((line = in.readLine()) != null) { | |
| String[] parts = line.split("\t", 2); | |
| if (parts.length < 2 || !parts[0].matches("[0-9]+")) continue; | |
| String id = parts[0]; | |
| BufferedImage img; | |
| try { | |
| img = ImageIO.read(new File(parts[1])); | |
| } catch (Exception e) { | |
| img = null; | |
| } | |
| if (img == null || img.getType() != BufferedImage.TYPE_BYTE_GRAY) { | |
| out.println("{\"id\":" + id + ",\"error\":\"not an 8-bit gray PNG\"}"); | |
| continue; | |
| } | |
| int w = img.getWidth(); | |
| int h = img.getHeight(); | |
| byte[] y = (byte[]) img.getRaster().getDataElements(0, 0, w, h, null); | |
| LuminanceSource src = new GraySource(y, w, h); | |
| Result r = decode(reader, src); | |
| boolean inverted = false; | |
| if (r == null) { // QrCamera: "Check color inversion QR code" | |
| r = decode(reader, src.invert()); | |
| inverted = r != null; | |
| } | |
| StringBuilder sb = new StringBuilder(); | |
| sb.append("{\"id\":").append(id).append(",\"inverted\":").append(inverted).append(",\"contents\":["); | |
| if (r != null) { | |
| int i = 0; | |
| for (String c : contents(r)) sb.append(i++ > 0 ? "," : "").append('"').append(c).append('"'); | |
| } | |
| sb.append("]}"); | |
| out.println(sb); | |
| } | |
| } | |
| } | |