天天看點

java 生成二維碼之簡述

        移動開發現在是一個非常火爆的行業,那麼作為掃一掃就可以添加神器——微信的二維碼來說,那自然也是相當的牛逼的了。

        不多說了,先看看要生成一個二維碼,需要幾步?

        1.準備工作,一個生成二維碼中間的圖示,可選擇;一個是第三方的工具,java這邊的話生成二維碼有很多開發的jar包如 zxing,qrcode( 前者是谷歌開發的後者則是小日本開發的 ) ,這裡的話我使用zxing的開發包來弄。

        2.到網站上去下載下傳zxing包。 http://code.google.com/p/zxing/ 可以選擇版本下載下傳.

        3.直接上幹貨,不需要過多的配置操作。

        代碼片一:

public class BufferedImageLuminanceSource extends LuminanceSource {

    private final BufferedImage image;

    private final int left;

    private final int top;

    public BufferedImageLuminanceSource(BufferedImage image) {

        this(image, 0, 0, image.getWidth(), image.getHeight());

    }

    public BufferedImageLuminanceSource(BufferedImage image, int left,

            int top, int width, int height) {

        super(width, height);

        int sourceWidth = image.getWidth();

        int sourceHeight = image.getHeight();

        if (left + width > sourceWidth || top + height > sourceHeight) {

            throw new IllegalArgumentException(

                    "Crop rectangle does not fit within image data.");

        }

        for (int y = top; y < top + height; y++) {

            for (int x = left; x < left + width; x++) {

                if ((image.getRGB(x, y) & 0xFF000000) == 0) {

                    image.setRGB(x, y, 0xFFFFFFFF); // = white

                }

            }

        }

        this.image = new BufferedImage(sourceWidth, sourceHeight,

                BufferedImage.TYPE_BYTE_GRAY);

        this.image.getGraphics().drawImage(image, 0, 0, null);

        this.left = left;

        this.top = top;

    }

    public byte[] getRow(int y, byte[] row) {

        if (y < 0 || y >= getHeight()) {

            throw new IllegalArgumentException(

                    "Requested row is outside the image: " + y);

        }

        int width = getWidth();

        if (row == null || row.length < width) {

            row = new byte[width];

        }

        image.getRaster().getDataElements(left, top + y, width, 1, row);

        return row;

    }

    public byte[] getMatrix() {

        int width = getWidth();

        int height = getHeight();

        int area = width * height;

        byte[] matrix = new byte[area];

        image.getRaster().getDataElements(left, top, width, height, matrix);

        return matrix;

    }

    public boolean isCropSupported() {

        return true;

    }

    public LuminanceSource crop(int left, int top, int width, int height) {

        return new BufferedImageLuminanceSource(image, this.left + left,

                this.top + top, width, height);

    }

    public boolean isRotateSupported() {

        return true;

    }

    public LuminanceSource rotateCounterClockwise() {

        int sourceWidth = image.getWidth();

        int sourceHeight = image.getHeight();

        AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0,

                0.0, 0.0, sourceWidth);

        BufferedImage rotatedImage = new BufferedImage(sourceHeight,

                sourceWidth, BufferedImage.TYPE_BYTE_GRAY);

        Graphics2D g = rotatedImage.createGraphics();

        g.drawImage(image, transform, null);

        g.dispose();

        int width = getWidth();

        return new BufferedImageLuminanceSource(rotatedImage, top,

                sourceWidth - (left + width), getHeight(), width);

    }

}

生成二維碼代碼片二:

public class CodeUtil {

    private static final String CHARSET = "utf-8";

    private static final String FORMAT_NAME = "JPG";

    // 二維碼尺寸

    private static final int QRCODE_SIZE = 300;

    // LOGO寬度

    private static final int WIDTH = 60;

    // LOGO高度

    private static final int HEIGHT = 60;

    private static BufferedImage createImage(String content, String imgPath,

            boolean needCompress) throws Exception {

        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();

        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);

        hints.put(EncodeHintType.MARGIN, 1);

        BitMatrix bitMatrix = new MultiFormatWriter().encode(content,

                BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);

        int width = bitMatrix.getWidth();

        int height = bitMatrix.getHeight();

        BufferedImage image = new BufferedImage(width, height,

                BufferedImage.TYPE_INT_RGB);

        for (int x = 0; x < width; x++) {

            for (int y = 0; y < height; y++) {

                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000

                        : 0xFFFFFFFF);

            }

        }

        if (imgPath == null || "".equals(imgPath)) {

            return image;

        }

        // 插入圖檔

        CodeUtil.insertImage(image, imgPath, needCompress);

        return image;

    }

    private static void insertImage(BufferedImage source, String imgPath,

            boolean needCompress) throws Exception {

        File file = new File(imgPath);

        if (!file.exists()) {

            System.err.println(""+imgPath+"   該檔案不存在!");

            return;

        }

        Image src = ImageIO.read(new File(imgPath));

        int width = src.getWidth(null);

        int height = src.getHeight(null);

        if (needCompress) { // 壓縮LOGO

            if (width > WIDTH) {

                width = WIDTH;

            }

            if (height > HEIGHT) {

                height = HEIGHT;

            }

            Image image = src.getScaledInstance(width, height,

                    Image.SCALE_SMOOTH);

            BufferedImage tag = new BufferedImage(width, height,

                    BufferedImage.TYPE_INT_RGB);

            Graphics g = tag.getGraphics();

            g.drawImage(image, 0, 0, null); // 繪制縮小後的圖

            g.dispose();

            src = image;

        }

        // 插入LOGO

        Graphics2D graph = source.createGraphics();

        int x = (QRCODE_SIZE - width) / 2;

        int y = (QRCODE_SIZE - height) / 2;

        graph.drawImage(src, x, y, width, height, null);

        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);

        graph.setStroke(new BasicStroke(3f));

        graph.draw(shape);

        graph.dispose();

    }

    public static void encode(String content, String imgPath, String destPath,

            boolean needCompress) throws Exception {

        BufferedImage image = CodeUtil.createImage(content, imgPath,

                needCompress);

        mkdirs(destPath);

        String file = new Random().nextInt(99999999)+".jpg";

        ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file));

    }

    public static void mkdirs(String destPath) {

        File file =new File(destPath);    

        //當檔案夾不存在時,mkdirs會自動建立多層目錄,差別于mkdir.(mkdir如果父目錄不存在則會抛出異常)

        if (!file.exists() && !file.isDirectory()) {

            file.mkdirs();

        }

    }

    public static void encode(String content, String imgPath, String destPath)

            throws Exception {

        CodeUtil.encode(content, imgPath, destPath, false);

    }

    public static void encode(String content, String destPath,

            boolean needCompress) throws Exception {

        CodeUtil.encode(content, null, destPath, needCompress);

    }

    public static void encode(String content, String destPath) throws Exception {

        CodeUtil.encode(content, null, destPath, false);

    }

    public static void encode(String content, String imgPath,

            OutputStream output, boolean needCompress) throws Exception {

        BufferedImage image = CodeUtil.createImage(content, imgPath,

                needCompress);

        ImageIO.write(image, FORMAT_NAME, output);

    }

    public static void encode(String content, OutputStream output)

            throws Exception {

        CodeUtil.encode(content, null, output, false);

    }

    public static String decode(File file) throws Exception {

        BufferedImage image;

        image = ImageIO.read(file);

        if (image == null) {

            return null;

        }

        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(

                image);

        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

        Result result;

        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();

        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);

        result = new MultiFormatReader().decode(bitmap, hints);

        String resultStr = result.getText();

        return resultStr;

    }

    public static String decode(String path) throws Exception {

        return CodeUtil.decode(new File(path));

    }

    public static void main(String[] args) throws Exception {

        String text = "http://www.baidu.com";

        CodeUtil.encode(text, "f:/baidu.jpg", "f:/code", true);

    }

}

4.

問題總結:

1. ZXing掃描二維碼出現中文亂碼的問題:

 ZXing 掃條形碼沒有問題,但是掃描二維碼的時候卻有一部分是亂碼,或者不是中文的問題。

隻要以ISO- 8859 - 1 的格式來編碼,取出結果再進行相應的轉換,問題就解決了,并不需要修改源碼,可以參考上面的代碼。

2. 報錯:java.lang.UnsupportedClassVersionError: com/google/zxing/client/j2se/MatrixToImageWriter

遇到這個問題的話,98%的機率是JDK的版本與ZXing版不搭了,上面已經說過了,2.2版本在JDK1.6應該是沒問題的,2.3的話應該是對JDK1.7有依賴了。

使用者在使用這個的時候要注意,防止出現了問題。