tif.c: Use palette/bilevel/LZW to reduce file size, alpha/CMYK support

This commit is contained in:
gitlost 2021-03-19 13:09:21 +00:00
parent badd9e59ad
commit 2c053c325a
33 changed files with 983 additions and 203 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -30,6 +30,7 @@
/* vim: set ts=4 sw=4 et : */
#include "testcommon.h"
#include <sys/stat.h>
INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf);
@ -68,24 +69,24 @@ static void test_pixel_plot(int index, int debug) {
/* 13*/ { 3, 3, "101010101", 0 },
/* 14*/ { 4, 3, "10", 1 },
/* 15*/ { 3, 4, "10", 1 },
/* 16*/ { 52, 51, "10", 1 }, // Strip Count 1, Rows Per Strip 51 (52 * 51 * 3 == 7956)
/* 17*/ { 52, 52, "10", 1 }, // Strip Count 1, Rows Per Strip 52 (52 * 52 * 3 == 8112)
/* 18*/ { 53, 52, "10", 1 }, // Strip Count 2, Rows Per Strip 51 (53 * 51 * 3 == 8109)
/* 19*/ { 53, 53, "10", 1 }, // Strip Count 2, Rows Per Strip 51
/* 20*/ { 2730, 1, "10", 1 }, // Strip Count 1, Rows Per Strip 1 (2730 * 1 * 3 == 8190)
/* 21*/ { 1, 2730, "10", 1 }, // Strip Count 1, Rows Per Strip 2730
/* 22*/ { 2730, 2, "10", 1 }, // Strip Count 2, Rows Per Strip 1
/* 23*/ { 2, 2730, "10", 1 }, // Strip Count 2, Rows Per Strip 1365 (2 * 1365 * 3 == 8190)
/* 24*/ { 2730, 3, "10", 1 }, // Strip Count 3, Rows Per Strip 1
/* 25*/ { 3, 2730, "10", 1 }, // Strip Count 3, Rows Per Strip 910 (3 * 910 * 3 == 8190)
/* 26*/ { 2731, 4, "10", 1 }, // Strip Count 4, Rows Per Strip 1 (2731 * 1 * 3 == 8193) - large rows in 1 strip, even if > 8192
/* 27*/ { 4, 2731, "10", 1 }, // Strip Count 5, Rows Per Strip 682 (4 * 682 * 3 == 8184)
/* 16*/ { 45, 44, "10", 1 }, // Strip Count 1, Rows Per Strip 44 (45 * 44 * 4 == 7920)
/* 17*/ { 45, 45, "10", 1 }, // Strip Count 1, Rows Per Strip 45 (45 * 45 * 4 == 8100)
/* 18*/ { 46, 45, "10", 1 }, // Strip Count 2, Rows Per Strip 44 (46 * 45 * 4 == 8280)
/* 19*/ { 46, 46, "10", 1 }, // Strip Count 2, Rows Per Strip 44
/* 20*/ { 2048, 1, "10", 1 }, // Strip Count 1, Rows Per Strip 1 (2048 * 4 == 8192)
/* 21*/ { 1, 2048, "10", 1 }, // Strip Count 1, Rows Per Strip 2048
/* 22*/ { 2048, 2, "10", 1 }, // Strip Count 2, Rows Per Strip 1
/* 23*/ { 2, 2048, "10", 1 }, // Strip Count 2, Rows Per Strip 1024 (2 * 1024 * 4 == 8192)
/* 24*/ { 2048, 3, "10", 1 }, // Strip Count 3, Rows Per Strip 1
/* 25*/ { 3, 2048, "10", 1 }, // Strip Count 4, Rows Per Strip 682 ((3 * 682 + 2) * 4 == 8192)
/* 26*/ { 2049, 4, "10", 1 }, // Strip Count 4, Rows Per Strip 1 (2049 * 1 * 4 == 8196) - large rows in 1 strip, even if > 8192
/* 27*/ { 4, 2049, "10", 1 }, // Strip Count 5, Rows Per Strip 512 ((4 * 512 + 1) * 4 == 8196)
};
int data_size = ARRAY_SIZE(data);
char *tif = "out.tif";
char data_buf[2731 * 4 + 1];
char data_buf[65536];
for (int i = 0; i < data_size; i++) {
@ -98,10 +99,11 @@ static void test_pixel_plot(int index, int debug) {
symbol->bitmap_width = data[i].width;
symbol->bitmap_height = data[i].height;
strcpy(symbol->bgcolour, "FFFFFFEE"); // Use alpha background to force RGB
symbol->debug |= debug;
int size = data[i].width * data[i].height;
assert_nonzero(size < (int) sizeof(data_buf), "i:%d tif_pixel_plot size %d < sizeof(data_buf) %d\n", i, size, (int) sizeof(data_buf));
assert_nonzero(size < (int) sizeof(data_buf), "i:%d tif_pixel_plot size %d >= sizeof(data_buf) %d\n", i, size, (int) sizeof(data_buf));
if (data[i].repeat) {
testUtilStrCpyRepeat(data_buf, data[i].pattern, size);
@ -130,10 +132,138 @@ static void test_pixel_plot(int index, int debug) {
testFinish();
}
static void test_print(int index, int generate, int debug) {
testStart("");
int have_identify = testUtilHaveIdentify();
int ret;
struct item {
int symbology;
int input_mode;
int border_width;
int output_options;
int whitespace_width;
int show_hrt;
int option_1;
int option_2;
int height;
float scale;
char *fgcolour;
char *bgcolour;
char *data;
char *composite;
char *expected_file;
char *comment;
};
struct item data[] = {
/* 0*/ { BARCODE_CODE128, -1, -1, -1, 1, -1, -1, -1, 0, 0, "112233", "EEDDCC", "A", "", "../data/tif/code128_fgbg.tif", "" },
/* 1*/ { BARCODE_CODE128, -1, -1, -1, 1, -1, -1, -1, 0, 0, "C00000", "FEDCBACC", "A", "", "../data/tif/code128_bgalpha.tif", "" },
/* 2*/ { BARCODE_CODE128, -1, -1, -1, 1, -1, -1, -1, 0, 0, "00000099", "FEDCBA", "A", "", "../data/tif/code128_fgalpha.tif", "" },
/* 3*/ { BARCODE_CODE128, -1, -1, -1, 1, -1, -1, -1, 0, 0, "00000099", "FEDCBACC", "A", "", "../data/tif/code128_fgbgalpha.tif", "" },
/* 4*/ { BARCODE_CODE128, -1, -1, CMYK_COLOUR, 1, -1, -1, -1, 0, 0, "C00000", "FEDCBA", "A", "", "../data/tif/code128_cmyk.tif", "" },
/* 5*/ { BARCODE_CODE128, -1, -1, CMYK_COLOUR, 1, -1, -1, -1, 0, 0, "C0000099", "FEDCBACC", "A", "", "../data/tif/code128_cmyk_fgbgalpha.tif", "" },
/* 6*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "C00000", "FEDCBACC", "1234", "", "../data/tif/ultra_bgalpha.tif", "" },
/* 7*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "000000BB", "FEDCBA", "1234", "", "../data/tif/ultra_fgalpha.tif", "" },
/* 8*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "000000BB", "FEDCBACC", "1234", "", "../data/tif/ultra_fgbgalpha.tif", "" },
/* 9*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "000000BB", "", "1234", "", "../data/tif/ultra_fgalpha_nobg.tif", "" },
/* 10*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "", "FEDCBACC", "1234", "", "../data/tif/ultra_bgalpha_nofg.tif", "" },
/* 11*/ { BARCODE_ULTRA, -1, -1, -1, -1, -1, -1, -1, 0, 0.5f, "", "", "1", "", "../data/tif/ultra_odd.tif", "" },
/* 12*/ { BARCODE_HANXIN, UNICODE_MODE, -1, -1, -1, -1, 4, 84, 0, 2, "", "", "1", "", "../data/tif/hanxin_v84_l4_scale2.tif", "" },
/* 13*/ { BARCODE_AZTEC, -1, -1, -1, -1, -1, -1, 32, 0, 0, "4BE055", "", "1", "", "../data/tif/aztec_v32_fg.tif", "" },
/* 14*/ { BARCODE_DAFT, -1, -1, -1, -1, -1, -1, -1, 1, 0.5f, "", "", "F", "", "../data/tif/daft_scale0.5.tif", "" },
};
int data_size = ARRAY_SIZE(data);
char *data_dir = "../data/tif";
char *tif = "out.tif";
char escaped[1024];
int escaped_size = 1024;
char *text;
if (generate) {
if (!testUtilExists(data_dir)) {
ret = mkdir(data_dir, 0755);
assert_zero(ret, "mkdir(%s) ret %d != 0\n", data_dir, ret);
}
}
for (int i = 0; i < data_size; i++) {
if (index != -1 && i != index) continue;
struct zint_symbol* symbol = ZBarcode_Create();
assert_nonnull(symbol, "Symbol not created\n");
int length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/, data[i].option_1, data[i].option_2, -1, data[i].output_options, data[i].data, -1, debug);
if (data[i].show_hrt != -1) {
symbol->show_hrt = data[i].show_hrt;
}
if (data[i].height) {
symbol->height = data[i].height;
}
if (data[i].scale) {
symbol->scale = data[i].scale;
}
if (data[i].border_width != -1) {
symbol->border_width = data[i].border_width;
}
if (data[i].whitespace_width != -1) {
symbol->whitespace_width = data[i].whitespace_width;
}
if (*data[i].fgcolour) {
strcpy(symbol->fgcolour, data[i].fgcolour);
}
if (*data[i].bgcolour) {
strcpy(symbol->bgcolour, data[i].bgcolour);
}
if (strlen(data[i].composite)) {
text = data[i].composite;
strcpy(symbol->primary, data[i].data);
} else {
text = data[i].data;
}
int text_length = strlen(text);
ret = ZBarcode_Encode(symbol, (unsigned char *) text, text_length);
assert_zero(ret, "i:%d %s ZBarcode_Encode ret %d != 0 %s\n", i, testUtilBarcodeName(data[i].symbology), ret, symbol->errtxt);
strcpy(symbol->outfile, tif);
ret = ZBarcode_Print(symbol, 0);
assert_zero(ret, "i:%d %s ZBarcode_Print %s ret %d != 0\n", i, testUtilBarcodeName(data[i].symbology), symbol->outfile, ret);
if (generate) {
printf(" /*%3d*/ { %s, %s, %d, %s, %d, %d, %d, %d, %d, %.5g, \"%s\",\"%s\", \"%s\", \"%s\", \"%s\", \"%s\" },\n",
i, testUtilBarcodeName(data[i].symbology), testUtilInputModeName(data[i].input_mode), data[i].border_width, testUtilOutputOptionsName(data[i].output_options),
data[i].whitespace_width, data[i].show_hrt, data[i].option_1, data[i].option_2, data[i].height, data[i].scale, data[i].fgcolour, data[i].bgcolour,
testUtilEscape(data[i].data, length, escaped, escaped_size), data[i].composite, data[i].expected_file, data[i].comment);
ret = rename(symbol->outfile, data[i].expected_file);
assert_zero(ret, "i:%d rename(%s, %s) ret %d != 0\n", i, symbol->outfile, data[i].expected_file, ret);
if (have_identify) {
ret = testUtilVerifyIdentify(data[i].expected_file, debug);
assert_zero(ret, "i:%d %s identify %s ret %d != 0\n", i, testUtilBarcodeName(data[i].symbology), data[i].expected_file, ret);
}
} else {
assert_nonzero(testUtilExists(symbol->outfile), "i:%d testUtilExists(%s) == 0\n", i, symbol->outfile);
assert_nonzero(testUtilExists(data[i].expected_file), "i:%d testUtilExists(%s) == 0\n", i, data[i].expected_file);
ret = testUtilCmpBins(symbol->outfile, data[i].expected_file);
assert_zero(ret, "i:%d %s testUtilCmpBins(%s, %s) %d != 0\n", i, testUtilBarcodeName(data[i].symbology), symbol->outfile, data[i].expected_file, ret);
assert_zero(remove(symbol->outfile), "i:%d remove(%s) != 0\n", i, symbol->outfile);
}
ZBarcode_Delete(symbol);
}
testFinish();
}
int main(int argc, char *argv[]) {
testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */
{ "test_pixel_plot", test_pixel_plot, 1, 0, 1 },
{ "test_print", test_print, 1, 1, 1 },
};
testRun(argc, argv, funcs, ARRAY_SIZE(funcs));

View File

@ -3,7 +3,7 @@
/*
libzint - the open source barcode library
Copyright (C) 2016 - 2020 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2016 - 2021 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@ -35,43 +35,238 @@
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <limits.h>
#include "common.h"
#include "tif.h"
#include "tif_lzw.h"
#ifdef _MSC_VER
#include <io.h>
#include <fcntl.h>
#include <malloc.h>
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
#include <endian.h>
# if __BYTE_ORDER == __BIG_ENDIAN
#define TIF_BIG_ENDIAN
#endif
#endif
/* PhotometricInterpretation */
#define TIF_PMI_WHITEISZERO 0
#define TIF_PMI_BLACKISZERO 1
#define TIF_PMI_RGB 2
#define TIF_PMI_PALETTE_COLOR 3
#define TIF_PMI_SEPARATED 5 /* CMYK */
/* Compression */
#define TIF_NO_COMPRESSION 1
#define TIF_LZW 5
static void to_color_map(unsigned char rgb[4], tiff_color_t *color_map_entry) {
color_map_entry->red = (rgb[0] << 8) | rgb[0];
color_map_entry->green = (rgb[1] << 8) | rgb[1];
color_map_entry->blue = (rgb[2] << 8) | rgb[2];
}
static void to_cmyk(unsigned char rgb[3], unsigned char alpha, unsigned char *cmyk) {
unsigned char max = rgb[0];
if (rgb[1] > max) {
max = rgb[1];
}
if (rgb[2] > max) {
max = rgb[2];
}
cmyk[0] = max - rgb[0];
cmyk[1] = max - rgb[1];
cmyk[2] = max - rgb[2];
cmyk[3] = 0xff - max;
cmyk[4] = alpha;
}
INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf) {
int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
unsigned char fg[4], bg[4];
int i;
int pmi; /* PhotometricInterpretation */
int rows_per_strip, strip_count;
unsigned int free_memory;
int rows_last_strip;
int bytes_per_strip;
uint16_t bits_per_sample;
int samples_per_pixel;
int pixels_per_sample;
unsigned char map[128];
tiff_color_t color_map[256] = {0};
unsigned char palette[32][5];
int color_map_size = 0;
int extra_samples = 0;
uint32_t free_memory;
int row, column, strip;
int strip_row;
unsigned int bytes_put;
long total_bytes_put;
FILE *tif_file;
unsigned char *pb;
int compression = TIF_NO_COMPRESSION;
tif_lzw_state lzw_state;
long file_pos;
#ifdef _MSC_VER
uint32_t* strip_offset;
uint32_t* strip_bytes;
unsigned char *strip_buf;
#endif
tiff_header_t header;
tiff_ifd_t ifd;
uint16_t temp;
uint16_t entries = 0;
tiff_tag_t tags[20];
uint32_t offset = 0;
int update_offsets[20];
int offsets = 0;
int ifd_size;
uint32_t temp32;
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]);
fg[0] = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]);
fg[1] = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]);
fg[2] = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]);
bg[0] = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]);
bg[1] = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]);
bg[2] = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]);
if (strlen(symbol->fgcolour) > 6) {
fg[3] = (16 * ctoi(symbol->fgcolour[6])) + ctoi(symbol->fgcolour[7]);
} else {
fg[3] = 0xff;
}
if (strlen(symbol->bgcolour) > 6) {
bg[3] = (16 * ctoi(symbol->bgcolour[6])) + ctoi(symbol->bgcolour[7]);
} else {
bg[3] = 0xff;
}
if (symbol->symbology == BARCODE_ULTRA) {
static const int ultra_chars[8] = { 'W', 'C', 'B', 'M', 'R', 'Y', 'G', 'K' };
static unsigned char ultra_rgbs[8][3] = {
{ 0xff, 0xff, 0xff, }, /* White */
{ 0, 0xff, 0xff, }, /* Cyan */
{ 0, 0, 0xff, }, /* Blue */
{ 0xff, 0, 0xff, }, /* Magenta */
{ 0xff, 0, 0, }, /* Red */
{ 0xff, 0xff, 0, }, /* Yellow */
{ 0, 0xff, 0, }, /* Green */
{ 0, 0, 0, }, /* Black */
};
if (symbol->output_options & CMYK_COLOUR) {
for (i = 0; i < 8; i++) {
map[ultra_chars[i]] = i;
to_cmyk(ultra_rgbs[i], fg[3], palette[i]);
}
map['0'] = 8;
to_cmyk(bg, bg[3], palette[8]);
map['1'] = 9;
to_cmyk(fg, fg[3], palette[9]);
pmi = TIF_PMI_SEPARATED;
bits_per_sample = 8;
if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */
samples_per_pixel = 4;
} else {
samples_per_pixel = 5;
extra_samples = 1; /* Associated alpha */
}
pixels_per_sample = 1;
} else {
for (i = 0; i < 8; i++) {
map[ultra_chars[i]] = i;
memcpy(palette[i], ultra_rgbs[i], 3);
palette[i][3] = fg[3];
}
map['0'] = 8;
memcpy(palette[8], bg, 4);
map['1'] = 9;
memcpy(palette[9], fg, 4);
if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */
pmi = TIF_PMI_PALETTE_COLOR;
for (i = 0; i < 10; i++) {
to_color_map(palette[i], &color_map[i]);
}
bits_per_sample = 4;
samples_per_pixel = 1;
pixels_per_sample = 2;
color_map_size = 16; /* 2**BitsPerSample */
} else {
pmi = TIF_PMI_RGB;
bits_per_sample = 8;
samples_per_pixel = 4;
pixels_per_sample = 1;
extra_samples = 1; /* Associated alpha */
}
}
} else { /* fg/bg only */
if (symbol->output_options & CMYK_COLOUR) {
map['0'] = 0;
to_cmyk(bg, bg[3], palette[0]);
map['1'] = 1;
to_cmyk(fg, fg[3], palette[1]);
pmi = TIF_PMI_SEPARATED;
bits_per_sample = 8;
if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */
samples_per_pixel = 4;
} else {
samples_per_pixel = 5;
extra_samples = 1; /* Associated alpha */
}
pixels_per_sample = 1;
} else if (bg[0] == 0xff && bg[1] == 0xff && bg[2] == 0xff && bg[3] == 0xff
&& fg[0] == 0 && fg[1] == 0 && fg[2] == 0 && fg[3] == 0xff) {
map['0'] = 0;
map['1'] = 1;
pmi = TIF_PMI_WHITEISZERO;
bits_per_sample = 1;
samples_per_pixel = 1;
pixels_per_sample = 8;
} else if (bg[0] == 0 && bg[1] == 0 && bg[2] == 0 && bg[3] == 0xff
&& fg[0] == 0xff && fg[1] == 0xff && fg[2] == 0xff && fg[3] == 0xff) {
map['0'] = 1;
map['1'] = 0;
pmi = TIF_PMI_BLACKISZERO;
bits_per_sample = 1;
samples_per_pixel = 1;
pixels_per_sample = 8;
} else {
map['0'] = 0;
memcpy(palette[0], bg, 4);
map['1'] = 1;
memcpy(palette[1], fg, 4);
pmi = TIF_PMI_PALETTE_COLOR;
for (i = 0; i < 2; i++) {
to_color_map(palette[i], &color_map[i]);
}
if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */
bits_per_sample = 4;
samples_per_pixel = 1;
pixels_per_sample = 2;
color_map_size = 16; /* 2**BitsPerSample */
} else {
bits_per_sample = 8;
samples_per_pixel = 2;
pixels_per_sample = 1;
color_map_size = 256; /* 2**BitsPerSample */
extra_samples = 1; /* Associated alpha */
}
}
}
/* TIFF Rev 6 Section 7 p.27 "Set RowsPerStrip such that the size of each strip is about 8K bytes...
* Note that extremely wide high resolution images may have rows larger than 8K bytes; in this case,
* RowsPerStrip should be 1, and the strip will be larger than 8K." */
rows_per_strip = 8192 / (symbol->bitmap_width * 3);
rows_per_strip = (8192 * pixels_per_sample) / (symbol->bitmap_width * samples_per_pixel);
if (rows_per_strip == 0) {
rows_per_strip = 1;
}
@ -79,43 +274,56 @@ INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf)
/* Suppresses clang-tidy clang-analyzer-core.VLASize warning */
assert(symbol->bitmap_height > 0);
if (rows_per_strip >= symbol->bitmap_height) {
strip_count = 1;
rows_per_strip = rows_last_strip = symbol->bitmap_height;
} else {
strip_count = symbol->bitmap_height / rows_per_strip;
if ((symbol->bitmap_height % rows_per_strip) != 0) {
rows_last_strip = symbol->bitmap_height % rows_per_strip;
if (rows_last_strip != 0) {
strip_count++;
}
if (rows_per_strip > symbol->bitmap_height) {
rows_per_strip = symbol->bitmap_height;
rows_per_strip = rows_last_strip = symbol->bitmap_height;
}
}
assert(strip_count > 0); /* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("TIFF (%dx%d) Strip Count %d, Rows Per Strip %d\n", symbol->bitmap_width, symbol->bitmap_height, strip_count, rows_per_strip);
printf("TIFF (%dx%d) Strip Count %d, Rows Per Strip %d\n", symbol->bitmap_width, symbol->bitmap_height,
strip_count, rows_per_strip);
}
bytes_per_strip = rows_per_strip * ((symbol->bitmap_width + pixels_per_sample - 1) / pixels_per_sample)
* samples_per_pixel;
#ifndef _MSC_VER
uint32_t strip_offset[strip_count];
uint32_t strip_bytes[strip_count];
unsigned char strip_buf[bytes_per_strip + 1];
#else
strip_offset = (uint32_t *) _alloca(strip_count * sizeof(uint32_t));
strip_bytes = (uint32_t *) _alloca(strip_count * sizeof(uint32_t));
strip_buf = (unsigned char *) _alloca(bytes_per_strip + 1);
#endif
free_memory = 8;
free_memory = sizeof(tiff_header_t);
for (i = 0; i < strip_count; i++) {
strip_offset[i] = free_memory;
if (i != (strip_count - 1)) {
strip_bytes[i] = rows_per_strip * symbol->bitmap_width * 3;
strip_bytes[i] = bytes_per_strip;
} else {
if ((symbol->bitmap_height % rows_per_strip) != 0) {
strip_bytes[i] = (symbol->bitmap_height % rows_per_strip) * symbol->bitmap_width * 3;
if (rows_last_strip) {
strip_bytes[i] = rows_last_strip * ((symbol->bitmap_width + pixels_per_sample - 1) / pixels_per_sample)
* samples_per_pixel;
} else {
strip_bytes[i] = rows_per_strip * symbol->bitmap_width * 3;
strip_bytes[i] = bytes_per_strip;
}
}
free_memory += strip_bytes[i];
if ((free_memory % 2) == 1) {
free_memory++;
}
if (free_memory & 1) {
free_memory++; // IFD must be on word boundary
}
if (free_memory > 0xffff0000) {
@ -133,184 +341,232 @@ INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf)
#endif
tif_file = stdout;
} else {
if (!(tif_file = fopen(symbol->outfile, "wb"))) {
if (!(tif_file = fopen(symbol->outfile, "wb+"))) {
strcpy(symbol->errtxt, "672: Can't open output file");
return ZINT_ERROR_FILE_ACCESS;
}
compression = TIF_LZW;
tif_lzw_init(&lzw_state);
}
/* Header */
header.byte_order = 0x4949;
#ifdef TIF_BIG_ENDIAN
header.byte_order = 0x4D4D; // "MM" big-endian
#else
header.byte_order = 0x4949; // "II" little-endian
#endif
header.identity = 42;
header.offset = free_memory;
fwrite(&header, sizeof(tiff_header_t), 1, tif_file);
free_memory += sizeof(tiff_ifd_t);
total_bytes_put = sizeof(tiff_header_t);
/* Pixel data */
pb = pixelbuf;
strip = 0;
strip_row = 0;
bytes_put = 0;
for (row = 0; row < symbol->bitmap_height; row++) {
for (column = 0; column < symbol->bitmap_width; column++) {
switch(pixelbuf[(row * symbol->bitmap_width) + column]) {
case 'W': // White
putc(255, tif_file);
putc(255, tif_file);
putc(255, tif_file);
break;
case 'C': // Cyan
putc(0, tif_file);
putc(255, tif_file);
putc(255, tif_file);
break;
case 'B': // Blue
putc(0, tif_file);
putc(0, tif_file);
putc(255, tif_file);
break;
case 'M': // Magenta
putc(255, tif_file);
putc(0, tif_file);
putc(255, tif_file);
break;
case 'R': // Red
putc(255, tif_file);
putc(0, tif_file);
putc(0, tif_file);
break;
case 'Y': // Yellow
putc(255, tif_file);
putc(255, tif_file);
putc(0, tif_file);
break;
case 'G': // Green
putc(0, tif_file);
putc(255, tif_file);
putc(0, tif_file);
break;
case 'K': // Black
putc(0, tif_file);
putc(0, tif_file);
putc(0, tif_file);
break;
case '1':
putc(fgred, tif_file);
putc(fggrn, tif_file);
putc(fgblu, tif_file);
break;
default:
putc(bgred, tif_file);
putc(bggrn, tif_file);
putc(bgblu, tif_file);
break;
if (samples_per_pixel == 1) {
if (bits_per_sample == 1) { /* WHITEISZERO or BLACKISZERO */
for (column = 0; column < symbol->bitmap_width; column += 8) {
unsigned char byte = 0;
for (i = 0; i < 8 && column + i < symbol->bitmap_width; i++, pb++) {
byte |= map[*pb] << (7 - i);
}
strip_buf[bytes_put++] = byte;
}
} else { /* bits_per_sample == 4, PALETTE_COLOR with no alpha */
for (column = 0; column < symbol->bitmap_width; column += 2) {
unsigned char byte = map[*pb++] << 4;
if (column + 1 < symbol->bitmap_width) {
byte |= map[*pb++];
}
strip_buf[bytes_put++] = byte;
}
}
} else if (samples_per_pixel == 2) { /* PALETTE_COLOR with alpha */
for (column = 0; column < symbol->bitmap_width; column++) {
int idx = map[*pb++];
strip_buf[bytes_put++] = idx;
strip_buf[bytes_put++] = palette[idx][3];
}
} else { /* samples_per_pixel >= 4, RGB with alpha (4) or CMYK with (5) or without (4) alpha */
for (column = 0; column < symbol->bitmap_width; column++) {
int idx = map[*pb++];
memcpy(&strip_buf[bytes_put], &palette[idx], samples_per_pixel);
bytes_put += samples_per_pixel;
}
bytes_put += 3;
}
if (strip < strip_count && (bytes_put + 3) >= strip_bytes[strip]) {
// End of strip, pad if strip length is odd
if (strip_bytes[strip] % 2 == 1) {
putc(0, tif_file);
strip_row++;
if (strip_row == rows_per_strip || (strip == strip_count - 1 && strip_row == rows_last_strip)) {
// End of strip
if (compression == TIF_LZW) {
file_pos = ftell(tif_file);
if (!tif_lzw_encode(&lzw_state, tif_file, strip_buf, bytes_put)) { /* Only fails if can't malloc */
tif_lzw_cleanup(&lzw_state);
fclose(tif_file); /* Only use LZW if not STDOUT, so ok to close */
strcpy(symbol->errtxt, "673: Failed to malloc LZW hash table");
return ZINT_ERROR_MEMORY;
}
bytes_put = ftell(tif_file) - file_pos;
if (bytes_put != strip_bytes[strip]) {
int diff = bytes_put - strip_bytes[strip];
strip_bytes[strip] = bytes_put;
for (i = strip + 1; i < strip_count; i++) {
strip_offset[i] += diff;
}
}
} else {
fwrite(strip_buf, 1, bytes_put, tif_file);
}
strip++;
total_bytes_put += bytes_put;
bytes_put = 0;
strip_row = 0;
/* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */
assert(strip < strip_count || row + 1 == symbol->bitmap_height);
}
}
if (total_bytes_put & 1) {
putc(0, tif_file); // IFD must be on word boundary
total_bytes_put++;
}
if (compression == TIF_LZW) {
tif_lzw_cleanup(&lzw_state);
file_pos = ftell(tif_file);
fseek(tif_file, 4, SEEK_SET);
free_memory = file_pos;
fwrite(&free_memory, 4, 1, tif_file);
fseek(tif_file, file_pos, SEEK_SET);
}
/* Image File Directory */
ifd.entries = 14;
ifd.offset = 0;
tags[entries].tag = 0x0100; // ImageWidth
tags[entries].type = 3; // SHORT
tags[entries].count = 1;
tags[entries++].offset = symbol->bitmap_width;
ifd.new_subset.tag = 0xfe;
ifd.new_subset.type = 4;
ifd.new_subset.count = 1;
ifd.new_subset.offset = 0;
tags[entries].tag = 0x0101; // ImageLength - number of rows
tags[entries].type = 3; // SHORT
tags[entries].count = 1;
tags[entries++].offset = symbol->bitmap_height;
ifd.image_width.tag = 0x0100;
ifd.image_width.type = 3; // SHORT
ifd.image_width.count = 1;
ifd.image_width.offset = symbol->bitmap_width;
ifd.image_length.tag = 0x0101;
ifd.image_length.type = 3; // SHORT
ifd.image_length.count = 1;
ifd.image_length.offset = symbol->bitmap_height;
ifd.bits_per_sample.tag = 0x0102;
ifd.bits_per_sample.type = 3; // SHORT
ifd.bits_per_sample.count = 3;
ifd.bits_per_sample.offset = free_memory;
free_memory += 6;
ifd.compression.tag = 0x0103;
ifd.compression.type = 3;
ifd.compression.count = 1;
ifd.compression.offset = 1; // Uncompressed
ifd.photometric.tag = 0x0106;
ifd.photometric.type = 3; // SHORT
ifd.photometric.count = 1;
ifd.photometric.offset = 2; // RGB Model
ifd.strip_offsets.tag = 0x0111;
ifd.strip_offsets.type = 4; // LONG
ifd.strip_offsets.count = strip_count;
if (strip_count == 1) {
ifd.strip_offsets.offset = strip_offset[0];
if (samples_per_pixel != 1 || bits_per_sample != 1) {
tags[entries].tag = 0x0102; // BitsPerSample
tags[entries].type = 3; // SHORT
tags[entries].count = samples_per_pixel;
if (samples_per_pixel == 1) {
tags[entries++].offset = bits_per_sample;
} else if (samples_per_pixel == 2) { /* 2 SHORTS fit into LONG offset so packed into offset */
tags[entries++].offset = (bits_per_sample << 16) | bits_per_sample;
} else {
ifd.strip_offsets.offset = free_memory;
update_offsets[offsets++] = entries;
tags[entries++].offset = free_memory;
free_memory += samples_per_pixel * 2;
}
}
tags[entries].tag = 0x0103; // Compression
tags[entries].type = 3; // SHORT
tags[entries].count = 1;
tags[entries++].offset = compression;
tags[entries].tag = 0x0106; // PhotometricInterpretation
tags[entries].type = 3; // SHORT
tags[entries].count = 1;
tags[entries++].offset = pmi;
tags[entries].tag = 0x0111; // StripOffsets
tags[entries].type = 4; // LONG
tags[entries].count = strip_count;
if (strip_count == 1) {
tags[entries++].offset = strip_offset[0];
} else {
update_offsets[offsets++] = entries;
tags[entries++].offset = free_memory;
free_memory += strip_count * 4;
}
ifd.samples_per_pixel.tag = 0x0115;
ifd.samples_per_pixel.type = 3;
ifd.samples_per_pixel.count = 1;
ifd.samples_per_pixel.offset = 3;
if (samples_per_pixel > 1) {
tags[entries].tag = 0x0115; // SamplesPerPixel
tags[entries].type = 3; // SHORT
tags[entries].count = 1;
tags[entries++].offset = samples_per_pixel;
}
ifd.rows_per_strip.tag = 0x0116;
ifd.rows_per_strip.type = 4;
ifd.rows_per_strip.count = 1;
ifd.rows_per_strip.offset = rows_per_strip;
tags[entries].tag = 0x0116; // RowsPerStrip
tags[entries].type = 4; // LONG
tags[entries].count = 1;
tags[entries++].offset = rows_per_strip;
ifd.strip_byte_counts.tag = 0x0117;
ifd.strip_byte_counts.type = 4;
ifd.strip_byte_counts.count = strip_count;
tags[entries].tag = 0x0117; // StripByteCounts
tags[entries].type = 4; // LONG
tags[entries].count = strip_count;
if (strip_count == 1) {
ifd.strip_byte_counts.offset = strip_bytes[0];
tags[entries++].offset = strip_bytes[0];
} else {
ifd.strip_byte_counts.offset = free_memory;
update_offsets[offsets++] = entries;
tags[entries++].offset = free_memory;
free_memory += strip_count * 4;
}
ifd.x_resolution.tag = 0x011a;
ifd.x_resolution.type = 5;
ifd.x_resolution.count = 1;
ifd.x_resolution.offset = free_memory;
tags[entries].tag = 0x011a; // XResolution
tags[entries].type = 5; // RATIONAL
tags[entries].count = 1;
update_offsets[offsets++] = entries;
tags[entries++].offset = free_memory;
free_memory += 8;
ifd.y_resolution.tag = 0x011b;
ifd.y_resolution.type = 5;
ifd.y_resolution.count = 1;
ifd.y_resolution.offset = free_memory;
// free_memory += 8;
tags[entries].tag = 0x011b; // YResolution
tags[entries].type = 5; // RATIONAL
tags[entries].count = 1;
update_offsets[offsets++] = entries;
tags[entries++].offset = free_memory;
free_memory += 8;
ifd.planar_config.tag = 0x11c;
ifd.planar_config.type = 3;
ifd.planar_config.count = 1;
ifd.planar_config.offset = 1;
tags[entries].tag = 0x0128; // ResolutionUnit
tags[entries].type = 3; // SHORT
tags[entries].count = 1;
tags[entries++].offset = 2; // Inches
ifd.resolution_unit.tag = 0x0128;
ifd.resolution_unit.type = 3;
ifd.resolution_unit.count = 1;
ifd.resolution_unit.offset = 2; // Inches
if (color_map_size) {
tags[entries].tag = 0x0140; // ColorMap
tags[entries].type = 3; // SHORT
tags[entries].count = color_map_size * 3;
update_offsets[offsets++] = entries;
tags[entries++].offset = free_memory;
//free_memory += color_map_size * 3 * 2; /* Unnecessary as long as last use */
}
fwrite(&ifd, sizeof(tiff_ifd_t), 1, tif_file);
if (extra_samples) {
tags[entries].tag = 0x0152; // ExtraSamples
tags[entries].type = 3; // SHORT
tags[entries].count = 1;
tags[entries++].offset = extra_samples;
}
/* Bits per sample */
temp = 8;
fwrite(&temp, 2, 1, tif_file); // Red Bytes
fwrite(&temp, 2, 1, tif_file); // Green Bytes
fwrite(&temp, 2, 1, tif_file); // Blue Bytes
ifd_size = sizeof(entries) + sizeof(tiff_tag_t) * entries + sizeof(offset);
for (i = 0; i < offsets; i++) {
tags[update_offsets[i]].offset += ifd_size;
}
fwrite(&entries, sizeof(entries), 1, tif_file);
fwrite(&tags, sizeof(tiff_tag_t), entries, tif_file);
fwrite(&offset, sizeof(offset), 1, tif_file);
total_bytes_put += ifd_size;
if (samples_per_pixel > 2) {
for (i = 0; i < samples_per_pixel; i++) {
fwrite(&bits_per_sample, sizeof(bits_per_sample), 1, tif_file);
}
total_bytes_put += sizeof(bits_per_sample) * samples_per_pixel;
}
if (strip_count != 1) {
/* Strip offsets */
@ -322,6 +578,7 @@ INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf)
for (i = 0; i < strip_count; i++) {
fwrite(&strip_bytes[i], 4, 1, tif_file);
}
total_bytes_put += strip_count * 8;
}
/* X Resolution */
@ -329,16 +586,36 @@ INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf)
fwrite(&temp32, 4, 1, tif_file);
temp32 = 1;
fwrite(&temp32, 4, 1, tif_file);
total_bytes_put += 8;
/* Y Resolution */
temp32 = 72;
fwrite(&temp32, 4, 1, tif_file);
temp32 = 1;
fwrite(&temp32, 4, 1, tif_file);
total_bytes_put += 8;
if (color_map_size) {
for (i = 0; i < color_map_size; i++) {
fwrite(&color_map[i].red, 2, 1, tif_file);
}
for (i = 0; i < color_map_size; i++) {
fwrite(&color_map[i].green, 2, 1, tif_file);
}
for (i = 0; i < color_map_size; i++) {
fwrite(&color_map[i].blue, 2, 1, tif_file);
}
total_bytes_put += 6 * color_map_size;
}
if (symbol->output_options & BARCODE_STDOUT) {
fflush(tif_file);
} else {
if (ftell(tif_file) != total_bytes_put) {
fclose(tif_file);
strcpy(symbol->errtxt, "674: Failed to write all output");
return ZINT_ERROR_FILE_WRITE;
}
fclose(tif_file);
}

View File

@ -2,7 +2,7 @@
/*
libzint - the open source barcode library
Copyright (C) 2016-2017 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2016-2021 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@ -29,6 +29,8 @@
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
/* vim: set ts=4 sw=4 et : */
#ifndef TIF_H
#define TIF_H
@ -58,24 +60,11 @@ extern "C" {
uint32_t offset;
} tiff_tag_t;
typedef struct tiff_ifd {
uint16_t entries;
tiff_tag_t new_subset;
tiff_tag_t image_width;
tiff_tag_t image_length;
tiff_tag_t bits_per_sample;
tiff_tag_t compression;
tiff_tag_t photometric;
tiff_tag_t strip_offsets;
tiff_tag_t samples_per_pixel;
tiff_tag_t rows_per_strip;
tiff_tag_t strip_byte_counts;
tiff_tag_t x_resolution;
tiff_tag_t y_resolution;
tiff_tag_t planar_config;
tiff_tag_t resolution_unit;
uint32_t offset;
} tiff_ifd_t;
typedef struct tiff_color {
uint16_t red;
uint16_t green;
uint16_t blue;
} tiff_color_t;
#pragma pack()
@ -84,5 +73,3 @@ extern "C" {
#endif
#endif /* TIF_H */

373
backend/tif_lzw.h Normal file
View File

@ -0,0 +1,373 @@
/* tif_lzw.h - LZW compression for TIFF
libzint - the open source barcode library
Copyright (C) 2021 Robin Stuart <rstuart114@gmail.com>
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.
*/
/* vim: set ts=4 sw=4 et : */
#ifndef TIF_LZW_H
#define TIF_LZW_H
/*
* Adapted from TIFF Library 4.2.0 libtiff/tif_lzw.c */
/*
* Copyright (c) 1988-1997 Sam Leffler
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that (i) the above copyright notices and this permission notice appear in
* all copies of the software and related documentation, and (ii) the names of
* Sam Leffler and Silicon Graphics may not be used in any advertising or
* publicity relating to the software without the specific, prior written
* permission of Sam Leffler and Silicon Graphics.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/*
* TIFF Library.
* Rev 5.0 Lempel-Ziv & Welch Compression Support
*
* This code is derived from the compress program whose code is
* derived from software contributed to Berkeley by James A. Woods,
* derived from original work by Spencer Thomas and Joseph Orost.
*
* The original Berkeley copyright notice appears below in its entirety.
*/
/*
* Copyright (c) 1985, 1986 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* James A. Woods, derived from original work by Spencer Thomas
* and Joseph Orost.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#define MAXCODE(n) ((1L << (n)) - 1)
/*
* The TIFF spec specifies that encoded bit
* strings range from 9 to 12 bits.
*/
#define BITS_MIN 9 /* start with 9 bits */
#define BITS_MAX 12 /* max of 12 bit strings */
/* predefined codes */
#define CODE_CLEAR 256 /* code to clear string table */
#define CODE_EOI 257 /* end-of-information code */
#define CODE_FIRST 258 /* first free code entry */
#define CODE_MAX MAXCODE(BITS_MAX)
#define HSIZE 9001L /* 91% occupancy */
#define HSHIFT (13 - 8)
/*
* Encoding-specific state.
*/
typedef uint16_t tif_lzw_hcode; /* codes fit in 16 bits */
typedef struct {
long hash;
tif_lzw_hcode code;
} tif_lzw_hash;
#define CHECK_GAP 10000 /* ratio check interval */
/*
* State block.
*/
typedef struct {
tif_lzw_hash *enc_hashtab; /* kept separate for small machines */
} tif_lzw_state;
/*
* LZW Encoding.
*/
/*
* Reset encoding hash table.
*/
static void tif_lzw_cl_hash(tif_lzw_state *sp) {
register tif_lzw_hash *hp = &sp->enc_hashtab[HSIZE - 1];
register long i = HSIZE - 8;
do {
i -= 8;
hp[-7].hash = -1;
hp[-6].hash = -1;
hp[-5].hash = -1;
hp[-4].hash = -1;
hp[-3].hash = -1;
hp[-2].hash = -1;
hp[-1].hash = -1;
hp[ 0].hash = -1;
hp -= 8;
} while (i >= 0);
for (i += 8; i > 0; i--, hp--) {
hp->hash = -1;
}
}
#define CALCRATIO(sp, rat) { \
if (incount > 0x007fffff) { /* NB: shift will overflow */ \
rat = outcount >> 8; \
rat = (rat == 0 ? 0x7fffffff : incount / rat); \
} else \
rat = (incount << 8) / outcount; \
}
/* Explicit 0xff masking to make icc -check=conversions happy */
#define PutNextCode(op_file, c) { \
nextdata = (nextdata << nbits) | c; \
nextbits += nbits; \
putc((nextdata >> (nextbits - 8)) & 0xff, op_file); \
nextbits -= 8; \
if (nextbits >= 8) { \
putc((nextdata >> (nextbits - 8)) & 0xff, op_file); \
nextbits -= 8; \
} \
outcount += nbits; \
}
/*
* Encode a chunk of pixels.
*
* Uses an open addressing double hashing (no chaining) on the
* prefix code/next character combination. We do a variant of
* Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's
* relatively-prime secondary probe. Here, the modular division
* first probe is gives way to a faster exclusive-or manipulation.
* Also do block compression with an adaptive reset, whereby the
* code table is cleared when the compression ratio decreases,
* but after the table fills. The variable-length output codes
* are re-sized at this point, and a CODE_CLEAR is generated
* for the decoder.
*/
static int tif_lzw_encode(tif_lzw_state *sp, FILE *op_file, const unsigned char *bp, int cc) {
register long fcode;
register tif_lzw_hash *hp;
register int h, c;
tif_lzw_hcode ent;
long disp;
int nbits; /* # of bits/code */
int maxcode; /* maximum code for nbits */
int free_ent; /* next free entry in hash table */
unsigned long nextdata; /* next bits of i/o */
long nextbits; /* # of valid bits in nextdata */
long checkpoint; /* point at which to clear table */
long ratio; /* current compression ratio */
long incount; /* (input) data bytes encoded */
long outcount; /* encoded (output) bytes */
/*
* Reset encoding state at the start of a strip.
*/
if (sp->enc_hashtab == NULL) {
sp->enc_hashtab = (tif_lzw_hash *) malloc(HSIZE * sizeof(tif_lzw_hash));
if (sp->enc_hashtab == NULL) {
return 0;
}
}
tif_lzw_cl_hash(sp); /* clear hash table */
nbits = BITS_MIN;
maxcode = MAXCODE(BITS_MIN);
free_ent = CODE_FIRST;
nextdata = 0;
nextbits = 0;
checkpoint = CHECK_GAP;
ratio = 0;
incount = 0;
outcount = 0;
ent = (tif_lzw_hcode) -1;
if (cc > 0) {
PutNextCode(op_file, CODE_CLEAR);
ent = *bp++; cc--; incount++;
}
while (cc > 0) {
c = *bp++; cc--; incount++;
fcode = ((long)c << BITS_MAX) + ent;
h = (c << HSHIFT) ^ ent; /* xor hashing */
#ifdef _WINDOWS
/*
* Check hash index for an overflow.
*/
if (h >= HSIZE) {
h -= HSIZE;
}
#endif
hp = &sp->enc_hashtab[h];
if (hp->hash == fcode) {
ent = hp->code;
continue;
}
if (hp->hash >= 0) {
/*
* Primary hash failed, check secondary hash.
*/
disp = HSIZE - h;
if (h == 0) {
disp = 1;
}
do {
/*
* Avoid pointer arithmetic because of
* wraparound problems with segments.
*/
if ((h -= disp) < 0) {
h += HSIZE;
}
hp = &sp->enc_hashtab[h];
if (hp->hash == fcode) {
ent = hp->code;
goto hit;
}
} while (hp->hash >= 0);
}
/*
* New entry, emit code and add to table.
*/
PutNextCode(op_file, ent);
ent = (tif_lzw_hcode) c;
hp->code = (tif_lzw_hcode) (free_ent++);
hp->hash = fcode;
if (free_ent == CODE_MAX - 1) {
/* table is full, emit clear code and reset */
tif_lzw_cl_hash(sp);
ratio = 0;
incount = 0;
outcount = 0;
free_ent = CODE_FIRST;
PutNextCode(op_file, CODE_CLEAR);
nbits = BITS_MIN;
maxcode = MAXCODE(BITS_MIN);
} else {
/*
* If the next entry is going to be too big for
* the code size, then increase it, if possible.
*/
if (free_ent > maxcode) {
nbits++;
assert(nbits <= BITS_MAX);
maxcode = (int) MAXCODE(nbits);
} else if (incount >= checkpoint) {
long rat;
/*
* Check compression ratio and, if things seem
* to be slipping, clear the hash table and
* reset state. The compression ratio is a
* 24+8-bit fractional number.
*/
checkpoint = incount + CHECK_GAP;
CALCRATIO(sp, rat);
if (rat <= ratio) {
tif_lzw_cl_hash(sp);
ratio = 0;
incount = 0;
outcount = 0;
free_ent = CODE_FIRST;
PutNextCode(op_file, CODE_CLEAR);
nbits = BITS_MIN;
maxcode = MAXCODE(BITS_MIN);
} else {
ratio = rat;
}
}
}
hit:
;
}
/*
* Finish off an encoded strip by flushing the last
* string and tacking on an End Of Information code.
*/
if (ent != (tif_lzw_hcode) -1) {
PutNextCode(op_file, ent);
free_ent++;
if (free_ent == CODE_MAX - 1) {
/* table is full, emit clear code and reset */
outcount = 0;
PutNextCode(op_file, CODE_CLEAR);
nbits = BITS_MIN;
} else {
/*
* If the next entry is going to be too big for
* the code size, then increase it, if possible.
*/
if (free_ent > maxcode) {
nbits++;
assert(nbits <= BITS_MAX);
}
}
}
PutNextCode(op_file, CODE_EOI);
/* Explicit 0xff masking to make icc -check=conversions happy */
if (nextbits > 0) {
putc((nextdata << (8 - nextbits)) & 0xff, op_file);
}
return 1;
}
static void tif_lzw_cleanup(tif_lzw_state *sp) {
if (sp->enc_hashtab) {
free(sp->enc_hashtab);
}
}
static void tif_lzw_init(tif_lzw_state *sp) {
sp->enc_hashtab = NULL;
}
#endif /* TIF_LZW_H */

View File

@ -275,6 +275,7 @@ extern "C" {
#define ZINT_ERROR_ENCODING_PROBLEM 9
#define ZINT_ERROR_FILE_ACCESS 10
#define ZINT_ERROR_MEMORY 11
#define ZINT_ERROR_FILE_WRITE 12
// File types
#define OUT_BUFFER 0

View File

@ -1037,6 +1037,9 @@ ZINT_ERROR_FILE_ACCESS | Zint was unable to open the requested output
| problem.
ZINT_ERROR_MEMORY | Zint ran out of memory. This should only be a
| problem with legacy systems.
ZINT_ERROR_FILE_WRITE | Zint failed to write all contents to the
| requested output file. This should only occur
| if the output disk becomes full.
--------------------------------------------------------------------------------
To catch errors use an integer variable as shown in the code below:

View File

@ -53,6 +53,7 @@ HEADERS += barcodeitem.h \
..\backend\sjis.h \
..\backend\stdint_msvc.h \
..\backend\tif.h \
..\backend\tif_lzw.h \
..\backend\zint.h \
..\backend\zintconfig.h \

View File

@ -936,10 +936,10 @@ p, li { white-space: pre-wrap; }
<item row="3" column="3">
<widget class="QCheckBox" name="chkCMYK">
<property name="toolTip">
<string>Use CMYK colour space in EPS output</string>
<string>Use CMYK colour space in EPS/TIF output</string>
</property>
<property name="text">
<string>CMY&amp;K (EPS)</string>
<string>CMY&amp;K (EPS/TIF)</string>
</property>
<property name="checked">
<bool>false</bool>

View File

@ -210,6 +210,7 @@
<ClInclude Include="..\backend\sjis.h" />
<ClInclude Include="..\backend\stdint_msvc.h" />
<ClInclude Include="..\backend\tif.h" />
<ClInclude Include="..\backend\tif_lzw.h" />
<ClInclude Include="..\backend\zint.h" />
<ClInclude Include="..\backend\zintconfig.h" />
</ItemGroup>

View File

@ -617,6 +617,10 @@
RelativePath="..\backend\tif.h"
>
</File>
<File
RelativePath="..\backend\tif_lzw.h"
>
</File>
<File
RelativePath="..\backend\zint.h"
>

View File

@ -389,6 +389,7 @@
<ClInclude Include="..\..\backend\sjis.h" />
<ClInclude Include="..\..\backend\stdint_msvc.h" />
<ClInclude Include="..\..\backend\tif.h" />
<ClInclude Include="..\..\backend\tif_lzw.h" />
<ClInclude Include="..\..\backend\zint.h" />
<ClInclude Include="..\..\backend\zintconfig.h" />
</ItemGroup>

View File

@ -157,6 +157,7 @@
<ClInclude Include="..\..\backend\sjis.h" />
<ClInclude Include="..\..\backend\stdint_msvc.h" />
<ClInclude Include="..\..\backend\tif.h" />
<ClInclude Include="..\..\backend\tif_lzw.h" />
<ClInclude Include="..\..\backend\zint.h" />
<ClInclude Include="..\..\backend\zintconfig.h" />
</ItemGroup>

View File

@ -210,6 +210,7 @@
<ClInclude Include="..\..\backend\sjis.h" />
<ClInclude Include="..\..\backend\stdint_msvc.h" />
<ClInclude Include="..\..\backend\tif.h" />
<ClInclude Include="..\..\backend\tif_lzw.h" />
<ClInclude Include="..\..\backend\zint.h" />
<ClInclude Include="..\..\backend\zintconfig.h" />
</ItemGroup>