diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WebcamService.java b/src/main/java/com/sparrowwallet/sparrow/control/WebcamService.java index 2473721d..74d7f263 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/WebcamService.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/WebcamService.java @@ -14,6 +14,7 @@ import javafx.concurrent.ScheduledService; import javafx.concurrent.Task; import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.Image; +import net.sourceforge.zbar.ZBar; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -155,6 +156,13 @@ public class WebcamService extends ScheduledService { LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + if(ZBar.isEnabled()) { + ZBar.Scan scan = ZBar.scan(bufferedImage); + if(scan != null) { + return new Result(scan.stringData(), scan.rawData(), new ResultPoint[0], BarcodeFormat.QR_CODE); + } + } + try { return qrReader.decode(bitmap, Map.of(DecodeHintType.TRY_HARDER, Boolean.TRUE)); } catch(ReaderException e) { diff --git a/src/main/java/net/sourceforge/zbar/Config.java b/src/main/java/net/sourceforge/zbar/Config.java new file mode 100644 index 00000000..a5a47c9c --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/Config.java @@ -0,0 +1,76 @@ +/*------------------------------------------------------------------------ + * Config + * + * Copyright 2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +package net.sourceforge.zbar; + +/** + * Decoder configuration options. + */ +public class Config { + /** + * Enable symbology/feature. + */ + public static final int ENABLE = 0; + /** + * Enable check digit when optional. + */ + public static final int ADD_CHECK = 1; + /** + * Return check digit when present. + */ + public static final int EMIT_CHECK = 2; + /** + * Enable full ASCII character set. + */ + public static final int ASCII = 3; + + /** + * Minimum data length for valid decode. + */ + public static final int MIN_LEN = 0x20; + /** + * Maximum data length for valid decode. + */ + public static final int MAX_LEN = 0x21; + + /** + * Required video consistency frames. + */ + public static final int UNCERTAINTY = 0x40; + + /** + * Enable scanner to collect position data. + */ + public static final int POSITION = 0x80; + + /** + * Image scanner vertical scan density. + */ + public static final int X_DENSITY = 0x100; + /** + * Image scanner horizontal scan density. + */ + public static final int Y_DENSITY = 0x101; +} diff --git a/src/main/java/net/sourceforge/zbar/Image.java b/src/main/java/net/sourceforge/zbar/Image.java new file mode 100644 index 00000000..e2123091 --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/Image.java @@ -0,0 +1,197 @@ +/*------------------------------------------------------------------------ + * Image + * + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +package net.sourceforge.zbar; + +import java.io.Closeable; + +/** + * stores image data samples along with associated format and size + * metadata. + */ +public class Image implements Closeable { + static { + init(); + } + + /** + * C pointer to a zbar_symbol_t. + */ + private long peer; + private Object data; + + public Image() { + peer = create(); + } + + public Image(int width, int height) { + this(); + setSize(width, height); + } + + public Image(int width, int height, String format) { + this(); + setSize(width, height); + setFormat(format); + } + + public Image(String format) { + this(); + setFormat(format); + } + + Image(long peer) { + this.peer = peer; + } + + private static native void init(); + + /** + * Create an associated peer instance. + */ + private native long create(); + + public void close() { + destroy(); + } + + /** + * Clean up native data associated with an instance. + */ + public synchronized void destroy() { + if(peer != 0) { + destroy(peer); + peer = 0; + } + } + + /** + * Destroy the associated peer instance. + */ + private native void destroy(long peer); + + /** + * Image format conversion. + * + * @returns a @em new image with the sample data from the original + * image converted to the requested format fourcc. the original + * image is unaffected. + */ + public Image convert(String format) { + long newpeer = convert(peer, format); + if(newpeer == 0) { + return (null); + } + return (new Image(newpeer)); + } + + private native long convert(long peer, String format); + + /** + * Retrieve the image format fourcc. + */ + public native String getFormat(); + + /** + * Specify the fourcc image format code for image sample data. + */ + public native void setFormat(String format); + + /** + * Retrieve a "sequence" (page/frame) number associated with this + * image. + */ + public native int getSequence(); + + /** + * Associate a "sequence" (page/frame) number with this image. + */ + public native void setSequence(int seq); + + /** + * Retrieve the width of the image. + */ + public native int getWidth(); + + /** + * Retrieve the height of the image. + */ + public native int getHeight(); + + /** + * Retrieve the size of the image. + */ + public native int[] getSize(); + + /** + * Specify the pixel size of the image. + */ + public native void setSize(int[] size); + + /** + * Specify the pixel size of the image. + */ + public native void setSize(int width, int height); + + /** + * Retrieve the crop region of the image. + */ + public native int[] getCrop(); + + /** + * Specify the crop region of the image. + */ + public native void setCrop(int[] crop); + + /** + * Specify the crop region of the image. + */ + public native void setCrop(int x, int y, int width, int height); + + /** + * Retrieve the image sample data. + */ + public native byte[] getData(); + + /** + * Specify image sample data. + */ + public native void setData(byte[] data); + + /** + * Specify image sample data. + */ + public native void setData(int[] data); + + /** + * Retrieve the decoded results associated with this image. + */ + public SymbolSet getSymbols() { + return (new SymbolSet(getSymbols(peer))); + } + + private native long getSymbols(long peer); + +} diff --git a/src/main/java/net/sourceforge/zbar/ImageScanner.java b/src/main/java/net/sourceforge/zbar/ImageScanner.java new file mode 100644 index 00000000..39298a11 --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/ImageScanner.java @@ -0,0 +1,110 @@ +/*------------------------------------------------------------------------ + * ImageScanner + * + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +package net.sourceforge.zbar; + +import java.io.Closeable; + +/** + * Read barcodes from 2-D images. + */ +public class ImageScanner implements Closeable { + static { + init(); + } + + /** + * C pointer to a zbar_image_scanner_t. + */ + private long peer; + + public ImageScanner() { + peer = create(); + } + + private static native void init(); + + /** + * Create an associated peer instance. + */ + private native long create(); + + public void close() { + destroy(); + } + + /** + * Clean up native data associated with an instance. + */ + public synchronized void destroy() { + if(peer != 0) { + destroy(peer); + peer = 0; + } + } + + /** + * Destroy the associated peer instance. + */ + private native void destroy(long peer); + + /** + * Set config for indicated symbology (0 for all) to specified value. + */ + public native void setConfig(int symbology, int config, int value) throws IllegalArgumentException; + + /** + * Parse configuration string and apply to image scanner. + */ + public native void parseConfig(String config); + + /** + * Enable or disable the inter-image result cache (default disabled). + * Mostly useful for scanning video frames, the cache filters duplicate + * results from consecutive images, while adding some consistency + * checking and hysteresis to the results. Invoking this method also + * clears the cache. + */ + public native void enableCache(boolean enable); + + /** + * Retrieve decode results for last scanned image. + * + * @returns the SymbolSet result container + */ + public SymbolSet getResults() { + return (new SymbolSet(getResults(peer))); + } + + private native long getResults(long peer); + + /** + * Scan for symbols in provided Image. + * The image format must currently be "Y800" or "GRAY". + * + * @returns the number of symbols successfully decoded from the image. + */ + public native int scanImage(Image image); +} diff --git a/src/main/java/net/sourceforge/zbar/Modifier.java b/src/main/java/net/sourceforge/zbar/Modifier.java new file mode 100644 index 00000000..22b5571e --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/Modifier.java @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------ + * Modifier + * + * Copyright 2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +package net.sourceforge.zbar; + +/** + * Decoder symbology modifiers. + */ +public class Modifier { + /** + * barcode tagged as GS1 (EAN.UCC) reserved + * (eg, FNC1 before first data character). + * data may be parsed as a sequence of GS1 AIs + */ + public static final int GS1 = 0; + + /** + * barcode tagged as AIM reserved + * (eg, FNC1 after first character or digit pair) + */ + public static final int AIM = 1; +} diff --git a/src/main/java/net/sourceforge/zbar/Orientation.java b/src/main/java/net/sourceforge/zbar/Orientation.java new file mode 100644 index 00000000..fa278f2e --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/Orientation.java @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------ + * Orientation + * + * Copyright 2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +package net.sourceforge.zbar; + +/** + * Decoded symbol coarse orientation. + */ +public class Orientation { + /** + * Unable to determine orientation. + */ + public static final int UNKNOWN = -1; + /** + * Upright, read left to right. + */ + public static final int UP = 0; + /** + * sideways, read top to bottom + */ + public static final int RIGHT = 1; + /** + * upside-down, read right to left + */ + public static final int DOWN = 2; + /** + * sideways, read bottom to top + */ + public static final int LEFT = 3; +} diff --git a/src/main/java/net/sourceforge/zbar/Symbol.java b/src/main/java/net/sourceforge/zbar/Symbol.java new file mode 100644 index 00000000..254b100a --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/Symbol.java @@ -0,0 +1,265 @@ +/*------------------------------------------------------------------------ + * Symbol + * + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +package net.sourceforge.zbar; + +import java.io.Closeable; + +/** + * Immutable container for decoded result symbols associated with an image + * or a composite symbol. + */ +public class Symbol implements Closeable { + /** + * No symbol decoded. + */ + public static final int NONE = 0; + /** + * Symbol detected but not decoded. + */ + public static final int PARTIAL = 1; + + /** + * EAN-8. + */ + public static final int EAN8 = 8; + /** + * UPC-E. + */ + public static final int UPCE = 9; + /** + * ISBN-10 (from EAN-13). + */ + public static final int ISBN10 = 10; + /** + * UPC-A. + */ + public static final int UPCA = 12; + /** + * EAN-13. + */ + public static final int EAN13 = 13; + /** + * ISBN-13 (from EAN-13). + */ + public static final int ISBN13 = 14; + /** + * Interleaved 2 of 5. + */ + public static final int I25 = 25; + /** + * DataBar (RSS-14). + */ + public static final int DATABAR = 34; + /** + * DataBar Expanded. + */ + public static final int DATABAR_EXP = 35; + /** + * Codabar. + */ + public static final int CODABAR = 38; + /** + * Code 39. + */ + public static final int CODE39 = 39; + /** + * PDF417. + */ + public static final int PDF417 = 57; + /** + * QR Code. + */ + public static final int QRCODE = 64; + /** + * Code 93. + */ + public static final int CODE93 = 93; + /** + * Code 128. + */ + public static final int CODE128 = 128; + + static { + init(); + } + + /** + * C pointer to a zbar_symbol_t. + */ + private long peer; + /** + * Cached attributes. + */ + private int type; + + /** + * Symbols are only created by other package methods. + */ + Symbol(long peer) { + this.peer = peer; + } + + private static native void init(); + + public void close() { + destroy(); + } + + /** + * Clean up native data associated with an instance. + */ + public synchronized void destroy() { + if(peer != 0) { + destroy(peer); + peer = 0; + } + } + + /** + * Release the associated peer instance. + */ + private native void destroy(long peer); + + /** + * Retrieve type of decoded symbol. + */ + public int getType() { + if(type == 0) { + type = getType(peer); + } + return (type); + } + + private native int getType(long peer); + + /** + * Retrieve symbology boolean configs settings used during decode. + */ + public native int getConfigMask(); + + /** + * Retrieve symbology characteristics detected during decode. + */ + public native int getModifierMask(); + + /** + * Retrieve data decoded from symbol as a String. + */ + public native String getData(); + + /** + * Retrieve raw data bytes decoded from symbol. + */ + public native byte[] getDataBytes(); + + /** + * Retrieve a symbol confidence metric. Quality is an unscaled, + * relative quantity: larger values are better than smaller + * values, where "large" and "small" are application dependent. + */ + public native int getQuality(); + + /** + * Retrieve current cache count. When the cache is enabled for + * the image_scanner this provides inter-frame reliability and + * redundancy information for video streams. + * + * @returns < 0 if symbol is still uncertain + * @returns 0 if symbol is newly verified + * @returns > 0 for duplicate symbols + */ + public native int getCount(); + + /** + * Retrieve an approximate, axis-aligned bounding box for the + * symbol. + */ + public int[] getBounds() { + int n = getLocationSize(peer); + if(n <= 0) { + return (null); + } + + int[] bounds = new int[4]; + int xmin = Integer.MAX_VALUE; + int xmax = Integer.MIN_VALUE; + int ymin = Integer.MAX_VALUE; + int ymax = Integer.MIN_VALUE; + + for(int i = 0; i < n; i++) { + int x = getLocationX(peer, i); + if(xmin > x) { + xmin = x; + } + if(xmax < x) { + xmax = x; + } + + int y = getLocationY(peer, i); + if(ymin > y) { + ymin = y; + } + if(ymax < y) { + ymax = y; + } + } + bounds[0] = xmin; + bounds[1] = ymin; + bounds[2] = xmax - xmin; + bounds[3] = ymax - ymin; + return (bounds); + } + + private native int getLocationSize(long peer); + + private native int getLocationX(long peer, int idx); + + private native int getLocationY(long peer, int idx); + + public int[] getLocationPoint(int idx) { + int[] p = new int[2]; + p[0] = getLocationX(peer, idx); + p[1] = getLocationY(peer, idx); + return (p); + } + + /** + * Retrieve general axis-aligned, orientation of decoded + * symbol. + */ + public native int getOrientation(); + + /** + * Retrieve components of a composite result. + */ + public SymbolSet getComponents() { + return (new SymbolSet(getComponents(peer))); + } + + private native long getComponents(long peer); + + native long next(); +} diff --git a/src/main/java/net/sourceforge/zbar/SymbolIterator.java b/src/main/java/net/sourceforge/zbar/SymbolIterator.java new file mode 100644 index 00000000..a359a168 --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/SymbolIterator.java @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------ + * SymbolIterator + * + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +package net.sourceforge.zbar; + +/** + * Iterator over a SymbolSet. + */ +public class SymbolIterator implements java.util.Iterator { + /** + * Next symbol to be returned by the iterator. + */ + private Symbol current; + + /** + * SymbolIterators are only created by internal interface methods. + */ + SymbolIterator(Symbol first) { + current = first; + } + + /** + * Returns true if the iteration has more elements. + */ + public boolean hasNext() { + return (current != null); + } + + /** + * Retrieves the next element in the iteration. + */ + public Symbol next() { + if(current == null) { + throw (new java.util.NoSuchElementException("access past end of SymbolIterator")); + } + + Symbol result = current; + long sym = current.next(); + if(sym != 0) { + current = new Symbol(sym); + } else { + current = null; + } + return (result); + } + + /** + * Raises UnsupportedOperationException. + */ + public void remove() { + throw (new UnsupportedOperationException("SymbolIterator is immutable")); + } +} diff --git a/src/main/java/net/sourceforge/zbar/SymbolSet.java b/src/main/java/net/sourceforge/zbar/SymbolSet.java new file mode 100644 index 00000000..62313d7b --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/SymbolSet.java @@ -0,0 +1,93 @@ +/*------------------------------------------------------------------------ + * SymbolSet + * + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +package net.sourceforge.zbar; + +import java.io.Closeable; + +/** + * Immutable container for decoded result symbols associated with an image + * or a composite symbol. + */ +public class SymbolSet extends java.util.AbstractCollection implements Closeable { + static { + init(); + } + + /** + * C pointer to a zbar_symbol_set_t. + */ + private long peer; + + /** + * SymbolSets are only created by other package methods. + */ + SymbolSet(long peer) { + this.peer = peer; + } + + private static native void init(); + + public void close() { + destroy(); + } + + /** + * Clean up native data associated with an instance. + */ + public synchronized void destroy() { + if(peer != 0) { + destroy(peer); + peer = 0; + } + } + + /** + * Release the associated peer instance. + */ + private native void destroy(long peer); + + /** + * Retrieve an iterator over the Symbol elements in this collection. + */ + public java.util.Iterator iterator() { + long sym = firstSymbol(peer); + if(sym == 0) { + return (new SymbolIterator(null)); + } + + return (new SymbolIterator(new Symbol(sym))); + } + + /** + * Retrieve the number of elements in the collection. + */ + public native int size(); + + /** + * Retrieve C pointer to first symbol in the set. + */ + private native long firstSymbol(long peer); +} diff --git a/src/main/java/net/sourceforge/zbar/ZBar.java b/src/main/java/net/sourceforge/zbar/ZBar.java new file mode 100644 index 00000000..51be4d43 --- /dev/null +++ b/src/main/java/net/sourceforge/zbar/ZBar.java @@ -0,0 +1,118 @@ +package net.sourceforge.zbar; + +import com.sparrowwallet.sparrow.net.NativeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.util.Iterator; + +public class ZBar { + private static final Logger log = LoggerFactory.getLogger(ZBar.class); + + private final static boolean enabled; + + static { // static initializer + enabled = loadLibrary(); + } + + public static boolean isEnabled() { + return enabled; + } + + public static Scan scan(BufferedImage bufferedImage) { + BufferedImage grayscale = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY); + Graphics2D g2d = (Graphics2D)grayscale.getGraphics(); + g2d.drawImage(bufferedImage, 0, 0, null); + g2d.dispose(); + + byte[] data = convertToY800(grayscale); + + try(Image image = new Image()) { + image.setSize(grayscale.getWidth(), grayscale.getHeight()); + image.setFormat("Y800"); + image.setData(data); + + try(ImageScanner scanner = new ImageScanner()) { + scanner.setConfig(Symbol.NONE, Config.ENABLE, 0); + scanner.setConfig(Symbol.QRCODE, Config.ENABLE, 1); + int result = scanner.scanImage(image); + if(result != 0) { + try(SymbolSet results = scanner.getResults()) { + Scan scan = null; + for(Iterator iter = results.iterator(); iter.hasNext(); ) { + try(Symbol symbol = iter.next()) { + scan = new Scan(symbol.getDataBytes(), symbol.getData()); + } + } + return scan; + } + } + } + } + + return null; + } + + private static byte[] convertToY800(BufferedImage image) { + // Ensure the image is grayscale + if (image.getType() != BufferedImage.TYPE_BYTE_GRAY) { + throw new IllegalArgumentException("Input image must be grayscale"); + } + + // Get the underlying byte array of the image data + byte[] imageData = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); + + // Check if the image size is even + int width = image.getWidth(); + int height = image.getHeight(); + if (width % 2 != 0 || height % 2 != 0) { + throw new IllegalArgumentException("Image dimensions must be even"); + } + + // Prepare the output byte array in Y800 format + byte[] outputData = new byte[width * height]; + int outputIndex = 0; + + // Convert the grayscale image data to Y800 format + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int pixel = imageData[y * width + x] & 0xFF; // Extract the grayscale value + + // Write the grayscale value to the output byte array + outputData[outputIndex++] = (byte) pixel; + } + } + + return outputData; + } + + private static boolean loadLibrary() { + try { + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + if(osName.startsWith("Mac") && osArch.equals("aarch64")) { + NativeUtils.loadLibraryFromJar("/native/osx/aarch64/libzbar.dylib"); + } else if(osName.startsWith("Mac")) { + NativeUtils.loadLibraryFromJar("/native/osx/x64/libzbar.dylib"); + } else if(osName.startsWith("Windows")) { + NativeUtils.loadLibraryFromJar("/native/windows/x64/iconv-2.dll"); + NativeUtils.loadLibraryFromJar("/native/windows/x64/zbar.dll"); + } else if(osArch.equals("aarch64")) { + NativeUtils.loadLibraryFromJar("/native/linux/aarch64/libzbar.so"); + } else { + NativeUtils.loadLibraryFromJar("/native/linux/x64/libzbar.so"); + } + + return true; + } catch(Exception e) { + log.warn("Could not load ZBar native libraries, disabling. " + e.getMessage()); + } + + return false; + } + + public record Scan(byte[] rawData, String stringData) {} +} diff --git a/src/main/resources/native/linux/aarch64/libzbar.so b/src/main/resources/native/linux/aarch64/libzbar.so new file mode 100755 index 00000000..490326f6 Binary files /dev/null and b/src/main/resources/native/linux/aarch64/libzbar.so differ diff --git a/src/main/resources/native/linux/x64/libzbar.so b/src/main/resources/native/linux/x64/libzbar.so new file mode 100755 index 00000000..e7fe52cf Binary files /dev/null and b/src/main/resources/native/linux/x64/libzbar.so differ diff --git a/src/main/resources/native/osx/aarch64/libzbar.dylib b/src/main/resources/native/osx/aarch64/libzbar.dylib new file mode 100755 index 00000000..8ad09d76 Binary files /dev/null and b/src/main/resources/native/osx/aarch64/libzbar.dylib differ diff --git a/src/main/resources/native/osx/x64/libzbar.dylib b/src/main/resources/native/osx/x64/libzbar.dylib new file mode 100755 index 00000000..3b9f11bd Binary files /dev/null and b/src/main/resources/native/osx/x64/libzbar.dylib differ diff --git a/src/main/resources/native/windows/x64/iconv-2.dll b/src/main/resources/native/windows/x64/iconv-2.dll new file mode 100644 index 00000000..700561a8 Binary files /dev/null and b/src/main/resources/native/windows/x64/iconv-2.dll differ diff --git a/src/main/resources/native/windows/x64/zbar.dll b/src/main/resources/native/windows/x64/zbar.dll new file mode 100644 index 00000000..95a1b060 Binary files /dev/null and b/src/main/resources/native/windows/x64/zbar.dll differ