/* * Copyright 2015 Patrick Ahlbrecht * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.onyxbits.raccoon.qr; import java.awt.AWTEvent; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.util.HashMap; import javax.swing.Action; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; /** * A {@link JPanel} that paints a QR code on its background. * * @author patrick * */ public class QrPanel extends JPanel { /** * */ private static final long serialVersionUID = 1L; private static final BufferedImage BLANK = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); private static final int[] PIX = { 0, 0, 0, 255 }; private static final int[] BACK = { 0, 0, 0, 0 }; private BufferedImage image; private int size; private QRCodeWriter qrCodeWriter; private HashMap<EncodeHintType, Object> hintMap; private JPopupMenu menu; private boolean toggle; private String contentString; /** * Create a new panel of a given size. * * @param size * panel width/height */ public QrPanel(int size) { this.size = size; qrCodeWriter = new QRCodeWriter(); hintMap = new HashMap<EncodeHintType, Object>(); hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); hintMap.put(EncodeHintType.CHARACTER_SET, "UTF-8"); image = BLANK; } /** * Add popup menu to the panel. * * @param menuActions * actions to put into the popup menu. a null entry creates a * separator. */ public QrPanel withActions(Action... menuActions) { if (menuActions != null) { enableEvents(AWTEvent.MOUSE_EVENT_MASK); menu = new JPopupMenu(); for (Action act : menuActions) { if (act == null) { menu.add(new JSeparator()); } else { menu.add(act); } } } return this; } @Override protected void processMouseEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_RELEASED) { if (toggle) { menu.setVisible(false); } else { menu.show(e.getComponent(), e.getX(), e.getY()); } toggle = !toggle; } } /** * Create a new panel with standard size. */ public QrPanel() { this(200); } /** * Change the contents of the panel * * @param content * string to render. A string that cannot be rendered (empty, null, * too long) will result in a blank panel. */ public void setContentString(String content) { contentString = content; try { BitMatrix byteMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, size, size, hintMap); int size = byteMatrix.getWidth(); image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); WritableRaster raster = image.getRaster(); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (byteMatrix.get(i, j)) { raster.setPixel(i, j, PIX); } else { raster.setPixel(i, j, BACK); } } } } catch (Exception e) { image = BLANK; } repaint(); } /** * Query the image * * @return the currently showing code. */ public BufferedImage getImage() { return image; } @Override public Dimension getPreferredSize() { Insets in = getInsets(); return new Dimension(size + in.left + in.right + 5, size + in.top + in.bottom + 5); } @Override public void paint(Graphics gr) { super.paint(gr); // Draw the QR code centered; Use a bitshift to divide by 2 (potentially // faster). int x = (getWidth() >> 1) - (size >> 1); int y = (getHeight() >> 1) - (size >> 1); gr.drawImage(image, x, y, size, size, null); } public String getContentString() { return contentString; } }