Fixed the build.
[zxing.git] / core / src / com / google / zxing / qrcode / encoder / Renderer.java
1 /*
2  * Copyright 2008 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.qrcode.encoder;
18
19 // #include "third_party/png/png.h"
20
21 /**
22  * JAVAPORT: This class may get thrown out in the future, or it may turn into the object which
23  * returns a MonochromeBitmapSource.
24  *
25  * @author satorux@google.com (Satoru Takabayashi) - creator
26  * @author dswitkin@google.com (Daniel Switkin) - ported from C++
27  */
28 public final class Renderer {
29
30   // See 7.3.7 of JISX0510:2004 (p. 11).
31   private static final int kQuietZoneSize = 4;
32
33   // Render QR Code as PNG image with "cell_size". On success, store
34   // the result in "result" and return true.  On error, return false.
35   // The recommended cell size for desktop screens is 3.  This
36   // setting generates 87x87 pixels PNG image for version 1 QR Code
37   // (21x21). 87 = (21 + 4 + 4) * 3.  4 is for surrounding white
38   // space (they call it quiet zone).
39   // Sorry for the long function but libpng's API is a bit complecated.
40 // See http://www.libpng.org/pub/png/libpng-1.2.5-manual.html for
41   // details.
42   public static boolean RenderAsPNG(final QRCode &qr_code, int cell_size,
43                                     String *result) {
44     // First, clear the result String.
45     result.clear();
46
47     // Create PNG class.
48     png_structp png_ptr =  png_create_write_struct(PNG_LIBPNG_VER_STRING,
49         null, null, null);
50     if (png_ptr == null) {
51       Debug.LOG_ERROR("Unable to create png_strupctp");
52       return false;
53     }
54
55     // Create PNG info.
56     png_infop info_ptr = png_create_info_struct(png_ptr);
57     if (info_ptr == null) {
58       Debug.LOG_ERROR("Unable to create png_infop");
59       png_destroy_write_struct(&png_ptr, (png_infopp)null);
60       return false;
61     }
62
63     // Calculate the width of the resulting image.  Note that the height
64     // is equal to the width (i.e. the resulting image is square).
65     final int image_width = (qr_code.matrix_width() +
66         kQuietZoneSize * 2) * cell_size;
67     // Since we use 1-bit color depth, we only need 1 bit per pixel.
68     final int num_bytes_in_row = image_width / 8 +
69         (image_width % 8 == 0 ? 0 : 1);
70     // We'll use this storage later but we should prepare this before
71     // setjmp() so that this will be deleted on error.  Today's lesson
72     // is that RAII isn't reliable with setjmp/longjmp!
73     scoped_array<char> row(new char[num_bytes_in_row]);
74
75     // Erorr handling of libpng is a bit tricky.  If something bad
76     // happens in libpng, they call longjmp() to get to here.
77     if (setjmp(png_ptr.jmpbuf)) {
78       Debug.LOG_ERROR("Something bad happened in libpng");
79       png_destroy_write_struct(&png_ptr, &info_ptr);
80       return false;
81     }
82
83     // Attach the pointer to the result String and the pointer to the
84     // writer function.
85     png_set_write_fn(png_ptr, static_cast<void*>(result), PNGWriter, null);
86
87     // Set the image information.
88     png_set_IHDR(png_ptr, info_ptr, image_width, image_width,
89         1,  // The color depth is 1 (black and white).
90         PNG_COLOR_TYPE_GRAY,
91         PNG_INTERLACE_NONE,
92         PNG_COMPRESSION_TYPE_BASE,
93         PNG_FILTER_TYPE_BASE);
94
95     // Write the file header information.
96     png_write_info(png_ptr, info_ptr);
97
98     // Quiet zone at the top.
99     FillRowWithWhite(num_bytes_in_row, row.get());
100     WriteRowNumTimes(png_ptr, row.get(), kQuietZoneSize * cell_size);
101     // Fill data.
102     for (int y = 0; y < qr_code.matrix_width(); ++y) {
103       FillRowWithData(num_bytes_in_row, qr_code, y, cell_size, row.get());
104       WriteRowNumTimes(png_ptr, row.get(), cell_size);
105     }
106     // Quiet zone at the bottom.
107     FillRowWithWhite(num_bytes_in_row, row.get());
108     WriteRowNumTimes(png_ptr, row.get(), kQuietZoneSize * cell_size);
109
110     // Cleanups for libpng stuff.
111     png_write_end(png_ptr, info_ptr);
112     png_destroy_write_struct(&png_ptr, &info_ptr);
113
114     // Finally, it's all done!
115     return true;
116   }
117
118   // Similar to RenderAsPNG but it renders QR code from data in
119   // "bytes" with error correction level "ec_level". This is the
120   // friendliest function in the QR code library.
121   public static boolean RenderAsPNGFromData(final ByteArray& bytes, int ec_level, int cell_size,
122       String *result) {
123     QRCode qr_code;
124     if (!Encoder.Encode(bytes, ec_level, &qr_code)) {
125     return false;
126   }
127     return RenderAsPNG(qr_code, cell_size, result);
128   }
129
130   // Callback function which gets called by png_write_row().
131   private static void PNGWriter(png_structp png_ptr, png_bytep data, png_size_t length) {
132     String* out = static_cast<String*>(png_get_io_ptr(png_ptr));
133     out.append(reinterpret_cast<char*>(data), length);
134   }
135
136   // Fill all pixels in "row" with white.
137   private static void FillRowWithWhite(final int num_bytes_in_row, char *row) {
138     memset(row, 0xff, num_bytes_in_row);
139   }
140
141   // Set the bit in "row" pointed by "index" to 1 (1 is for white).
142   private static void SetBit(final int index, char *row) {
143     final int byte_index = index / 8;
144     final int bit_index = index % 8;
145     row[byte_index] |= 0x80 >> bit_index;
146   }
147
148   // Fill pixels in "row" with data in "qr_code".
149   private static void FillRowWithData(final int num_bytes_in_row,
150                                       final QRCode &qr_code,
151                                       final int y,
152                                       final int cell_size,
153                                       char *row) {
154     memset(row, 0, num_bytes_in_row);  // Fill all pixels with black.
155
156     int index = 0;
157     for (int i = 0; i < kQuietZoneSize * cell_size; ++i) {
158       SetBit(index++, row);  // Cells in the quite zone should be white.
159     }
160     for (int x = 0; x < qr_code.matrix_width(); ++x) {
161       for (int i = 0; i < cell_size; ++i) {
162         if (qr_code.at(x, y) == 0) {  // White cell.
163           SetBit(index, row);
164         }
165         ++index;
166       }
167     }
168     for (int i = 0; i < kQuietZoneSize * cell_size; ++i) {
169       SetBit(index++, row);
170     }
171   }
172
173   // Write pixels in "row" to "png_ptr" "num" times.
174   private static void WriteRowNumTimes(png_structp png_ptr, char *row, final int num) {
175     for (int i = 0; i < num; ++i) {
176       png_write_row(png_ptr, reinterpret_cast<png_bytep>(row));
177     }
178   }
179
180 }