1 /*
2 * render.c - Generic Rendered Format
3 *
4 * Initiall written by Sam Lown for use in gLabels. Converts encoded
5 * data into a generic internal structure of lines and characters
6 * usable in external applications.
7 */
8
9 /*
10 libzint - the open source barcode library
11 Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
16
17 1. Redistributions of source code must retain the above copyright
18 notice, this list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
22 3. Neither the name of the project nor the names of its contributors
23 may be used to endorse or promote products derived from this software
24 without specific prior written permission.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
27 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
30 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 SUCH DAMAGE.
37 */
38
39 #include <locale.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #ifdef _MSC_VER
44 #include <malloc.h>
45 #endif
46 #include "common.h"
47
48 #define GL_CONST 2.8346
49
50 struct zint_render_line *render_plot_create_line(float x, float y, float width, float length);
51 int render_plot_add_line(struct zint_symbol *symbol, struct zint_render_line *line, struct zint_render_line **last_line);
52 struct zint_render_ring *render_plot_create_ring(float x, float y, float radius, float line_width);
53 int render_plot_add_ring(struct zint_symbol *symbol, struct zint_render_ring *ring, struct zint_render_ring **last_ring);
54 struct zint_render_hexagon *render_plot_create_hexagon(float x, float y);
55 int render_plot_add_hexagon(struct zint_symbol *symbol, struct zint_render_hexagon *ring, struct zint_render_hexagon **last_hexagon);
56
57 int render_plot_add_string(struct zint_symbol *symbol, unsigned char *text, float x, float y, float fsize, float width, struct zint_render_string **last_string);
58
render_plot(struct zint_symbol * symbol,const float width,const float height)59 int render_plot(struct zint_symbol *symbol, const float width, const float height) {
60 struct zint_render *render;
61 struct zint_render_line *line, *last_line = NULL;
62 struct zint_render_string *last_string = NULL;
63 struct zint_render_ring *ring, *last_ring = NULL;
64 struct zint_render_hexagon *hexagon, *last_hexagon = NULL;
65
66 int i, r, block_width, latch, this_row;
67 float textpos, textwidth, large_bar_height, preset_height, row_height, row_posn = 0.0;
68 // int error_number = 0;
69 int text_offset, text_height, xoffset, yoffset, textdone, main_symbol_width_x, addon_width_x;
70 char addon[6], textpart[10];
71 int large_bar_count, symbol_lead_in, total_symbol_width_x, total_area_width_x;
72 float addon_text_posn;
73 float default_text_posn;
74 float scaler;
75 const char *locale = NULL;
76 int hide_text = 0;
77 float required_aspect;
78 float symbol_aspect = 1;
79 float x_dimension;
80 int upceanflag = 0;
81
82 // Allocate memory for the rendered version
83 render = symbol->rendered = (struct zint_render *) malloc(sizeof (struct zint_render));
84 if (!symbol->rendered) return ZINT_ERROR_MEMORY;
85 render->lines = NULL;
86 render->strings = NULL;
87 render->rings = NULL;
88 render->hexagons = NULL;
89
90 locale = setlocale(LC_ALL, "C");
91
92 row_height = 0;
93 textdone = 0;
94 textpos = 0.0;
95 main_symbol_width_x = symbol->width;
96 strcpy(addon, "");
97 symbol_lead_in = 0;
98 addon_text_posn = 0.0;
99 addon_width_x = 0;
100
101 /*
102 * Determine if there will be any addon texts and text height
103 */
104 latch = 0;
105 r = 0;
106 /* Isolate add-on text */
107 if (is_extendable(symbol->symbology)) {
108 for(i = 0; i < (int)ustrlen(symbol->text); i++) {
109 if (latch == 1) {
110 addon[r] = symbol->text[i];
111 r++;
112 }
113 if (symbol->text[i] == '+') {
114 latch = 1;
115 }
116 }
117 }
118 addon[r] = '\0';
119
120 if ((!symbol->show_hrt) || (ustrlen(symbol->text) == 0)) {
121 hide_text = 1;
122 text_height = text_offset = 0.0;
123 } else {
124 text_height = 9.0;
125 text_offset = 2.0;
126 }
127
128
129 /*
130 * Calculate the width of the barcode, especially if there are any extra
131 * borders or white space to add.
132 */
133
134 while (!(module_is_set(symbol, symbol->rows - 1, symbol_lead_in))) {
135 symbol_lead_in++;
136 }
137
138 /* Certain symbols need whitespace otherwise characters get chopped off the sides */
139 if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC))
140 || (symbol->symbology == BARCODE_ISBNX)) {
141 switch (ustrlen(symbol->text)) {
142 case 13: /* EAN 13 */
143 case 16:
144 case 19:
145 if (symbol->whitespace_width == 0) {
146 symbol->whitespace_width = 10;
147 }
148 main_symbol_width_x = 96 + symbol_lead_in;
149 upceanflag = 13;
150 break;
151 case 2:
152 main_symbol_width_x = 22 + symbol_lead_in;
153 upceanflag = 2;
154 break;
155 case 5:
156 main_symbol_width_x = 49 + symbol_lead_in;
157 upceanflag = 5;
158 break;
159 default:
160 main_symbol_width_x = 68 + symbol_lead_in;
161 upceanflag = 8;
162 }
163 switch (ustrlen(symbol->text)) {
164 case 11:
165 case 16:
166 /* EAN-2 add-on */
167 addon_width_x = 31;
168 break;
169 case 14:
170 case 19:
171 /* EAN-5 add-on */
172 addon_width_x = 58;
173 break;
174 }
175 }
176 else if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) {
177 upceanflag = 12;
178 if (symbol->whitespace_width < 10) {
179 symbol->whitespace_width = 10;
180 main_symbol_width_x = 96 + symbol_lead_in;
181 }
182 switch (ustrlen(symbol->text)) {
183 case 15:
184 /* EAN-2 add-on */
185 addon_width_x = 31;
186 break;
187 case 18:
188 /* EAN-5 add-on */
189 addon_width_x = 58;
190 break;
191 }
192 }
193 else if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCE_CC)) {
194 upceanflag = 6;
195 if (symbol->whitespace_width == 0) {
196 symbol->whitespace_width = 10;
197 main_symbol_width_x = 51 + symbol_lead_in;
198 }
199 switch (ustrlen(symbol->text)) {
200 case 11:
201 /* EAN-2 add-on */
202 addon_width_x = 31;
203 break;
204 case 14:
205 /* EAN-5 add-on */
206 addon_width_x = 58;
207 break;
208 }
209 }
210
211 total_symbol_width_x = 0.0 + main_symbol_width_x + addon_width_x;
212 total_area_width_x = total_symbol_width_x + (2 * (symbol->border_width + symbol->whitespace_width));
213
214 xoffset = symbol->border_width + symbol->whitespace_width;
215 yoffset = symbol->border_width;
216
217 // Determine if height should be overridden
218 large_bar_count = 0;
219 preset_height = 0.0;
220 for (i = 0; i < symbol->rows; i++) {
221 preset_height += symbol->row_height[i];
222 if (symbol->row_height[i] == 0) {
223 large_bar_count++;
224 }
225 }
226
227 if (large_bar_count == 0) {
228 required_aspect = width / height;
229 symbol_aspect = (total_symbol_width_x + (2 * xoffset)) / (preset_height + (2 * yoffset) + text_offset + text_height);
230 symbol->height = (int) preset_height;
231 if (required_aspect > symbol_aspect) {
232 /* the area is too wide */
233 scaler = height / (preset_height + (2 * yoffset) + text_offset + text_height);
234 render->width = symbol_aspect * height;
235 render->height = height;
236 } else {
237 /* the area is too high */
238 scaler = width / (total_symbol_width_x + (2 * xoffset));
239 render->width = width;
240 render->height = width / symbol_aspect;
241 }
242 } else {
243 scaler = width / (total_symbol_width_x + (2 * xoffset));
244 symbol->height = (int) ((height / scaler) - ((2 * yoffset) + text_offset + text_height));
245
246 render->width = width;
247 render->height = height;
248 }
249 large_bar_height = (symbol->height - preset_height) / large_bar_count;
250
251 if ((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND)) {
252 default_text_posn = (symbol->height + text_offset + symbol->border_width + symbol->border_width) * scaler;
253 } else {
254 default_text_posn = (symbol->height + text_offset + symbol->border_width) * scaler;
255 }
256
257 x_dimension = render->width / total_area_width_x;
258 x_dimension /= GL_CONST;
259
260 /* Set minimum size of symbol */
261 /* Barcode must be at least 2mm high by 2mm across */
262 if (render->height < ((x_dimension * ((2 * symbol->border_width) + text_offset + text_height)) + 2.0) * GL_CONST) {
263 render->height = ((x_dimension * ((2 * symbol->border_width) + text_offset + text_height)) + 2.0) * GL_CONST;
264 }
265 if (render->width < (2.0 * GL_CONST)) {
266 render->width = (2.0 * GL_CONST);
267 }
268
269 if (symbol->symbology == BARCODE_CODABAR) {
270 /* The minimum X-dimension of Codabar is 0.191mm. The minimum bar height is 5mm */
271 if (x_dimension < 0.191) {
272 render->width = 0.191 * GL_CONST * total_area_width_x;
273 }
274 if (render->height < ((x_dimension * ((2 * symbol->border_width) + text_offset + text_height)) + 5.0) * GL_CONST) {
275 render->height = ((x_dimension * ((2 * symbol->border_width) + text_offset + text_height)) + 5.0) * GL_CONST;
276 }
277 }
278 else if (symbol->symbology == BARCODE_CODE49) {
279 /* The minimum X-dimension of Code 49 is 0.191mm */
280 if (x_dimension < 0.191) {
281 render->width = 0.191 * GL_CONST * total_area_width_x;
282 render->height = render->width / symbol_aspect;
283 }
284 }
285
286 if (upceanflag != 0) {
287 /* The X-dimension of UPC/EAN symbols is fixed at 0.330mm */
288 /* NOTE: This code will need adjustment before it correctly deals with composite symbols */
289 render->width = 0.330 * GL_CONST * total_area_width_x;
290 /* The height is also fixed */
291 switch (upceanflag) {
292 case 6:
293 case 12:
294 case 13:
295 /* UPC-A, UPC-E and EAN-13 */
296 /* Height of bars should be 22.85mm */
297 render->height = ((0.330 * ((2 * symbol->border_width) + text_offset + text_height)) + 22.85) * GL_CONST;
298 break;
299 case 8:
300 /* EAN-8 */
301 /* Height of bars should be 18.23mm */
302 render->height = ((0.330 * ((2 * symbol->border_width) + text_offset + text_height)) + 18.23) * GL_CONST;
303 break;
304 default:
305 /* EAN-2 and EAN-5 */
306 /* Height of bars should be 21.10mm */
307 render->height = ((0.330 * ((2 * symbol->border_width) + text_offset + text_height)) + 21.10) * GL_CONST;
308 }
309 }
310
311 if (symbol->symbology == BARCODE_ONECODE) {
312 /* The size of USPS Intelligent Mail barcode is fixed */
313 render->width = 0.508 * GL_CONST * total_area_width_x;
314 render->height = 4.064 * GL_CONST;
315 }
316 else if ((symbol->symbology == BARCODE_POSTNET) || (symbol->symbology == BARCODE_PLANET)) {
317 /* The size of PostNet and PLANET are fized */
318 render->width = 0.508 * GL_CONST * total_area_width_x;
319 render->height = 2.921 * GL_CONST;
320 }
321 else if (((symbol->symbology == BARCODE_AUSPOST) || (symbol->symbology == BARCODE_AUSREPLY)) ||
322 ((symbol->symbology == BARCODE_AUSROUTE) || (symbol->symbology == BARCODE_AUSREDIRECT))) {
323 /* Australia Post use the same sizes as USPS */
324 render->width = 0.508 * GL_CONST * total_area_width_x;
325 render->height = 4.064 * GL_CONST;
326 }
327 else if ((symbol->symbology == BARCODE_RM4SCC) || (symbol->symbology == BARCODE_KIX)) {
328 /* Royal Mail and KIX Code uses 22 bars per inch */
329 render->width = 0.577 * GL_CONST * total_area_width_x;
330 render->height = 5.22 * GL_CONST;
331 }
332
333 if (symbol->symbology == BARCODE_MAXICODE) {
334 /* Maxicode is a fixed size */
335 scaler = GL_CONST; /* Converts from millimeters to the scale used by glabels */
336 render->width = 28.16 * scaler;
337 render->height = 26.86 * scaler;
338
339 /* Central bullseye pattern */
340 ring = render_plot_create_ring(13.64 * scaler, 13.43 * scaler, 0.85 * scaler, 0.67 * scaler);
341 render_plot_add_ring(symbol, ring, &last_ring);
342 ring = render_plot_create_ring(13.64 * scaler, 13.43 * scaler, 2.20 * scaler, 0.67 * scaler);
343 render_plot_add_ring(symbol, ring, &last_ring);
344 ring = render_plot_create_ring(13.64 * scaler, 13.43 * scaler, 3.54 * scaler, 0.67 * scaler);
345 render_plot_add_ring(symbol, ring, &last_ring);
346
347 /* Hexagons */
348 for (r = 0; r < symbol->rows; r++) {
349 for (i = 0; i < symbol->width; i++) {
350 if (module_is_set(symbol, r, i)) {
351 hexagon = render_plot_create_hexagon(((i * 0.88) + (r & 1 ? 1.76 : 1.32)) * scaler, ((r * 0.76) + 0.76) * scaler);
352 render_plot_add_hexagon(symbol, hexagon, &last_hexagon);
353 }
354 }
355 }
356
357 } else {
358 /* everything else uses rectangles (or squares) */
359 /* Works from the bottom of the symbol up */
360 int addon_latch = 0;
361
362 for (r = 0; r < symbol->rows; r++) {
363 this_row = r;
364 if (symbol->row_height[this_row] == 0) {
365 row_height = large_bar_height;
366 } else {
367 row_height = symbol->row_height[this_row];
368 }
369 row_posn = 0;
370 for (i = 0; i < r; i++) {
371 if (symbol->row_height[i] == 0) {
372 row_posn += large_bar_height;
373 } else {
374 row_posn += symbol->row_height[i];
375 }
376 }
377 row_posn += yoffset;
378
379 i = 0;
380 if (module_is_set(symbol, this_row, 0)) {
381 latch = 1;
382 } else {
383 latch = 0;
384 }
385
386 do {
387 block_width = 0;
388 do {
389 block_width++;
390 } while (module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i));
391 if ((addon_latch == 0) && (r == (symbol->rows - 1)) && (i > main_symbol_width_x)) {
392 addon_text_posn = row_posn * scaler;
393 addon_latch = 1;
394 }
395 if (latch == 1) {
396 /* a bar */
397 if (addon_latch == 0) {
398 line = render_plot_create_line((i + xoffset) * scaler, (row_posn) * scaler, block_width * scaler, row_height * scaler);
399 } else {
400 line = render_plot_create_line((i + xoffset) * scaler, (row_posn + 10.0) * scaler, block_width * scaler, (row_height - 5.0) * scaler);
401 }
402 latch = 0;
403
404 render_plot_add_line(symbol, line, &last_line);
405 } else {
406 /* a space */
407 latch = 1;
408 }
409 i += block_width;
410
411 } while (i < symbol->width);
412 }
413 }
414 /* That's done the actual data area, everything else is human-friendly */
415
416
417 /* Add the text */
418 xoffset -= symbol_lead_in;
419 row_posn = (row_posn + large_bar_height) * scaler;
420
421 if (!hide_text) {
422 if (upceanflag == 8) {
423 /* guard bar extensions and text formatting for EAN-8 */
424 i = 0;
425 for (line = symbol->rendered->lines; line != NULL; line = line->next) {
426 switch (i) {
427 case 0:
428 case 1:
429 case 10:
430 case 11:
431 case 20:
432 case 21:
433 line->length += (5.0 * scaler);
434 break;
435 }
436 i++;
437 }
438
439 for (i = 0; i < 4; i++) {
440 textpart[i] = symbol->text[i];
441 }
442 textpart[4] = '\0';
443 textpos = 17;
444 textwidth = 4.0 * 8.5;
445 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
446 for (i = 0; i < 4; i++) {
447 textpart[i] = symbol->text[i + 4];
448 }
449 textpart[4] = '\0';
450 textpos = 50;
451 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
452 textdone = 1;
453 switch (strlen(addon)) {
454 case 2:
455 textpos = xoffset + 86;
456 textwidth = 2.0 * 8.5;
457 render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
458 break;
459 case 5:
460 textpos = xoffset + 100;
461 textwidth = 5.0 * 8.5;
462 render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
463 break;
464 }
465
466 }
467
468 if (upceanflag == 13) {
469 /* guard bar extensions and text formatting for EAN-13 */
470 i = 0;
471 for (line = symbol->rendered->lines; line != NULL; line = line->next) {
472 switch (i) {
473 case 0:
474 case 1:
475 case 14:
476 case 15:
477 case 28:
478 case 29:
479 line->length += (5.0 * scaler);
480 break;
481 }
482 i++;
483 }
484
485 textpart[0] = symbol->text[0];
486 textpart[1] = '\0';
487 textpos = -5; // 7
488 textwidth = 8.5;
489 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
490
491 for (i = 0; i < 6; i++) {
492 textpart[i] = symbol->text[i + 1];
493 }
494 textpart[6] = '\0';
495 textpos = 25;
496 textwidth = 6.0 * 8.5;
497 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
498 for (i = 0; i < 6; i++) {
499 textpart[i] = symbol->text[i + 7];
500 }
501 textpart[6] = '\0';
502 textpos = 72;
503 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
504 textdone = 1;
505 switch (strlen(addon)) {
506 case 2:
507 textpos = xoffset + 114;
508 textwidth = 2.0 * 8.5;
509 render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
510 break;
511 case 5:
512 textpos = xoffset + 128;
513 textwidth = 5.0 * 8.5;
514 render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
515 break;
516 }
517 }
518
519 if (upceanflag == 12) {
520 /* guard bar extensions and text formatting for UPCA */
521 i = 0;
522 for (line = symbol->rendered->lines; line != NULL; line = line->next) {
523 switch (i) {
524 case 0:
525 case 1:
526 case 2:
527 case 3:
528 case 14:
529 case 15:
530 case 26:
531 case 27:
532 case 28:
533 case 29:
534 line->length += (5.0 * scaler);
535 break;
536 }
537 i++;
538 }
539
540 textpart[0] = symbol->text[0];
541 textpart[1] = '\0';
542 textpos = -5;
543 textwidth = 6.2;
544 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn + (2.0 * scaler), 8.0 * scaler, textwidth * scaler, &last_string);
545 for (i = 0; i < 5; i++) {
546 textpart[i] = symbol->text[i + 1];
547 }
548 textpart[5] = '\0';
549 textpos = 27;
550 textwidth = 5.0 * 8.5;
551 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
552 for (i = 0; i < 5; i++) {
553 textpart[i] = symbol->text[i + 6];
554 }
555 textpos = 68;
556 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
557 textpart[0] = symbol->text[11];
558 textpart[1] = '\0';
559 textpos = 100;
560 textwidth = 6.2;
561 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn + (2.0 * scaler), 8.0 * scaler, textwidth * scaler, &last_string);
562 textdone = 1;
563 switch (strlen(addon)) {
564 case 2:
565 textpos = xoffset + 116;
566 textwidth = 2.0 * 8.5;
567 render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
568 break;
569 case 5:
570 textpos = xoffset + 130;
571 textwidth = 5.0 * 8.5;
572 render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
573 break;
574 }
575 }
576
577 if (upceanflag == 6) {
578 /* guard bar extensions and text formatting for UPCE */
579 i = 0;
580 for (line = symbol->rendered->lines; line != NULL; line = line->next) {
581 switch (i) {
582 case 0:
583 case 1:
584 case 14:
585 case 15:
586 case 16:
587 line->length += (5.0 * scaler);
588 break;
589 }
590 i++;
591 }
592
593 textpart[0] = symbol->text[0];
594 textpart[1] = '\0';
595 textpos = -5;
596 textwidth = 6.2;
597 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn + (2.0 * scaler), 8.0 * scaler, textwidth * scaler, &last_string);
598 for (i = 0; i < 6; i++) {
599 textpart[i] = symbol->text[i + 1];
600 }
601 textpart[6] = '\0';
602 textpos = 24;
603 textwidth = 6.0 * 8.5;
604 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
605 textpart[0] = symbol->text[7];
606 textpart[1] = '\0';
607 textpos = 55;
608 textwidth = 6.2;
609 render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn + (2.0 * scaler), 8.0 * scaler, textwidth * scaler, &last_string);
610 textdone = 1;
611 switch (strlen(addon)) {
612 case 2:
613 textpos = xoffset + 70;
614 textwidth = 2.0 * 8.5;
615 render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
616 break;
617 case 5:
618 textpos = xoffset + 84;
619 textwidth = 5.0 * 8.5;
620 render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
621 break;
622 }
623 }
624
625 /* Put normal human readable text at the bottom (and centered) */
626 if (textdone == 0) {
627 // caculate start xoffset to center text
628 render_plot_add_string(symbol, symbol->text, ((symbol->width / 2.0) + xoffset) * scaler, default_text_posn, 9.0 * scaler, 0.0, &last_string);
629 }
630 }
631
632 switch (symbol->symbology) {
633 case BARCODE_MAXICODE:
634 /* Do nothing! */
635 break;
636 default:
637 if ((symbol->output_options & BARCODE_BIND) != 0) {
638 if ((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) {
639 /* row binding */
640 for (r = 1; r < symbol->rows; r++) {
641 line = render_plot_create_line(xoffset * scaler, ((r * row_height) + yoffset - 1) * scaler, symbol->width * scaler, 2.0 * scaler);
642 render_plot_add_line(symbol, line, &last_line);
643 }
644 }
645 }
646 if ((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND)) {
647 line = render_plot_create_line(0, 0, (symbol->width + xoffset + xoffset) * scaler, symbol->border_width * scaler);
648 render_plot_add_line(symbol, line, &last_line);
649 line = render_plot_create_line(0, (symbol->height + symbol->border_width) * scaler, (symbol->width + xoffset + xoffset) * scaler, symbol->border_width * scaler);
650 render_plot_add_line(symbol, line, &last_line);
651 }
652 if (symbol->output_options & BARCODE_BOX) {
653 /* side bars */
654 line = render_plot_create_line(0, 0, symbol->border_width * scaler, (symbol->height + (2 * symbol->border_width)) * scaler);
655 render_plot_add_line(symbol, line, &last_line);
656 line = render_plot_create_line((symbol->width + xoffset + xoffset - symbol->border_width) * scaler, 0, symbol->border_width * scaler, (symbol->height + (2 * symbol->border_width)) * scaler);
657 render_plot_add_line(symbol, line, &last_line);
658 }
659 break;
660 }
661
662 if (locale)
663 setlocale(LC_ALL, locale);
664
665 return 1;
666 }
667
668 /*
669 * Create a new line with its memory allocated ready for adding to the
670 * rendered structure.
671 *
672 * This is much quicker than writing out each line manually (in some cases!)
673 */
render_plot_create_line(float x,float y,float width,float length)674 struct zint_render_line *render_plot_create_line(float x, float y, float width, float length) {
675 struct zint_render_line *line;
676
677 line = (struct zint_render_line*) malloc(sizeof (struct zint_render_line));
678 if (!line) return NULL;
679
680 line->next = NULL;
681 line->x = x;
682 line->y = y;
683 line->width = width;
684 line->length = length;
685
686 return line;
687 }
688
689 /*
690 * Add the line to the current rendering and update the last line's
691 * next value.
692 */
render_plot_add_line(struct zint_symbol * symbol,struct zint_render_line * line,struct zint_render_line ** last_line)693 int render_plot_add_line(struct zint_symbol *symbol, struct zint_render_line *line, struct zint_render_line **last_line) {
694 if (!line) return ZINT_ERROR_MEMORY;
695 if (*last_line)
696 (*last_line)->next = line;
697 else
698 symbol->rendered->lines = line; // first line
699
700 *last_line = line;
701 return 1;
702 }
703
render_plot_create_ring(float x,float y,float radius,float line_width)704 struct zint_render_ring *render_plot_create_ring(float x, float y, float radius, float line_width) {
705 struct zint_render_ring *ring;
706
707 ring = (struct zint_render_ring *) malloc(sizeof (struct zint_render_ring));
708 if (!ring) return NULL;
709 ring->next = NULL;
710 ring->x = x;
711 ring->y = y;
712 ring->radius = radius;
713 ring->line_width = line_width;
714
715 return ring;
716 }
717
render_plot_add_ring(struct zint_symbol * symbol,struct zint_render_ring * ring,struct zint_render_ring ** last_ring)718 int render_plot_add_ring(struct zint_symbol *symbol, struct zint_render_ring *ring, struct zint_render_ring **last_ring) {
719 if (!ring) return ZINT_ERROR_MEMORY;
720 if (*last_ring)
721 (*last_ring)->next = ring;
722 else
723 symbol->rendered->rings = ring; // first ring
724
725 *last_ring = ring;
726 return 1;
727 }
728
render_plot_create_hexagon(float x,float y)729 struct zint_render_hexagon *render_plot_create_hexagon(float x, float y) {
730 struct zint_render_hexagon *hexagon;
731
732 hexagon = (struct zint_render_hexagon*) malloc(sizeof (struct zint_render_hexagon));
733 if (!hexagon) return NULL;
734 hexagon->next = NULL;
735 hexagon->x = x;
736 hexagon->y = y;
737
738 return hexagon;
739 }
740
render_plot_add_hexagon(struct zint_symbol * symbol,struct zint_render_hexagon * hexagon,struct zint_render_hexagon ** last_hexagon)741 int render_plot_add_hexagon(struct zint_symbol *symbol, struct zint_render_hexagon *hexagon, struct zint_render_hexagon **last_hexagon) {
742 if (!hexagon) return ZINT_ERROR_MEMORY;
743 if (*last_hexagon)
744 (*last_hexagon)->next = hexagon;
745 else
746 symbol->rendered->hexagons = hexagon; // first hexagon
747
748 *last_hexagon = hexagon;
749 return 1;
750 }
751
752 /*
753 * Add a string structure to the symbol.
754 * Coordinates assumed to be from top-center.
755 */
render_plot_add_string(struct zint_symbol * symbol,unsigned char * text,float x,float y,float fsize,float width,struct zint_render_string ** last_string)756 int render_plot_add_string(struct zint_symbol *symbol,
757 unsigned char *text, float x, float y, float fsize, float width,
758 struct zint_render_string **last_string) {
759 struct zint_render_string *string;
760
761 string = (struct zint_render_string*) malloc(sizeof (struct zint_render_string));
762 string->next = NULL;
763 string->x = x;
764 string->y = y;
765 string->width = width;
766 string->fsize = fsize;
767 string->length = ustrlen(text);
768 string->text = (unsigned char*) malloc(sizeof (unsigned char) * (ustrlen(text) + 1));
769 ustrcpy(string->text, text);
770
771 if (*last_string)
772 (*last_string)->next = string;
773 else
774 symbol->rendered->strings = string; // First character
775 *last_string = string;
776
777 return 1;
778 }
779