diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index 67beb4bf..191d50bf 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -8,7 +8,7 @@ set(zint_COMMON_SRCS common.c library.c render.c large.c reedsol.c gs1.c) set(zint_ONEDIM_SRCS code.c code128.c 2of5.c upcean.c telepen.c medical.c plessey.c rss.c) set(zint_POSTAL_SRCS postal.c auspost.c imail.c) set(zint_TWODIM_SRCS code16k.c dmatrix.c pdf417.c qr.c maxicode.c composite.c aztec.c code49.c code1.c gridmtx.c hanxin.c) -set(zint_OUTPUT_SRCS render.c ps.c svg.c bmp.c png.c raster.c) +set(zint_OUTPUT_SRCS render.c ps.c svg.c bmp.c pcx.c png.c raster.c) set(zint_SRCS ${zint_OUTPUT_SRCS} ${zint_COMMON_SRCS} ${zint_ONEDIM_SRCS} ${zint_POSTAL_SRCS} ${zint_TWODIM_SRCS}) if(PNG_FOUND) diff --git a/backend/library.c b/backend/library.c index e038e107..0a5e3634 100644 --- a/backend/library.c +++ b/backend/library.c @@ -949,6 +949,12 @@ int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) { symbol->text[0] = '\0'; } error_number = plot_raster(symbol, rotate_angle, OUT_BMP_FILE); + } else + if (!(strcmp(output, "PCX"))) { + if (symbol->scale < 1.0) { + symbol->text[0] = '\0'; + } + error_number = plot_raster(symbol, rotate_angle, OUT_PCX_FILE); } else if (!(strcmp(output, "TXT"))) { error_number = dump_plot(symbol); diff --git a/backend/pcx.c b/backend/pcx.c new file mode 100644 index 00000000..1f9d949d --- /dev/null +++ b/backend/pcx.c @@ -0,0 +1,255 @@ +/* pcx.c - Handles output to ZSoft PCX file */ + +/* + libzint - the open source barcode library + Copyright (C) 2009-2016 Robin Stuart + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ + +#include +#include +#include +#include "common.h" +#include "pcx.h" /* PCX header structure */ +#include + +#define SSET "0123456789ABCDEF" + +int pcx_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle) { + int fgred, fggrn, fgblu, bgred, bggrn, bgblu; + int errno; + int row, column, i; + int run_count, sub_block; + char pixel_colour; + FILE *pcx_file; + +#ifndef _MSC_VER + char rotated_bitmap[image_height * image_width]; +#else + char* rotated_bitmap = (char *) _alloca((image_height * image_width) * sizeof(char)); +#endif /* _MSC_VER */ + + switch (rotate_angle) { + case 0: + case 180: + symbol->bitmap_width = image_width; + symbol->bitmap_height = image_height; + break; + case 90: + case 270: + symbol->bitmap_width = image_height; + symbol->bitmap_height = image_width; + break; + } + +#ifndef _MSC_VER + unsigned char rle_row[symbol->bitmap_width * 6]; +#else + unsignd char* rle_row = (unsigned char *) _alloca((symbol->bitmap_width * 6) * sizeof(unsigned char)); +#endif /* _MSC_VER */ + + /* sort out colour options */ + to_upper((unsigned char*) symbol->fgcolour); + to_upper((unsigned char*) symbol->bgcolour); + + if (strlen(symbol->fgcolour) != 6) { + strcpy(symbol->errtxt, "Malformed foreground colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + if (strlen(symbol->bgcolour) != 6) { + strcpy(symbol->errtxt, "Malformed background colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + errno = is_sane(SSET, (unsigned char*) symbol->fgcolour, strlen(symbol->fgcolour)); + if (errno == ZINT_ERROR_INVALID_DATA) { + strcpy(symbol->errtxt, "Malformed foreground colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + errno = is_sane(SSET, (unsigned char*) symbol->bgcolour, strlen(symbol->fgcolour)); + if (errno == ZINT_ERROR_INVALID_DATA) { + strcpy(symbol->errtxt, "Malformed background colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + + fgred = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); + fggrn = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); + fgblu = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]); + bgred = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]); + bggrn = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]); + bgblu = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]); + + /* Rotate image before plotting */ + switch (rotate_angle) { + case 0: /* Plot the right way up */ + for (row = 0; row < image_height; row++) { + for (column = 0; column < image_width; column++) { + rotated_bitmap[(row * image_width) + column] = + *(pixelbuf + (image_width * row) + column); + } + } + break; + case 90: /* Plot 90 degrees clockwise */ + for (row = 0; row < image_width; row++) { + for (column = 0; column < image_height; column++) { + rotated_bitmap[(row * image_width) + column] = + *(pixelbuf + (image_width * (image_height - column - 1)) + row); + } + } + break; + case 180: /* Plot upside down */ + for (row = 0; row < image_height; row++) { + for (column = 0; column < image_width; column++) { + rotated_bitmap[(row * image_width) + column] = + *(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1)); + } + } + break; + case 270: /* Plot 90 degrees anti-clockwise */ + for (row = 0; row < image_width; row++) { + for (column = 0; column < image_height; column++) { + rotated_bitmap[(row * image_width) + column] = + *(pixelbuf + (image_width * column) + (image_width - row - 1)); + } + } + break; + } + + pcx_header_t header; + + header.manufacturer = 10; // ZSoft + header.version = 5; // Version 3.0 + header.encoding = 1; // Run length encoding + header.bits_per_pixel = 8; + header.window_xmin = 0; + header.window_ymin = 0; + header.window_xmax = symbol->bitmap_width - 1; + header.window_ymax = symbol->bitmap_height - 1; + header.horiz_dpi = 300; + header.vert_dpi = 300; + + for(i = 0; i < 48; i++) { + header.colourmap[i] = 0x00; + } + + header.reserved = 0; + header.number_of_planes = 3; + + if (symbol->bitmap_width % 2) { + header.bytes_per_line = symbol->bitmap_width + 1; + } else { + header.bytes_per_line = symbol->bitmap_width; + } + + header.palette_info = 1; // Colour + header.horiz_screen_size = 0; + header.vert_screen_size = 0; + + for(i = 0; i < 54; i++) { + header.filler[i] = 0x00; + } + + /* Open output file in binary mode */ + if ((symbol->output_options & BARCODE_STDOUT) != 0) { +#ifdef _MSC_VER + if (-1 == _setmode(_fileno(stdout), _O_BINARY)) { + strcpy(symbol->errtxt, "Can't open output file"); + return ZINT_ERROR_FILE_ACCESS; + } +#endif + pcx_file = stdout; + } else { + if (!(pcx_file = fopen(symbol->outfile, "wb"))) { + strcpy(symbol->errtxt, "Can't open output file"); + return ZINT_ERROR_FILE_ACCESS; + } + } + + fwrite(&header, sizeof(pcx_header_t), 1, pcx_file); + + for(row = 0; row < symbol->bitmap_height; row++) { + run_count = 1; + sub_block = 0; + for(column = 1; column < symbol->bitmap_width; column++) { + if ((rotated_bitmap[(row * image_width) + column - 1] + == rotated_bitmap[(row * image_width) + column]) + && (run_count < 63)) { + run_count++; + } else { + pixel_colour = rotated_bitmap[(row * image_width) + column - 1]; + rle_row[(sub_block * 2)] = run_count + 0xc0; + rle_row[(sub_block * 2) + (2 * symbol->bitmap_width)] = run_count + 0xc0; + rle_row[(sub_block * 2) + (4 * symbol->bitmap_width)] = run_count + 0xc0; + if (pixel_colour == '1') { + rle_row[(sub_block * 2) + 1] = fgred; + rle_row[(sub_block * 2) + (2 * symbol->bitmap_width) + 1] = fggrn; + rle_row[(sub_block * 2) + (4 * symbol->bitmap_width) + 1] = fgblu; + } else { + rle_row[(sub_block * 2) + 1] = bgred; + rle_row[(sub_block * 2) + (2 * symbol->bitmap_width) + 1] = bggrn; + rle_row[(sub_block * 2) + (4 * symbol->bitmap_width) + 1] = bgblu; + } + sub_block++; + run_count = 1; + } + + } + + if (run_count > 1) { + pixel_colour = rotated_bitmap[(row * image_width) + column - 1]; + rle_row[(sub_block * 2)] = run_count + 0xc0; + rle_row[(sub_block * 2) + (2 * symbol->bitmap_width)] = run_count + 0xc0; + rle_row[(sub_block * 2) + (4 * symbol->bitmap_width)] = run_count + 0xc0; + if (pixel_colour == '1') { + rle_row[(sub_block * 2) + 1] = fgred; + rle_row[(sub_block * 2) + (2 * symbol->bitmap_width) + 1] = fggrn; + rle_row[(sub_block * 2) + (4 * symbol->bitmap_width) + 1] = fgblu; + } else { + rle_row[(sub_block * 2) + 1] = bgred; + rle_row[(sub_block * 2) + (2 * symbol->bitmap_width) + 1] = bggrn; + rle_row[(sub_block * 2) + (4 * symbol->bitmap_width) + 1] = bgblu; + } + sub_block++; + } + + for (i = 0; i < (sub_block * 2); i++) { + fputc(rle_row[i], pcx_file); + } + + for (i = 0; i < (sub_block * 2); i++) { + fputc(rle_row[i + (2 * symbol->bitmap_width)], pcx_file); + } + + for (i = 0; i < (sub_block * 2); i++) { + fputc(rle_row[i + (4 * symbol->bitmap_width)], pcx_file); + } + + } + + fclose(pcx_file); + + return 0; +} \ No newline at end of file diff --git a/backend/pcx.h b/backend/pcx.h new file mode 100644 index 00000000..3d816d3d --- /dev/null +++ b/backend/pcx.h @@ -0,0 +1,67 @@ +/* pcx.h - header structure for ZSoft PCX files + + libzint - the open source barcode library + Copyright (C) 2016 Robin Stuart + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ + +#ifndef PCX_H +#define PCX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + + typedef struct pcx_header { + uint8_t manufacturer; + uint8_t version; + uint8_t encoding; + uint8_t bits_per_pixel; + uint16_t window_xmin; + uint16_t window_ymin; + uint16_t window_xmax; + uint16_t window_ymax; + uint16_t horiz_dpi; + uint16_t vert_dpi; + uint8_t colourmap[48]; + uint8_t reserved; + uint8_t number_of_planes; + uint16_t bytes_per_line; + uint16_t palette_info; + uint16_t horiz_screen_size; + uint16_t vert_screen_size; + uint8_t filler[54]; + } __attribute__((__packed__ )) pcx_header_t; + +#ifdef __cplusplus +} +#endif + +#endif /* PCX_H */ + diff --git a/backend/raster.c b/backend/raster.c index ba7a2017..4da49b10 100644 --- a/backend/raster.c +++ b/backend/raster.c @@ -50,7 +50,7 @@ extern int png_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle); #endif /* NO_PNG */ extern int bmp_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle); - +extern int pcx_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle); int save_raster_image_to_file(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle, int image_type) { int error_number; @@ -81,14 +81,20 @@ int save_raster_image_to_file(struct zint_symbol *symbol, int image_height, int } } - if (image_type == OUT_PNG_FILE) { + switch(image_type) { + case OUT_PNG_FILE: #ifndef NO_PNG - error_number = png_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); + error_number = png_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); #else - return ZINT_ERROR_INVALID_OPTION; + return ZINT_ERROR_INVALID_OPTION; #endif - } else { - error_number = bmp_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); + break; + case OUT_PCX_FILE: + error_number = pcx_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); + break; + default: + error_number = bmp_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); + break; } free(scaled_pixelbuf); diff --git a/backend/zint.h b/backend/zint.h index ccae4196..a129b805 100644 --- a/backend/zint.h +++ b/backend/zint.h @@ -228,6 +228,8 @@ extern "C" { // Raster file types #define OUT_PNG_FILE 100 #define OUT_BMP_FILE 120 +#define OUT_GIF_FILE 140 +#define OUT_PCX_FILE 160 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(_MSC_VER) #if defined (DLL_EXPORT) || defined(PIC) || defined(_USRDLL)