1 /*
2  * This tool creates a frame pattern data for debug purpose used by
3  * test_qrspec. test_qrspec and create_frame_pattern uses the same function
4  * of libqrencode. This means the test is meaningless if test_qrspec is run
5  * with a pattern data created by create_frame_pattern of the same version.
6  * In order to test it correctly, create a pattern data by the tool of the
7  * previous version, or use the frame data attached to the package.
8  */
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include <png.h>
13 #include "common.h"
14 #include "../qrspec.h"
15 
append_pattern(int version,FILE * fp)16 void append_pattern(int version, FILE *fp)
17 {
18 	int width;
19 	unsigned char *frame;
20 
21 	frame = QRspec_newFrame(version);
22 	width = QRspec_getWidth(version);
23 	fwrite(frame, 1, width * width, fp);
24 	free(frame);
25 }
26 
writePNG(unsigned char * frame,int width,const char * outfile)27 static int writePNG(unsigned char *frame, int width, const char *outfile)
28 {
29 	static FILE *fp;
30 	png_structp png_ptr;
31 	png_infop info_ptr;
32 	unsigned char *row, *p, *q;
33 	int x, y, xx, yy, bit;
34 	int realwidth;
35 	const int margin = 0;
36 	const int size = 1;
37 
38 	realwidth = (width + margin * 2) * size;
39 	row = (unsigned char *)malloc((realwidth + 7) / 8);
40 	if(row == NULL) {
41 		fprintf(stderr, "Failed to allocate memory.\n");
42 		exit(EXIT_FAILURE);
43 	}
44 
45 	if(outfile[0] == '-' && outfile[1] == '\0') {
46 		fp = stdout;
47 	} else {
48 		fp = fopen(outfile, "wb");
49 		if(fp == NULL) {
50 			fprintf(stderr, "Failed to create file: %s\n", outfile);
51 			perror(NULL);
52 			exit(EXIT_FAILURE);
53 		}
54 	}
55 
56 	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
57 	if(png_ptr == NULL) {
58 		fclose(fp);
59 		fprintf(stderr, "Failed to initialize PNG writer.\n");
60 		exit(EXIT_FAILURE);
61 	}
62 
63 	info_ptr = png_create_info_struct(png_ptr);
64 	if(info_ptr == NULL) {
65 		fclose(fp);
66 		fprintf(stderr, "Failed to initialize PNG write.\n");
67 		exit(EXIT_FAILURE);
68 	}
69 
70 	if(setjmp(png_jmpbuf(png_ptr))) {
71 		png_destroy_write_struct(&png_ptr, &info_ptr);
72 		fclose(fp);
73 		fprintf(stderr, "Failed to write PNG image.\n");
74 		exit(EXIT_FAILURE);
75 	}
76 
77 	png_init_io(png_ptr, fp);
78 	png_set_IHDR(png_ptr, info_ptr,
79 			realwidth, realwidth,
80 			1,
81 			PNG_COLOR_TYPE_GRAY,
82 			PNG_INTERLACE_NONE,
83 			PNG_COMPRESSION_TYPE_DEFAULT,
84 			PNG_FILTER_TYPE_DEFAULT);
85 	png_write_info(png_ptr, info_ptr);
86 
87 	/* top margin */
88 	memset(row, 0xff, (realwidth + 7) / 8);
89 	for(y=0; y<margin * size; y++) {
90 		png_write_row(png_ptr, row);
91 	}
92 
93 	/* data */
94 	p = frame;
95 	for(y=0; y<width; y++) {
96 		bit = 7;
97 		memset(row, 0xff, (realwidth + 7) / 8);
98 		q = row;
99 		q += margin * size / 8;
100 		bit = 7 - (margin * size % 8);
101 		for(x=0; x<width; x++) {
102 			for(xx=0; xx<size; xx++) {
103 				*q ^= (*p & 1) << bit;
104 				bit--;
105 				if(bit < 0) {
106 					q++;
107 					bit = 7;
108 				}
109 			}
110 			p++;
111 		}
112 		for(yy=0; yy<size; yy++) {
113 			png_write_row(png_ptr, row);
114 		}
115 	}
116 	/* bottom margin */
117 	memset(row, 0xff, (realwidth + 7) / 8);
118 	for(y=0; y<margin * size; y++) {
119 		png_write_row(png_ptr, row);
120 	}
121 
122 	png_write_end(png_ptr, info_ptr);
123 	png_destroy_write_struct(&png_ptr, &info_ptr);
124 
125 	fclose(fp);
126 	free(row);
127 
128 	return 0;
129 }
130 
write_pattern_image(int version,const char * filename)131 void write_pattern_image(int version, const char *filename)
132 {
133 	int width;
134 	unsigned char *frame;
135 	static char str[256];
136 
137 	frame = QRspec_newFrame(version);
138 	width = QRspec_getWidth(version);
139 
140 	snprintf(str, 256, "%s-%d.png", filename, version);
141 	writePNG(frame, width, str);
142 	free(frame);
143 }
144 
write_pattern(const char * filename)145 void write_pattern(const char *filename)
146 {
147 	FILE *fp;
148 	int i;
149 
150 	fp = fopen(filename, "wb");
151 	if(fp == NULL) {
152 		perror("Failed to open a file to write:");
153 		abort();
154 	}
155 	for(i=1; i<=QRSPEC_VERSION_MAX; i++) {
156 		append_pattern(i, fp);
157 		write_pattern_image(i, filename);
158 	}
159 	fclose(fp);
160 }
161 
main(int argc,char ** argv)162 int main(int argc, char **argv)
163 {
164 	if(argc < 2) {
165 		printf("Create empty frame patterns.\nUsage: %s FILENAME\n", argv[0]);
166 		exit(0);
167 	}
168 	write_pattern(argv[1]);
169 	return 0;
170 }
171