Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/dxfilmedge.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* dxfilmedge.c - Handles DX Film Edge symbology */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2024 Antoine Merino <antoine.merino.dev@gmail.com> | |
| 5 | |
| 6 Redistribution and use in source and binary forms, with or without | |
| 7 modification, are permitted provided that the following conditions | |
| 8 are met: | |
| 9 | |
| 10 1. Redistributions of source code must retain the above copyright | |
| 11 notice, this list of conditions and the following disclaimer. | |
| 12 2. Redistributions in binary form must reproduce the above copyright | |
| 13 notice, this list of conditions and the following disclaimer in the | |
| 14 documentation and/or other materials provided with the distribution. | |
| 15 3. Neither the name of the project nor the names of its contributors | |
| 16 may be used to endorse or promote products derived from this software | |
| 17 without specific prior written permission. | |
| 18 | |
| 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| 20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
| 23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 29 SUCH DAMAGE. | |
| 30 */ | |
| 31 /* SPDX-License-Identifier: BSD-3-Clause */ | |
| 32 | |
| 33 /* DX Film Edge Barcode is used on 35mm and APS films: | |
| 34 * https://en.wikipedia.org/wiki/DX_encoding | |
| 35 * | |
| 36 * A little information about decoding this symbology can be found at | |
| 37 * https://www.merinorus.com/blog/identifying-manufacturer-35-mm-films/ | |
| 38 * | |
| 39 * Partial specification and history can be found on this Kodak patent: | |
| 40 * https://patents.google.com/patent/US4965628A/en | |
| 41 */ | |
| 42 | |
| 43 #include <assert.h> | |
| 44 #include <stdio.h> | |
| 45 #include "common.h" | |
| 46 | |
| 47 #define DX_DEBUG_STR_LEN 20 | |
| 48 /* Max length of the DX info part. Include the \0. Eg: "018500\0", "150-10\0" */ | |
| 49 #define DX_MAX_DX_INFO_LENGTH 6 | |
| 50 #define DX_MAX_DX_INFO_MAX_STR "6" /* String version of above */ | |
| 51 /* Max length of the frame info part. Eg: "00A\0", "23A\0" */ | |
| 52 #define DX_MAX_FRAME_INFO_LENGTH 3 | |
| 53 #define DX_MAX_FRAME_INFO_MAX_STR "3" /* String version of above */ | |
| 54 | |
| 55 static void dx_int_to_binary(const int value, const int width, char *output) { | |
| 56 int i; | |
| 57 for (i = 0; i < width; i++) { | |
| 58 output[width - 1 - i] = (value & (1 << i)) ? '1' : '0'; | |
| 59 } | |
| 60 output[width] = '\0'; | |
| 61 } | |
| 62 | |
| 63 static int dx_parse_code(struct zint_symbol *symbol, const unsigned char *source, const int length, | |
| 64 char *binary_output, int *output_length, int *has_frame_info) { | |
| 65 int i; | |
| 66 int parity_bit = 0; | |
| 67 int dx_extract = -1, dx_code_1 = -1, dx_code_2 = -1, frame_number = -1; | |
| 68 char binary_dx_code_1[8], binary_dx_code_2[5], binary_frame_number[7]; | |
| 69 char half_frame_flag = '\0'; | |
| 70 char dx_info[DX_MAX_DX_INFO_LENGTH + 1] = "\0"; | |
| 71 char frame_info[DX_MAX_FRAME_INFO_LENGTH + 1] = "\0"; | |
| 72 int dx_length; | |
| 73 const char *frame_start; | |
| 74 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; | |
| 75 | |
| 76 *has_frame_info = 0; | |
| 77 | |
| 78 /* All codes should start with a digit*/ | |
| 79 if (!z_isdigit(source[0])) { | |
| 80 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 970, | |
| 81 "Invalid first character \"%c\", DX code should start with a number", source[0]); | |
| 82 } | |
| 83 | |
| 84 /* Check if there is the '/' separator, which indicates the frame number is present. */ | |
| 85 dx_length = posn((const char *) source, '/'); | |
| 86 if (dx_length != -1) { | |
| 87 /* Split the DX information from the frame number */ | |
| 88 int frame_info_len; | |
| 89 if (dx_length > DX_MAX_DX_INFO_LENGTH) { | |
| 90 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 971, | |
| 91 "DX information length %d too long (maximum " DX_MAX_DX_INFO_MAX_STR ")", dx_length); | |
| 92 } | |
| 93 ustrncat(dx_info, source, dx_length); | |
| 94 dx_info[dx_length] = '\0'; | |
| 95 frame_start = (const char *) source + dx_length + 1; | |
| 96 frame_info_len = (int) strlen(frame_start); | |
| 97 if (frame_info_len > DX_MAX_FRAME_INFO_LENGTH) { | |
| 98 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 972, | |
| 99 "Frame number part length %d too long (maximum " DX_MAX_FRAME_INFO_MAX_STR ")", frame_info_len); | |
| 100 } | |
| 101 ustrcpy(frame_info, frame_start); | |
| 102 *has_frame_info = 1; | |
| 103 to_upper((unsigned char *) frame_info, frame_info_len); | |
| 104 if (not_sane(IS_UPR_F | IS_NUM_F | IS_MNS_F, (const unsigned char *) frame_info, frame_info_len)) { | |
| 105 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 973, | |
| 106 "Frame number \"%s\" is invalid (expected digits, optionally followed by a single \"A\")", | |
| 107 frame_info); | |
| 108 } | |
| 109 } else { | |
| 110 /* No "/" found, store the entire input in dx_info */ | |
| 111 dx_length = length; | |
| 112 if (dx_length > DX_MAX_DX_INFO_LENGTH) { | |
| 113 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 974, | |
| 114 "DX information length %d too long (maximum " DX_MAX_DX_INFO_MAX_STR ")", dx_length); | |
| 115 } | |
| 116 ustrcpy(dx_info, source); | |
| 117 } | |
| 118 | |
| 119 if ((i = not_sane(IS_NUM_F | IS_MNS_F, (const unsigned char *) dx_info, dx_length))) { | |
| 120 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 975, | |
| 121 "Invalid character at position %d in DX info (digits and \"-\" character only)", i); | |
| 122 } | |
| 123 | |
| 124 if (debug_print) printf("\nDX info part: \"%s\", Frame info part: \"%s\"\n", dx_info, frame_info); | |
| 125 /* Parse the DX information */ | |
| 126 if (strchr(dx_info, '-')) { | |
| 127 /* DX code parts 1 and 2 are given directly, separated by a '-'. Eg: "79-7" */ | |
| 128 if (debug_print) printf("DX code 1 and 2 are separated by a dash \"-\"\n"); | |
| 129 if (chr_cnt((const unsigned char *) dx_info, dx_length, '-') > 1) { | |
| 130 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 976, | |
| 131 "The \"-\" is used to separate DX parts 1 and 2, and should be used no more than once"); | |
| 132 } | |
| 133 if (sscanf(dx_info, "%d-%d", &dx_code_1, &dx_code_2) < 2) { | |
| 134 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 977, | |
| 135 "Wrong format for DX parts 1 and 2 (expected format: XXX-XX, digits)"); | |
| 136 } | |
| 137 if (dx_code_1 <= 0 || dx_code_1 > 127) { | |
| 138 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 978, "DX part 1 \"%d\" out of range (1 to 127)", | |
| 139 dx_code_1); | |
| 140 } | |
| 141 if (dx_code_2 < 0 || dx_code_2 > 15) { | |
| 142 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 979, "DX part 2 \"%d\" out of range (0 to 15)", | |
| 143 dx_code_2); | |
| 144 } | |
| 145 } else { | |
| 146 /* DX format is either 4 digits (DX Extract, eg: 1271) or 6 digits (DX Full, eg: 012710) */ | |
| 147 if (debug_print) printf("No \"-\" separator, computing from DX Extract (4 digits) or DX Full (6 digits)\n"); | |
| 148 if (dx_length == 5 || dx_length > 6) { | |
| 149 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 980, | |
| 150 "DX number \"%s\" is incorrect; expected 4 digits (DX extract) or 6 digits (DX full)", dx_info); | |
| 151 } | |
| 152 if (dx_length == 6) { | |
| 153 if (debug_print) { | |
| 154 printf("DX full format detected: %s. Removing the first and the last characters.\n", dx_info); | |
| 155 } | |
| 156 /* Convert DX Full to DX Extract (remove first and last character) */ | |
| 157 for (i = 0; i <= 3; ++i) { | |
| 158 dx_info[i] = dx_info[i + 1]; | |
| 159 } | |
| 160 dx_info[4] = '\0'; | |
| 161 dx_length = 4; | |
| 162 } | |
| 163 /* Compute the DX parts 1 and 2 from the DX extract */ | |
| 164 dx_extract = to_int((const unsigned char *) dx_info, dx_length); | |
| 165 assert(dx_extract != -1); | |
| 166 if (dx_extract < 16 || dx_extract > 2047) { | |
| 167 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 981, "DX extract \"%d\" out of range (16 to 2047)", | |
| 168 dx_extract); | |
| 169 } | |
| 170 if (debug_print) printf("Computed DX extract: %04d\n", dx_extract); | |
| 171 dx_code_1 = dx_extract / 16; | |
| 172 dx_code_2 = dx_extract % 16; | |
| 173 } | |
| 174 | |
| 175 /* Convert components to binary strings */ | |
| 176 dx_int_to_binary(dx_code_1, 7, binary_dx_code_1); | |
| 177 dx_int_to_binary(dx_code_2, 4, binary_dx_code_2); | |
| 178 | |
| 179 if (debug_print) { | |
| 180 printf("%-*s%d\t-> %s\n", DX_DEBUG_STR_LEN, "DX code 1:", dx_code_1, binary_dx_code_1); | |
| 181 printf("%-*s%d\t-> %s\n", DX_DEBUG_STR_LEN, "DX code 2:", dx_code_2, binary_dx_code_2); | |
| 182 } | |
| 183 | |
| 184 if (*has_frame_info) { | |
| 185 int ret_sscanf, n; | |
| 186 if (strlen(frame_info) < 1) { | |
| 187 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 982, | |
| 188 "Frame number indicator \"/\" at position %d, but frame number is empty", | |
| 189 dx_length + 1); | |
| 190 } | |
| 191 /* Some frame numbers are special values, convert them their equivalent number */ | |
| 192 if (strcmp(frame_info, "S") == 0 || strcmp(frame_info, "X") == 0) { | |
| 193 strcpy(frame_info, "62"); | |
| 194 } else if (strcmp(frame_info, "SA") == 0 || strcmp(frame_info, "XA") == 0) { | |
| 195 strcpy(frame_info, "62A"); | |
| 196 } else if (strcmp(frame_info, "K") == 0 || strcmp(frame_info, "00") == 0) { | |
| 197 strcpy(frame_info, "63"); | |
| 198 } else if (strcmp(frame_info, "KA") == 0 || strcmp(frame_info, "00A") == 0) { | |
| 199 strcpy(frame_info, "63A"); | |
| 200 } else if (strcmp(frame_info, "F") == 0) { | |
| 201 strcpy(frame_info, "0"); | |
| 202 } else if (strcmp(frame_info, "FA") == 0) { | |
| 203 strcpy(frame_info, "0A"); | |
| 204 } | |
| 205 | |
| 206 ret_sscanf = sscanf(frame_info, "%d%c%n", &frame_number, &half_frame_flag, &n); | |
| 207 if (ret_sscanf < 1 || (ret_sscanf == 2 && frame_info[n] != '\0')) { | |
| 208 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 983, | |
| 209 "Frame number \"%s\" is invalid (expected digits, optionally followed by a single \"A\")", | |
| 210 frame_info); | |
| 211 } | |
| 212 if (frame_number < 0 || frame_number > 63) { | |
| 213 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 984, "Frame number \"%d\" out of range (0 to 63)", | |
| 214 frame_number); | |
| 215 } | |
| 216 dx_int_to_binary(frame_number, 6, binary_frame_number); | |
| 217 if (debug_print) { | |
| 218 printf("%-*s%d\t-> %s\n", DX_DEBUG_STR_LEN, "Frame number:", frame_number, binary_frame_number); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 /* Build the binary output */ | |
| 223 strcpy(binary_output, "101010"); /* Start pattern */ | |
| 224 strcat(binary_output, binary_dx_code_1); | |
| 225 strcat(binary_output, "0"); /* Separator between DX part 1 and DX part 2 */ | |
| 226 strcat(binary_output, binary_dx_code_2); | |
| 227 if (*has_frame_info) { | |
| 228 strcat(binary_output, binary_frame_number); | |
| 229 to_upper((unsigned char *) &half_frame_flag, 1); | |
| 230 if (half_frame_flag == 'A') { | |
| 231 if (debug_print) printf("%-*s'%c'\t-> 1\n", DX_DEBUG_STR_LEN, "Half frame flag:", half_frame_flag); | |
| 232 strcat(binary_output, "1"); /* Half-frame is set */ | |
| 233 } else { | |
| 234 if (half_frame_flag) { | |
| 235 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 985, | |
| 236 "Frame number \"%s\" is invalid (expected digits, optionally followed by a single \"A\")", | |
| 237 frame_info); | |
| 238 } | |
| 239 if (debug_print) printf("%-*s'%c'\t-> 0\n", DX_DEBUG_STR_LEN, "Half frame flag:", half_frame_flag); | |
| 240 strcat(binary_output, "0"); /* Half-frame is NOT set */ | |
| 241 } | |
| 242 strcat(binary_output, "0"); /* Separator between half frame flag and parity bit*/ | |
| 243 } | |
| 244 | |
| 245 /* Parity bit */ | |
| 246 for (i = 6; binary_output[i] != '\0'; i++) { | |
| 247 if (binary_output[i] == '1') { | |
| 248 parity_bit++; | |
| 249 } | |
| 250 } | |
| 251 parity_bit %= 2; | |
| 252 if (debug_print) { | |
| 253 printf("%-*s%s\t-> %d\n", DX_DEBUG_STR_LEN, "Parity bit:", parity_bit ? "yes" : "no", parity_bit); | |
| 254 } | |
| 255 if (parity_bit) { | |
| 256 strcat(binary_output, "1"); | |
| 257 } else { | |
| 258 strcat(binary_output, "0"); | |
| 259 } | |
| 260 | |
| 261 strcat(binary_output, "0101"); /* Stop pattern */ | |
| 262 | |
| 263 *output_length = (int) strlen(binary_output); | |
| 264 return 0; | |
| 265 } | |
| 266 | |
| 267 INTERNAL int dxfilmedge(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 268 int i; | |
| 269 int writer = 0; | |
| 270 int error_number = 0; | |
| 271 | |
| 272 char char_data[32]; | |
| 273 int data_length; | |
| 274 int has_frame_info; | |
| 275 | |
| 276 const char long_clock_pattern[] = "1111101010101010101010101010111"; | |
| 277 const char short_clock_pattern[] = "11111010101010101010111"; | |
| 278 const char *clock_pattern; | |
| 279 int clock_length; | |
| 280 int parse_result = -1; | |
| 281 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; | |
| 282 | |
| 283 if (length > 10) { | |
| 284 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 986, "Input length %d too long (maximum 10)", length); | |
| 285 } | |
| 286 | |
| 287 parse_result = dx_parse_code(symbol, source, length, char_data, &data_length, &has_frame_info); | |
| 288 if (parse_result != 0) { | |
| 289 if (debug_print) printf("Error %s\n\n", symbol->errtxt); | |
| 290 return parse_result; | |
| 291 } | |
| 292 | |
| 293 /* Clock signal is longer if the frame number is provided */ | |
| 294 if (has_frame_info) { | |
| 295 clock_pattern = long_clock_pattern; | |
| 296 clock_length = sizeof(long_clock_pattern) -1; | |
| 297 } else { | |
| 298 clock_pattern = short_clock_pattern; | |
| 299 clock_length = sizeof(short_clock_pattern) -1; | |
| 300 } | |
| 301 | |
| 302 /* First row: clock pattern */ | |
| 303 for (i = 0; i < clock_length; i++) { | |
| 304 if (clock_pattern[i] == '1') { | |
| 305 set_module(symbol, 0, writer); | |
| 306 } else if (clock_pattern[i] == '0') { | |
| 307 unset_module(symbol, 0, writer); | |
| 308 } | |
| 309 writer++; | |
| 310 } | |
| 311 | |
| 312 /* Reset writer X position for the second row */ | |
| 313 writer = 0; | |
| 314 | |
| 315 /* Second row: data signal */ | |
| 316 for (i = 0; i < clock_length; i++) { | |
| 317 if (char_data[i] == '1') { | |
| 318 set_module(symbol, 1, writer); | |
| 319 } else if (char_data[i] == '0') { | |
| 320 unset_module(symbol, 1, writer); | |
| 321 } | |
| 322 writer++; | |
| 323 } | |
| 324 symbol->rows = 2; | |
| 325 symbol->width = clock_length; | |
| 326 | |
| 327 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 328 /* Measured ratio on 35mm films. Depending on the brands, one symbol height is about 3 * the X-dim.*/ | |
| 329 const float default_height = 6.0f; | |
| 330 | |
| 331 /* AFAIK There is no standard on minimum and maximum height, so we stay close to the measurements */ | |
| 332 const float min_row_height = 2.2f; | |
| 333 const float max_height = 7.5f; | |
| 334 error_number = set_height(symbol, min_row_height, default_height, max_height, 0 /*no_errtxt*/); | |
| 335 } else { | |
| 336 /* Using compliant height as default as no backwards compatibility to consider */ | |
| 337 const float default_height = 6.0f; | |
| 338 (void) set_height(symbol, 0.0f, default_height, 0.0f, 1 /*no_errtxt*/); | |
| 339 } | |
| 340 | |
| 341 return error_number; | |
| 342 } | |
| 343 | |
| 344 /* vim: set ts=4 sw=4 et : */ |
