diff --git a/QR/.classpath b/QR/.classpath new file mode 100644 index 0000000..e693970 --- /dev/null +++ b/QR/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/QR/.project b/QR/.project new file mode 100644 index 0000000..e89508e --- /dev/null +++ b/QR/.project @@ -0,0 +1,17 @@ + + + Sven.QR + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/QR/.settings/org.eclipse.jdt.core.prefs b/QR/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..bb35fa0 --- /dev/null +++ b/QR/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/QR/bin/BorderInformation.class b/QR/bin/BorderInformation.class new file mode 100644 index 0000000..c3cbf32 Binary files /dev/null and b/QR/bin/BorderInformation.class differ diff --git a/QR/bin/MainFrame$1.class b/QR/bin/MainFrame$1.class new file mode 100644 index 0000000..bf1764f Binary files /dev/null and b/QR/bin/MainFrame$1.class differ diff --git a/QR/bin/MainFrame$2.class b/QR/bin/MainFrame$2.class new file mode 100644 index 0000000..4ef01d5 Binary files /dev/null and b/QR/bin/MainFrame$2.class differ diff --git a/QR/bin/MainFrame$3.class b/QR/bin/MainFrame$3.class new file mode 100644 index 0000000..a881e5c Binary files /dev/null and b/QR/bin/MainFrame$3.class differ diff --git a/QR/bin/MainFrame$4.class b/QR/bin/MainFrame$4.class new file mode 100644 index 0000000..a4d5252 Binary files /dev/null and b/QR/bin/MainFrame$4.class differ diff --git a/QR/bin/MainFrame$5.class b/QR/bin/MainFrame$5.class new file mode 100644 index 0000000..bf187a4 Binary files /dev/null and b/QR/bin/MainFrame$5.class differ diff --git a/QR/bin/MainFrame$6.class b/QR/bin/MainFrame$6.class new file mode 100644 index 0000000..4264ef0 Binary files /dev/null and b/QR/bin/MainFrame$6.class differ diff --git a/QR/bin/MainFrame.class b/QR/bin/MainFrame.class new file mode 100644 index 0000000..b82a17b Binary files /dev/null and b/QR/bin/MainFrame.class differ diff --git a/QR/bin/Pair.class b/QR/bin/Pair.class new file mode 100644 index 0000000..6a9a342 Binary files /dev/null and b/QR/bin/Pair.class differ diff --git a/QR/bin/PrintActionListener$ImagePrintable.class b/QR/bin/PrintActionListener$ImagePrintable.class new file mode 100644 index 0000000..5ea3e1d Binary files /dev/null and b/QR/bin/PrintActionListener$ImagePrintable.class differ diff --git a/QR/bin/PrintActionListener.class b/QR/bin/PrintActionListener.class new file mode 100644 index 0000000..749a2a9 Binary files /dev/null and b/QR/bin/PrintActionListener.class differ diff --git a/QR/bin/SvenQR.class b/QR/bin/SvenQR.class new file mode 100644 index 0000000..28784e2 Binary files /dev/null and b/QR/bin/SvenQR.class differ diff --git a/QR/jgoodies-common-1.8.0-sources.jar b/QR/jgoodies-common-1.8.0-sources.jar new file mode 100644 index 0000000..24762f7 Binary files /dev/null and b/QR/jgoodies-common-1.8.0-sources.jar differ diff --git a/QR/jgoodies-common-1.8.0.jar b/QR/jgoodies-common-1.8.0.jar new file mode 100644 index 0000000..e67347f Binary files /dev/null and b/QR/jgoodies-common-1.8.0.jar differ diff --git a/QR/jgoodies-forms-1.8.0-sources.jar b/QR/jgoodies-forms-1.8.0-sources.jar new file mode 100644 index 0000000..822eb93 Binary files /dev/null and b/QR/jgoodies-forms-1.8.0-sources.jar differ diff --git a/QR/jgoodies-forms-1.8.0.jar b/QR/jgoodies-forms-1.8.0.jar new file mode 100644 index 0000000..a6a8126 Binary files /dev/null and b/QR/jgoodies-forms-1.8.0.jar differ diff --git a/QR/src/BorderInformation.java b/QR/src/BorderInformation.java new file mode 100644 index 0000000..eb6049b --- /dev/null +++ b/QR/src/BorderInformation.java @@ -0,0 +1,11 @@ +public class BorderInformation { + // Randstärke in Pixeln + public float BorderWidth; + // Erstes schwarzes Pixel in der linken oberen Ecke + public Pair firstBlackPixel; + + public BorderInformation(float width, Pair firstBlack) { + BorderWidth = width; + firstBlackPixel = firstBlack; + } +} diff --git a/QR/src/MainFrame.java b/QR/src/MainFrame.java new file mode 100644 index 0000000..5b197ef --- /dev/null +++ b/QR/src/MainFrame.java @@ -0,0 +1,227 @@ +import java.awt.BorderLayout; +import java.awt.EventQueue; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.UIManager; +import javax.swing.border.EmptyBorder; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.JMenuBar; +import javax.swing.JTabbedPane; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JMenu; +import javax.swing.KeyStroke; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.awt.event.InputEvent; +import java.awt.FlowLayout; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; +import javax.swing.JLabel; +import com.jgoodies.forms.factories.DefaultComponentFactory; +import javax.swing.JTextField; +import javax.imageio.ImageIO; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JCheckBox; + +public class MainFrame extends JFrame { + + private JPanel contentPane; + private JTextField textField; + private JTextField textField_1; + JButton btnEinlesen = new JButton("Einlesen"); + JLabel lblNewLabel = new JLabel("Ausgelesener Wert: -"); + JButton btnDrucken = new JButton("Drucken"); + JButton btnSpeichern = new JButton("Speichern"); + + // Parent für JFileChooser + JFrame _this = this; + // File zum speichern / lesen + File f; + // Generierter QR-Code + BufferedImage img = null; + + /** + * Launch the application. + */ + public static void main(String[] args) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + MainFrame frame = new MainFrame(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Create the frame. + */ + public MainFrame() { + setTitle("Sven.QR"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 600, 400); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(new BorderLayout(0, 0)); + + JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); + contentPane.add(tabbedPane, BorderLayout.CENTER); + + JPanel panel_1 = new JPanel(); + tabbedPane.addTab(" QR-Code generieren ", null, panel_1, null); + panel_1.setLayout(null); + + JLabel lblQrcode = new JLabel("QR-Code Wert:"); + lblQrcode.setBounds(10, 14, 80, 14); + panel_1.add(lblQrcode); + + textField_1 = new JTextField(); + textField_1.setBounds(94, 11, 424, 20); + panel_1.add(textField_1); + textField_1.setColumns(10); + + // + // = BUTTON GENERIEREN: Generiert einen QR-Code aus dem Wert der TextBox und speichert ihn. + // + JButton btnGenerieren = new JButton("Generieren"); + btnGenerieren.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + int value = Integer.parseInt(textField_1.getText()); + img = SvenQR.GenerateQR(value); + } catch(Exception e1) { + JOptionPane.showMessageDialog(_this, "QR-Code konnte nicht generiert werden: " + e1.getMessage()); + return; + } + + btnDrucken.setEnabled(true); + btnSpeichern.setEnabled(true); + } + }); + btnGenerieren.setBounds(94, 42, 89, 23); + panel_1.add(btnGenerieren); + + // + // = BUTTON DRUCKEN: Druckt den generierten QR-Code. + // + + btnDrucken.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + new Thread(new PrintActionListener(img)).start(); + } + }); + btnDrucken.setEnabled(false); + btnDrucken.setBounds(292, 42, 89, 23); + panel_1.add(btnDrucken); + + // + // = BUTTON SPEICHERN: Speichert den generierten QR-Code. + // + + btnSpeichern.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + // JFileChooser erstellen + JFileChooser fc = new JFileChooser(); + // Dateifilter setzen + FileNameExtensionFilter filter = new FileNameExtensionFilter( + "PNG (*.png)", "png"); + + fc.setFileFilter(filter); + + // Wenn im Dialog nicht OK gedrückt wurde, Methode verlassen + if (fc.showSaveDialog(_this) != JFileChooser.APPROVE_OPTION) + return; + + f = fc.getSelectedFile(); + + try { + ImageIO.write(img, "png", f); + } catch (IOException e1) { + JOptionPane.showMessageDialog(_this, "QR-Code konnte nicht gespeichert werden: " + e1.getMessage()); + return; + } + } + }); + btnSpeichern.setEnabled(false); + btnSpeichern.setBounds(193, 42, 89, 23); + panel_1.add(btnSpeichern); + + JPanel panel = new JPanel(); + tabbedPane.addTab(" QR-Code einlesen ", null, panel, null); + panel.setLayout(null); + + JLabel lblQuelldatei = new JLabel("Quelldatei:"); + lblQuelldatei.setBounds(10, 12, 55, 14); + panel.add(lblQuelldatei); + + textField = new JTextField(); + textField.setBounds(75, 8, 451, 21); + panel.add(textField); + textField.setColumns(10); + + // + // = BUTTON ... : Wählt die Quelldatei mit einem JFileChooser aus. = + // + JButton button = new JButton("..."); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + // JFileChooser erstellen + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File("T:/INTABI19/Projekt/ELMO Interactive Toolbox/rec")); + + // Wenn im Dialog nicht OK gedrückt wurde, Methode verlassen + if (fc.showOpenDialog(_this) != JFileChooser.APPROVE_OPTION) + return; + + // Ausgewählte Datei auslesen + f = fc.getSelectedFile(); + // Pfad der Datei in Textbox schreiben + textField.setText(f.getAbsolutePath()); + + // Einlesen-Button aktivieren + btnEinlesen.setEnabled(true); + } + }); + button.setBounds(536, 7, 23, 23); + panel.add(button); + + // + // = BUTTON EINLESEN: Liest ausgewählten QR-Code aus Datei ein. = + // + btnEinlesen.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + // Ausgelesener Wert + int value = -1; + + // Versuche, den QR-Code einzulesen + // Wenn das nicht geht, wird eine Fehlermeldung ausgegeben + try { + value = SvenQR.ReadQR(f.getAbsolutePath()); + } catch (IOException e1) { + JOptionPane.showMessageDialog(_this, "QR-Code konnte nicht eingelesen werden: " + e1.getMessage()); + return; + } + + // Ausgelesener Wert auf Label schreiben + lblNewLabel.setText("Ausgelesener Wert: " + value); + } + }); + btnEinlesen.setEnabled(false); + btnEinlesen.setBounds(75, 40, 89, 23); + panel.add(btnEinlesen); + + + lblNewLabel.setBounds(10, 74, 549, 14); + panel.add(lblNewLabel); + } +} diff --git a/QR/src/Pair.java b/QR/src/Pair.java new file mode 100644 index 0000000..86373d6 --- /dev/null +++ b/QR/src/Pair.java @@ -0,0 +1,15 @@ +public class Pair { + public int x, y; + + public Pair(int _x, int _y) { + x = _x; + y = _y; + } + + // Kopierkonstruktor, da eine Zuweisung nicht die Werte kopiert, + // sondern beide Variablen auf den gleichen Speicher zeigen lässt. + public Pair(Pair copy) { + x = copy.x; + y = copy.y; + } +} diff --git a/QR/src/PrintActionListener.java b/QR/src/PrintActionListener.java new file mode 100644 index 0000000..ad02e2f --- /dev/null +++ b/QR/src/PrintActionListener.java @@ -0,0 +1,71 @@ +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +// Quelle: https://stackoverflow.com/questions/18404553/proper-way-of-printing-a-bufferedimage-in-java + +public class PrintActionListener implements Runnable { + + private BufferedImage image; + + public PrintActionListener(BufferedImage image) { + this.image = image; + } + + @Override + public void run() { + PrinterJob printJob = PrinterJob.getPrinterJob(); + printJob.setPrintable(new ImagePrintable(printJob, image)); + + if (printJob.printDialog()) { + try { + printJob.print(); + } catch (PrinterException prt) { + prt.printStackTrace(); + } + } + } + + public class ImagePrintable implements Printable { + + private double x, y, width; + + private int orientation; + + private BufferedImage image; + + public ImagePrintable(PrinterJob printJob, BufferedImage image) { + PageFormat pageFormat = printJob.defaultPage(); + this.x = pageFormat.getImageableX(); + this.y = pageFormat.getImageableY(); + this.width = pageFormat.getImageableWidth(); + this.orientation = pageFormat.getOrientation(); + this.image = image; + } + + @Override + public int print(Graphics g, PageFormat pageFormat, int pageIndex) + throws PrinterException { + if (pageIndex == 0) { + int pWidth = 0; + int pHeight = 0; + if (orientation == PageFormat.PORTRAIT) { + pWidth = (int) Math.min(width, (double) image.getWidth()); + pHeight = pWidth * image.getHeight() / image.getWidth(); + } else { + pHeight = (int) Math.min(width, (double) image.getHeight()); + pWidth = pHeight * image.getWidth() / image.getHeight(); + } + g.drawImage(image, (int) x, (int) y, pWidth, pHeight, null); + return PAGE_EXISTS; + } else { + return NO_SUCH_PAGE; + } + } + + } + + } diff --git a/QR/src/SvenQR.java b/QR/src/SvenQR.java new file mode 100644 index 0000000..68cf771 --- /dev/null +++ b/QR/src/SvenQR.java @@ -0,0 +1,484 @@ +import java.awt.*; +import java.awt.image.*; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.io.*; +import javax.imageio.ImageIO; + +public class SvenQR { + // Anzahl der Rechtecke horizontal + public static final int AMNT_RECT_X = 4; + // Anzahl der Rechtecke vertikal + public static final int AMNT_RECT_Y = 3; + // Rahmendicke in Pixeln + public static final int BORDER_WIDTH = 8; + // Rechteckgröße in Pixeln + public static final int RECT_WIDTH = 40; + + // Liest das angegebene Bild ein und wertet den QR-Code aus. + public static int ReadQR(String fileName) throws IOException { + // Quellbild + BufferedImage img = ImageIO.read(new File(fileName)); + // Informationen über den Rand und die Ausmaße + BorderInformation info; + // Gemessene Größe des QR-Codes + Pair measuredSize; + // Wert des QR-Codes + int value; + + img = _IN_PrepareImage(img); + + info = _IN_GetBorderWidth(img); + + Pair imageSize = new Pair((int) img.getWidth(), (int) img.getHeight()); + measuredSize = _IN_GetMeasuredSize(img, info, imageSize); + + // Durchschnittsgröße der Rechtecke + int avgSquareWidth = (int) ((measuredSize.x - 4f * info.BorderWidth) / AMNT_RECT_X); + int avgSquareHeight = (int) ((measuredSize.y - 4f * info.BorderWidth) / AMNT_RECT_Y); + Pair avgSquareSize = new Pair(avgSquareWidth, avgSquareHeight); + + value = _IN_HeuristicDetermination(img, info, avgSquareSize); + + return value; + } + + public static BufferedImage GenerateQR(int value) { + boolean[][] bits; + BufferedImage img; + + // Konvertiere die Zahl in eine Bit-Tabelle, die der QR-Code-Darstellung + // entspricht + bits = _OUT_GetBits(value); + + // Generiere Bild + img = _OUT_DrawImage(bits); + + return img; + } + + public static BufferedImage _IN_PrepareImage(BufferedImage img) { + // Bildgröße auslesen + int width = img.getWidth(); + int height = img.getHeight(); + + // + // = BILD ENTSÄTTIGEN UND KONTRAST SPREIZEN = + // + // Jedes Pixel durchgehen und in Graustufen umwandeln, + // danach den Kontrast spreizen, sodass nur noch schwarze + // und weiße Pixel im Bild sind, anders kann der Algorithmus + // nicht arbeiten. + // + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + + // Aktuelles Pixel auslesen + int value = img.getRGB(x, y); + Color c1 = new Color(value); + + // Graustufe berechnen + int grau = (c1.getBlue() + c1.getRed() + c1.getGreen()) / 3; + + // Kontrast spreizen + if (grau >= 127) { + grau = 255; + } else { + grau = 0; + } + + // Pixel ersetzen + Color c = new Color(grau, grau, grau); + img.setRGB(x, y, c.getRGB()); + } + } + + /*try { + File fx = new File("X:/ents.png"); // Speicherort + ImageIO.write(img, "png", fx); // Bildformat + } catch (IOException e) { + System.out.println("Error: " + e); + }*/ + + // + // = ALLEINSTEHENDE PIXEL IM BILD ENTFERNEN = + // + // Wenn das Bild fleckig ist, entstehen einzelne Pixel, die + // den Algorithmus zum auslesen stören können, also werden + // diese entfernt. + // + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + boolean weissAussendrum = true; + + // Rechts + if (!(x < width - 1 && img.getRGB(x + 1, y) == -1)) + weissAussendrum = false; + // Links + if (!(x > 0 && img.getRGB(x - 1, y) == -1)) + weissAussendrum = false; + // Drunter + if (!(y < height - 1 && img.getRGB(x, y + 1) == -1)) + weissAussendrum = false; + // Drüber + if (!(y > 0 && img.getRGB(x, y - 1) == -1)) + weissAussendrum = false; + + // Links oben + if (!(x > 0 && y > 0 && img.getRGB(x - 1, y - 1) == - 1)) + weissAussendrum = false; + // Links unten + if (!(x > 0 && y < height - 1 && img.getRGB(x - 1, y + 1) == -1)) + weissAussendrum = false; + // Rechts oben + if (!(x < width - 1 && y > 0 && img.getRGB(x + 1, y - 1) == -1)) + weissAussendrum = false; + // Rechts unten + if (!(x < width - 1 && y < height - 1 && img.getRGB(x + 1, y + 1) == -1)) + weissAussendrum = false; + + if (weissAussendrum) + img.setRGB(x, y, -1 ); + + } + } + + /*try { + File fx = new File("X:/prep2.png"); // Speicherort + ImageIO.write(img, "png", fx); // Bildformat + } catch (IOException e) { + System.out.println("Error: " + e); + }*/ + + return img; + } + + private static BorderInformation _IN_GetBorderWidth(BufferedImage img) { + Color pixel; + + // Informationen über den Rahmen des QR-Codes + BorderInformation info = null; + + // Breite des schwarzen Rahmens und Orientierungspunkte + float borderWidth = -1f; + Pair firstBlackPixel = new Pair(-1, -1); + Pair firstWhitePixel; + + // + // = SUCHE DAS ERSTE SCHWARZE PIXEL IN DER LINKEN OBEREN ECKE = + // + + // Gehe diagonal durch das Bild auf der Suche nach schwarzen Pixeln + while (!_IN_CompareColors(img.getRGB(firstBlackPixel.x + 1, firstBlackPixel.y + 1), Color.BLACK)) { + firstBlackPixel.x++; + firstBlackPixel.y++; + } + + firstBlackPixel.x++; + firstBlackPixel.y++; + + // Aufgrund von Ungenauigkeiten beim Drucken, gehen wir drei Pixel in den Rand rein + firstBlackPixel.x += 2; + + System.out.println("Suche schwarzes Pixel."); + System.out.println("X: " + firstBlackPixel.x + " Y: " + firstBlackPixel.y + "\n"); + + + // Gehe so weit wie möglich nach oben + while (firstBlackPixel.y > 0 + && _IN_CompareColors(img.getRGB(firstBlackPixel.x, firstBlackPixel.y - 1), Color.BLACK)) + firstBlackPixel.y--; + + System.out.println("Gehe so weit wie möglich nach oben"); + System.out.println("X: " + firstBlackPixel.x + " Y: " + firstBlackPixel.y + "\n"); + + // Gehe so weit wie möglich nach links + while (firstBlackPixel.x > 0 + && _IN_CompareColors(img.getRGB(firstBlackPixel.x - 1, firstBlackPixel.y), Color.BLACK)) + firstBlackPixel.x--; + + System.out.println("Gehe so weit wie möglich nach links"); + System.out.println("X: " + firstBlackPixel.x + " Y: " + firstBlackPixel.y + "\n"); + + // + // = SUCHE DAS ERSTE WEISSE PIXEL VOM INNEREN RAHMEN = + // + + firstWhitePixel = new Pair(firstBlackPixel); + + // Gehe diagonal vom ersten schwarzen Pixel durch das Bild + while (!_IN_CompareColors(img.getRGB(firstWhitePixel.x + 1, firstWhitePixel.y + 1), Color.WHITE)) { + firstWhitePixel.x++; + firstWhitePixel.y++; + } + + firstWhitePixel.x++; + firstWhitePixel.y++; + + System.out.println("Suche weißes Pixel"); + System.out.println("X: " + firstWhitePixel.x + " Y: " + firstWhitePixel.y + "\n"); + + // Gehe so weit wie möglich nach oben + while (_IN_CompareColors(img.getRGB(firstWhitePixel.x, firstWhitePixel.y - 1), Color.WHITE)) + firstWhitePixel.y--; + + System.out.println("Gehe soweit wie möglich nach oben"); + System.out.println("X: " + firstWhitePixel.x + " Y: " + firstWhitePixel.y + "\n"); + + // Gehe so weit wie möglich nach links + while (_IN_CompareColors(img.getRGB(firstWhitePixel.x - 1, firstWhitePixel.y), Color.WHITE)) + firstWhitePixel.x--; + + System.out.println("Gehe soweit wie möglich nach links"); + System.out.println("X: " + firstWhitePixel.x + " Y: " + firstWhitePixel.y + "\n"); + + // Differenzen, also Rahmenstärke ausrechnen + int deltaX = firstWhitePixel.x - firstBlackPixel.x; + int deltaY = firstWhitePixel.y - firstBlackPixel.y; + + // Durchschnitt ermitteln + borderWidth = (deltaX + deltaY) / 2f; + + System.out.println("Border width: " + borderWidth); + + info = new BorderInformation(borderWidth, firstBlackPixel); + return info; + } + + private static Pair _IN_GetMeasuredSize(BufferedImage img, BorderInformation borderInfo, Pair imageSize) { + Pair measuredSize; + Pair upperRightBlackPixel, lowerLeftBlackPixel; + Color pixel; + + // + // = MESSE DIE BREITE DES QR-CODES = + // + + upperRightBlackPixel = new Pair(borderInfo.firstBlackPixel); + // Weil das Bild nicht immer gerade ist, messen wir in der Mitte des + // schwarzen Rahmens + upperRightBlackPixel.y += borderInfo.BorderWidth / 2f; + + while (upperRightBlackPixel.x < imageSize.x - 1 + && !_IN_CompareColors(img.getRGB(upperRightBlackPixel.x + 1, upperRightBlackPixel.y), Color.WHITE)) + upperRightBlackPixel.x++; + + // + // = MESSE DIE HÖHE DES QR-CODES = + // + + lowerLeftBlackPixel = new Pair(borderInfo.firstBlackPixel); + // Immer mittig messen, kann bei arg schiefen Bildern jedoch auch wieder + // zu fehlerhaften Ergebnissen führen + // In solch einem Fall können wir nichts tun :/ + lowerLeftBlackPixel.x += borderInfo.BorderWidth / 2f; + + while (lowerLeftBlackPixel.y < imageSize.y - 1 + && !_IN_CompareColors(img.getRGB(upperRightBlackPixel.x, upperRightBlackPixel.y + 1), Color.WHITE)) + lowerLeftBlackPixel.y++; + + // Errechne die Größe des QR-Codes aus den Differenzen der Punkte + measuredSize = new Pair(upperRightBlackPixel.x - borderInfo.firstBlackPixel.x, + lowerLeftBlackPixel.y - borderInfo.firstBlackPixel.y); + measuredSize.x++; + measuredSize.y++; + + System.out.println("Gemessene Größe: " + measuredSize.x + " x " + measuredSize.y); + + return measuredSize; + } + + private static int _IN_HeuristicDetermination(BufferedImage img, BorderInformation borderInfo, Pair avgSquareSize) { + boolean[][] bits = new boolean[AMNT_RECT_X][AMNT_RECT_Y]; + float halfWidth = avgSquareSize.x / 2f, halfHeight = avgSquareSize.y / 2f; + int c_value; + + for (int x = 0; x < AMNT_RECT_X; x++) { + for (int y = 0; y < AMNT_RECT_Y; y++) { + + int _x = (int) (2 * borderInfo.BorderWidth); + _x += (int) (x * avgSquareSize.x); + _x += (int) halfWidth; + _x += borderInfo.firstBlackPixel.x; + + int _y = (int) (2 * borderInfo.BorderWidth); + _y += (int) (y * avgSquareSize.y); + _y += (int) halfHeight; + _y += borderInfo.firstBlackPixel.y; + + c_value = img.getRGB(_x, _y); + System.out.println("X: " + _x + " Y: " + _y + " V: " + (_IN_CompareColors(c_value, Color.WHITE) ? false : true)); + + if (_IN_CompareColors(c_value, Color.WHITE)) + bits[x][y] = false; + else if (_IN_CompareColors(c_value, Color.BLACK)) + bits[x][y] = true; + } + } + + int value = 0; + + if (bits[0][0]) + value += 1; + if (bits[1][0]) + value += 2; + if (bits[2][0]) + value += 4; + if (bits[3][0]) + value += 8; + + if (bits[0][1]) + value += 16; + if (bits[1][1]) + value += 32; + if (bits[2][1]) + value += 64; + if (bits[3][1]) + value += 128; + + if (bits[0][2]) + value += 256; + if (bits[1][2]) + value += 512; + if (bits[2][2]) + value += 1024; + if (bits[3][2]) + value += 2048; + + return value; + } + + private static boolean _IN_CompareColors(int rgb, Color template) { + Color c = new Color(rgb); + if (c.getRed() != template.getRed()) + return false; + if (c.getGreen() != template.getGreen()) + return false; + if (c.getBlue() != template.getBlue()) + return false; + return true; + } + + private static boolean[][] _OUT_GetBits(int value) { + // Die Bits in QR-Code-Darstellung + boolean[][] bits = new boolean[AMNT_RECT_X][AMNT_RECT_Y]; + // Die Bits als Binärstring + String bitsAsString = Integer.toBinaryString(value); + // Anzahl an führenden Nullen für 12-Bit: + int amntLeadingZeros = 12 - bitsAsString.length(); + + // Stelle führende Nullen voran + for (int i = 0; i < amntLeadingZeros; i++) + bitsAsString = "0" + bitsAsString; + + bits[0][0] = bitsAsString.charAt(11) == '0' ? false : true; + bits[1][0] = bitsAsString.charAt(10) == '0' ? false : true; + bits[2][0] = bitsAsString.charAt(9) == '0' ? false : true; + bits[3][0] = bitsAsString.charAt(8) == '0' ? false : true; + bits[0][1] = bitsAsString.charAt(7) == '0' ? false : true; + bits[1][1] = bitsAsString.charAt(6) == '0' ? false : true; + bits[2][1] = bitsAsString.charAt(5) == '0' ? false : true; + bits[3][1] = bitsAsString.charAt(4) == '0' ? false : true; + bits[0][2] = bitsAsString.charAt(3) == '0' ? false : true; + bits[1][2] = bitsAsString.charAt(2) == '0' ? false : true; + bits[2][2] = bitsAsString.charAt(1) == '0' ? false : true; + bits[3][2] = bitsAsString.charAt(0) == '0' ? false : true; + + return bits; + } + + private static BufferedImage _OUT_DrawImage(boolean[][] bits) { + // Bildgröße + Pair imageSize; + // Bild + BufferedImage img; + // Grafikobjekt zum zeichnen + Graphics2D g; + + // Bildbreite und -höhe berechnen + // Bei 72 dpi entspricht 1mm 3px, wir nehmen 2px + imageSize = new Pair(BORDER_WIDTH * 4 + AMNT_RECT_X * RECT_WIDTH, BORDER_WIDTH * 4 + AMNT_RECT_Y * RECT_WIDTH); + + // Bild erstellen und Grafikobjekt erstellen + img = new BufferedImage(imageSize.x, imageSize.y, BufferedImage.TYPE_INT_ARGB); + g = img.createGraphics(); + + // + // = QR-CODE-ZEICHEN = + // + + // Äußeren Rahmen zeichnen + g.setColor(Color.BLACK); + g.fillRect(0, 0, imageSize.x, imageSize.y); + + // Inneren Rahmen zeichnen + g.setColor(Color.WHITE); + g.fillRect(BORDER_WIDTH, BORDER_WIDTH, imageSize.x - 2 * BORDER_WIDTH, imageSize.y - 2 * BORDER_WIDTH); + + g.setColor(Color.BLACK); + + // Rechtecke zeichnen + for (int x = 0; x < AMNT_RECT_X; x++) { + for (int y = 0; y < AMNT_RECT_Y; y++) { + int _x = BORDER_WIDTH * 2 + x * RECT_WIDTH; + int _y = BORDER_WIDTH * 2 + y * RECT_WIDTH; + + if (!bits[x][y]) + continue; + + g.fillRect(_x, _y, RECT_WIDTH, RECT_WIDTH); + } + } + + // Rechte untere Ecke als Orientierungspunkt entfernen + g.setColor(Color.WHITE); + g.fillRect(imageSize.x - BORDER_WIDTH, imageSize.y - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH); + + return img; + } + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +