QR-Programm
This commit is contained in:
parent
6cc9b9e973
commit
5481ca8841
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="lib" path="jgoodies-common-1.8.0.jar" sourcepath="jgoodies-common-1.8.0-sources.jar"/>
|
||||
<classpathentry kind="lib" path="jgoodies-forms-1.8.0.jar" sourcepath="jgoodies-forms-1.8.0-sources.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Sven.QR</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue