📄 dmtxencode.c
字号:
/*libdmtx - Data Matrix Encoding/Decoding LibraryCopyright (c) 2008 Mike LaughtonThis library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAContact: mike@dragonflylogic.com*//* $Id: dmtxencode.c 514 2008-11-19 17:10:44Z mblaughton $ *//** * @file dmtxencode.c * @brief Encode messages *//* TODO rewrite this logic to use a push/stack approach. Do not track mid- byte progress. Encode triplet-based schemes pre-encoding as necessary like before, but only track how far up we had to go. Only rule channel loss when unlatch is possible, or at end of channel. Make sure that "remaining words in this schema" works accounts for shift characters, and is used by all terminating conditions. Also see the rewrite comments in EncodeAsciiCodeword().*/#define DMTX_CHAR_ASCII_PAD 129#define DMTX_CHAR_ASCII_UPPER_SHIFT 235#define DMTX_CHAR_C40_LATCH 230#define DMTX_CHAR_TEXT_LATCH 239#define DMTX_CHAR_X12_LATCH 238#define DMTX_CHAR_TRIPLET_UNLATCH 254#define DMTX_CHAR_TRIPLET_SHIFT_1 0#define DMTX_CHAR_TRIPLET_SHIFT_2 1#define DMTX_CHAR_TRIPLET_SHIFT_3 2#define DMTX_CHAR_EDIFACT_LATCH 240#define DMTX_CHAR_EDIFACT_UNLATCH 31#define DMTX_CHAR_BASE256_LATCH 231#define DMTX_CHAR_FNC1 232#define DMTX_CHAR_STRUCTURED_APPEND 233#define DMTX_CHAR_ECI 241#define DMTX_CHAR_05MACRO 236#define DMTX_CHAR_06MACRO 237#define DMTX_CHANNEL_VALID 0x00#define DMTX_CHANNEL_UNSUPPORTED_CHAR 0x01 << 0#define DMTX_CHANNEL_CANNOT_UNLATCH 0x01 << 1#define DMTX_UNLATCH_EXPLICIT 0#define DMTX_UNLATCH_IMPLICIT 1/** * @brief Initialize encode struct with default values * @return Initialized DmtxEncode struct */extern DmtxEncodedmtxEncodeStructInit(void){ DmtxEncode enc; memset(&enc, 0x00, sizeof(DmtxEncode)); enc.scheme = DmtxSchemeEncodeAscii; enc.moduleSize = 5; enc.marginSize = 10; /* Initialize background color to white *//* enc.region.gradient.ray.p.R = 255.0; enc.region.gradient.ray.p.G = 255.0; enc.region.gradient.ray.p.B = 255.0; */ /* Initialize foreground color to black *//* enc.region.gradient.tMin = 0.0; enc.region.gradient.tMax = dmtxColor3Mag(&(enc.region.gradient.ray.p)); *//* dmtxColor3Scale(&(enc.region.gradient.ray.c), &(enc.region.gradient.ray.p), -1.0/enc.region.gradient.tMax); */ dmtxMatrix3Identity(enc.xfrm); return enc;}/** * @brief Deinitialize encode struct * @param enc * @return void */extern voiddmtxEncodeStructDeInit(DmtxEncode *enc){ if(enc == NULL) return; dmtxImageFree(&(enc->image)); dmtxMessageFree(&(enc->message)); memset(enc, 0x00, sizeof(DmtxEncode));}/** * @brief Convert message into Data Matrix image * @param enc * @param inputSize * @param inputString * @param sizeIdxRequest * @return DMTX_SUCCESS | DMTX_FAILURE */extern intdmtxEncodeDataMatrix(DmtxEncode *enc, int inputSize, unsigned char *inputString, int sizeIdxRequest){ int dataWordCount; int sizeIdx; unsigned char buf[4096]; /* Encode input string into data codewords */ sizeIdx = sizeIdxRequest; dataWordCount = EncodeDataCodewords(buf, inputString, inputSize, enc->scheme, &sizeIdx); if(dataWordCount <= 0) return(DMTX_FAILURE); /* EncodeDataCodewords() should have updated any auto sizeIdx to a real one */ assert(sizeIdx != DmtxSymbolSquareAuto && sizeIdx != DmtxSymbolRectAuto); /* Add pad characters to match a standard symbol size (whether smallest or requested) */ AddPadChars(buf, &dataWordCount, dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx)); /* XXX we can remove a lot of this redundant data */ enc->region.sizeIdx = sizeIdx; enc->region.symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx); enc->region.symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx); enc->region.mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx); enc->region.mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx); /* Allocate memory for message and array */ enc->message = dmtxMessageMalloc(sizeIdx, DMTX_FORMAT_MATRIX); memcpy(enc->message->code, buf, dataWordCount);/* fprintf(stdout, "\n\nsize: %dx%d w/ %d error codewords\n", rows, cols, errorWordLength(enc->region.sizeIdx)); */ /* Generate error correction codewords */ GenReedSolEcc(enc->message, enc->region.sizeIdx); /* Module placement in region */ ModulePlacementEcc200(enc->message->array, enc->message->code, enc->region.sizeIdx, DMTX_MODULE_ON_RGB); /* Allocate memory for the image to be generated */ enc->image = dmtxImageMalloc( 2 * enc->marginSize + (enc->region.symbolCols * enc->moduleSize), 2 * enc->marginSize + (enc->region.symbolRows * enc->moduleSize)); if(enc->image == NULL) { perror("image malloc error"); return DMTX_FAILURE; } /* Insert finder and aligment pattern modules */ PrintPattern(enc); return DMTX_SUCCESS;}/** * @brief Convert message into Data Mosaic image * @param enc * @param inputSize * @param inputString * @param sizeIdxRequest * @return DMTX_SUCCESS | DMTX_FAILURE */extern intdmtxEncodeDataMosaic(DmtxEncode *enc, int inputSize, unsigned char *inputString, int sizeIdxRequest){ int dataWordCount; int tmpInputSize; unsigned char *inputStart; int splitInputSize[3]; int sizeIdx; int splitSizeIdxAttempt, splitSizeIdxFirst, splitSizeIdxLast; unsigned char buf[3][4096]; DmtxEncode encGreen, encBlue; int row, col, mappingRows, mappingCols; /* 1) count how many codewords it would take to encode the whole thing * 2) take ceiling N of codeword count divided by 3 * 3) using minimum symbol size that can accomodate N codewords: * 4) create several barcodes over iterations of increasing numbers of * input codewords until you go one too far * 5) if codewords remain after filling R, G, and B barcodes then go back * to 3 and try with next larger size * 6) take the 3 different images you created and write out a new barcode */ /* XXX we're going to force ascii until we fix the problem with C40/Text termination */ enc->scheme = DmtxSchemeEncodeAscii; /* Encode full input string to establish baseline data codeword count */ sizeIdx = sizeIdxRequest; /* XXX buf can be changed here to use all 3 buffers' length */ dataWordCount = EncodeDataCodewords(buf[0], inputString, inputSize, enc->scheme, &sizeIdx); if(dataWordCount <= 0) return DMTX_FAILURE; /* Use 1/3 (ceiling) of inputSize establish input size target */ tmpInputSize = (inputSize + 2) / 3; splitInputSize[0] = tmpInputSize; splitInputSize[1] = tmpInputSize; splitInputSize[2] = inputSize - (splitInputSize[0] + splitInputSize[1]); /* XXX clean up above lines later for corner cases */ /* Use 1/3 (floor) of dataWordCount establish first symbol size attempt */ splitSizeIdxFirst = FindCorrectSymbolSize(tmpInputSize, sizeIdxRequest); if(splitSizeIdxFirst == -1) return DMTX_FAILURE; /* Set the last possible symbol size for this symbol shape or specific size request */ if(sizeIdxRequest == DmtxSymbolSquareAuto) splitSizeIdxLast = DMTX_SYMBOL_SQUARE_COUNT - 1; else if(sizeIdxRequest == DmtxSymbolRectAuto) splitSizeIdxLast = DMTX_SYMBOL_SQUARE_COUNT + DMTX_SYMBOL_RECT_COUNT - 1; else splitSizeIdxLast = splitSizeIdxFirst; /* XXX would be nice if we could choose a size and then fill up each layer as we go, but this can cause problems with all data fits on first 2 layers. Revisit this later after things look a bit cleaner. */ /* Try increasing symbol sizes until 3 of them can hold all input values */ for(splitSizeIdxAttempt = splitSizeIdxFirst; splitSizeIdxAttempt <= splitSizeIdxLast; splitSizeIdxAttempt++) { assert(splitSizeIdxAttempt >= 0); /* RED LAYER */ sizeIdx = splitSizeIdxAttempt; inputStart = inputString; EncodeDataCodewords(buf[0], inputStart, splitInputSize[0], enc->scheme, &sizeIdx); if(sizeIdx != splitSizeIdxAttempt) continue; /* GREEN LAYER */ sizeIdx = splitSizeIdxAttempt; inputStart += splitInputSize[0]; EncodeDataCodewords(buf[1], inputStart, splitInputSize[1], enc->scheme, &sizeIdx); if(sizeIdx != splitSizeIdxAttempt) continue; /* BLUE LAYER */ sizeIdx = splitSizeIdxAttempt; inputStart += splitInputSize[1]; EncodeDataCodewords(buf[2], inputStart, splitInputSize[2], enc->scheme, &sizeIdx); if(sizeIdx != splitSizeIdxAttempt) continue; break; } /* Now we have the correct lengths for splitInputSize, and they all fit into the desired size */ encGreen = *enc; encBlue = *enc; /* First encode red to the main encode struct (image portion will be overwritten) */ inputStart = inputString; dmtxEncodeDataMatrix(enc, splitInputSize[0], inputStart, splitSizeIdxAttempt); inputStart += splitInputSize[0]; dmtxEncodeDataMatrix(&encGreen, splitInputSize[1], inputStart, splitSizeIdxAttempt); inputStart += splitInputSize[1]; dmtxEncodeDataMatrix(&encBlue, splitInputSize[2], inputStart, splitSizeIdxAttempt); mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, splitSizeIdxAttempt); mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, splitSizeIdxAttempt); memset(enc->message->array, 0x00, sizeof(unsigned char) * enc->region.mappingRows * enc->region.mappingCols); ModulePlacementEcc200(enc->message->array, enc->message->code, enc->region.sizeIdx, DMTX_MODULE_ON_RED); /* Data Mosaic will traverse this array multiple times -- reset DMTX_MODULE_ASSIGNED and DMX_MODULE_VISITED bits before starting */ for(row = 0; row < mappingRows; row++) { for(col = 0; col < mappingCols; col++) { enc->message->array[row*mappingCols+col] &= (0xff ^ (DMTX_MODULE_ASSIGNED | DMTX_MODULE_VISITED)); } } ModulePlacementEcc200(enc->message->array, encGreen.message->code, enc->region.sizeIdx, DMTX_MODULE_ON_GREEN); /* Data Mosaic will traverse this array multiple times -- reset DMTX_MODULE_ASSIGNED and DMX_MODULE_VISITED bits before starting */ for(row = 0; row < mappingRows; row++) { for(col = 0; col < mappingCols; col++) { enc->message->array[row*mappingCols+col] &= (0xff ^ (DMTX_MODULE_ASSIGNED | DMTX_MODULE_VISITED)); } } ModulePlacementEcc200(enc->message->array, encBlue.message->code, enc->region.sizeIdx, DMTX_MODULE_ON_BLUE);/* dmtxEncodeStructDeInit(&encGreen); dmtxEncodeStructDeInit(&encBlue); */ PrintPattern(enc); return DMTX_SUCCESS;}/** * @brief Convert input into message using specific encodation scheme * @param buf * @param inputString * @param inputSize * @param scheme * @param sizeIdx * @return Count of encoded data words */static intEncodeDataCodewords(unsigned char *buf, unsigned char *inputString, int inputSize, DmtxSchemeEncode scheme, int *sizeIdx){ int dataWordCount; /* * This function needs to take both dataWordCount and sizeIdx into account * because symbol size is tied to an encodation. That is, a data stream * might be different from one symbol size to another */ /* Encode input string into data codewords */ switch(scheme) { case DmtxSchemeEncodeAutoBest: dataWordCount = EncodeAutoBest(buf, inputString, inputSize); break; case DmtxSchemeEncodeAutoFast: dataWordCount = 0; /* dataWordCount = EncodeAutoFast(buf, inputString, inputSize); */ break; default: dataWordCount = EncodeSingleScheme(buf, inputString, inputSize, scheme); break; } /* XXX must fix ... will need to handle sizeIdx requests here because it is needed by Encode...() for triplet termination */ /* parameter sizeIdx is requested value, returned sizeIdx is decision */ *sizeIdx = FindCorrectSymbolSize(dataWordCount, *sizeIdx); if(*sizeIdx == -1) return 0; return dataWordCount;}/** * @brief Add necessary padding codewords to message * @param buf * @param bufSize * @param paddedSize * @return void */static voidAddPadChars(unsigned char *buf, int *bufSize, int paddedSize){ /* First pad character is not randomized */ if(*bufSize < paddedSize) buf[(*bufSize)++] = DMTX_CHAR_ASCII_PAD; /* All remaining pad characters are randomized based on character position */ while(*bufSize < paddedSize) { buf[*bufSize] = Randomize253State(DMTX_CHAR_ASCII_PAD, *bufSize + 1); (*bufSize)++; }}/** * @brief Randomize 253 state * @param codewordValue * @param codewordPosition * @return Randomized value */static unsigned charRandomize253State(unsigned char codewordValue, int codewordPosition){ int pseudoRandom; int tmp; pseudoRandom = ((149 * codewordPosition) % 253) + 1; tmp = codewordValue + pseudoRandom; return (tmp <= 254) ? tmp : tmp - 254;}/** * @brief Randomize 255 state * @param codewordValue
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -