📄 dmtxdecode.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: dmtxdecode.c 514 2008-11-19 17:10:44Z mblaughton $ *//** * @file dmtxdecode.c * @brief Decode regions *//** * @brief Initialize decode struct with default values * @param img * @return Initialized DmtxDecode struct */extern DmtxDecodedmtxDecodeStructInit(DmtxImage *img){ DmtxDecode dec; int cacheSize; memset(&dec, 0x00, sizeof(DmtxDecode)); dec.image = img; cacheSize = dmtxImageGetProp(img, DmtxPropWidth) * dmtxImageGetProp(img, DmtxPropHeight) * sizeof(unsigned char); memset(dec.image->cache, 0x00, cacheSize); /* These values should probably be stored in the decode struct */ img->scale = 1; img->xMin = img->xMinScaled = 0; img->xMax = img->xMaxScaled = img->width - 1; img->yMin = img->yMinScaled = 0; img->yMax = img->yMaxScaled = img->height - 1; dec.edgeMin = -1; dec.edgeMax = -1; dec.scanGap = 1; dec.squareDevn = cos(50 * (M_PI/180)); dec.sizeIdxExpected = DmtxSymbolShapeAuto; dec.edgeThresh = 10; dec.shrinkMin = 1; dec.shrinkMax = 1; dec.grid = InitScanGrid(img, dec.scanGap); return dec;}/** * @brief Deinitialize decode struct * @param dec * @return void */extern voiddmtxDecodeStructDeInit(DmtxDecode *dec){ memset(dec, 0x00, sizeof(DmtxDecode));}/** * @brief Set decoding behavior property * @param dec * @param prop * @param value * @return DMTX_SUCCESS | DMTX_FAILURE */extern intdmtxDecodeSetProp(DmtxDecode *dec, int prop, int value){ int err; switch(prop) { case DmtxPropEdgeMin: dec->edgeMin = value; break; case DmtxPropEdgeMax: dec->edgeMax = value; break; case DmtxPropScanGap: dec->scanGap = value; break; case DmtxPropSquareDevn: dec->squareDevn = cos(value * (M_PI/180.0)); break; case DmtxPropSymbolSize: dec->sizeIdxExpected = value; break; case DmtxPropEdgeThresh: dec->edgeThresh = value; break; case DmtxPropXmin: err = dmtxImageSetProp(dec->image, DmtxPropXmin, value); if(err == DMTX_FAILURE) return DMTX_FAILURE; break; case DmtxPropXmax: err = dmtxImageSetProp(dec->image, DmtxPropXmax, value); if(err == DMTX_FAILURE) return DMTX_FAILURE; break; case DmtxPropYmin: err = dmtxImageSetProp(dec->image, DmtxPropYmin, value); if(err == DMTX_FAILURE) return DMTX_FAILURE; break; case DmtxPropYmax: err = dmtxImageSetProp(dec->image, DmtxPropYmax, value); if(err == DMTX_FAILURE) return DMTX_FAILURE; break; case DmtxPropShrinkMin: dec->shrinkMin = value; break; case DmtxPropShrinkMax: dec->shrinkMax = value; err = dmtxImageSetProp(dec->image, DmtxPropScale, value); if(err == DMTX_FAILURE) return DMTX_FAILURE; break; } /* Minimum image scale can't be larger than maximum image scale */ if(dec->shrinkMin < 1 || dec->shrinkMax < dec->shrinkMin) return DMTX_FAILURE; if(dec->squareDevn <= 0.0 || dec->squareDevn >= 1.0) return DMTX_FAILURE; if(dec->scanGap < 1) return DMTX_FAILURE; if(dec->edgeThresh < 1 || dec->edgeThresh > 100) return DMTX_FAILURE; /* Reinitialize scangrid if any inputs changed */ dec->grid = InitScanGrid(dec->image, dec->scanGap); return DMTX_SUCCESS;}/** * @brief Convert fitted Data Matrix region into a decoded message * @param dec * @param reg * @param fix * @return Decoded message */extern DmtxMessage *dmtxDecodeMatrixRegion(DmtxImage *img, DmtxRegion *reg, int fix){ int row, col; int width, height; int offset; DmtxMessage *msg; DmtxVector2 p; msg = dmtxMessageMalloc(reg->sizeIdx, DMTX_FORMAT_MATRIX); if(msg == NULL) return NULL; if(PopulateArrayFromMatrix(msg, img, reg) != DMTX_SUCCESS) { dmtxMessageFree(&msg); return NULL; } ModulePlacementEcc200(msg->array, msg->code, reg->sizeIdx, DMTX_MODULE_ON_RED | DMTX_MODULE_ON_GREEN | DMTX_MODULE_ON_BLUE); if(DecodeCheckErrors(msg->code, reg->sizeIdx, fix) != DMTX_SUCCESS) { dmtxMessageFree(&msg); return NULL; } width = dmtxImageGetProp(img, DmtxPropScaledWidth); height = dmtxImageGetProp(img, DmtxPropScaledHeight); for(row = 0; row < height; row++) { for(col = 0; col < width; col++) { p.X = col; p.Y = row; dmtxMatrix3VMultiplyBy(&p, reg->raw2fit); /* XXX tighten these boundaries can by accounting for barcode size */ if(p.X >= -0.1 && p.X <= 1.1 && p.Y >= -0.1 && p.Y <= 1.1) { offset = dmtxImageGetOffset(img, col, row); if(offset == DMTX_BAD_OFFSET) continue; else img->cache[offset] |= 0x80; /* Mark as visited */ } } } DecodeDataStream(msg, reg->sizeIdx, NULL); return msg;}/** * @brief Convert fitted Data Mosaic region into a decoded message * @param dec * @param reg * @param fix * @return Decoded message */extern DmtxMessage *dmtxDecodeMosaicRegion(DmtxImage *img, DmtxRegion *reg, int fix){ int row, col; int mappingRows, mappingCols; DmtxMessage *msg; DmtxMessage rMesg, gMesg, bMesg; mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, reg->sizeIdx); mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, reg->sizeIdx); msg = dmtxMessageMalloc(reg->sizeIdx, DMTX_FORMAT_MOSAIC); if(msg == NULL) return NULL; rMesg = gMesg = bMesg = *msg; rMesg.codeSize = gMesg.codeSize = bMesg.codeSize = msg->codeSize/3; gMesg.code += gMesg.codeSize; bMesg.code += (bMesg.codeSize * 2); if(PopulateArrayFromMosaic(msg, img, reg) != DMTX_SUCCESS) { dmtxMessageFree(&msg); return NULL; } ModulePlacementEcc200(msg->array, rMesg.code, reg->sizeIdx, DMTX_MODULE_ON_RED); if(DecodeCheckErrors(rMesg.code, reg->sizeIdx, fix) != DMTX_SUCCESS) { dmtxMessageFree(&msg); return NULL; } for(row = 0; row < mappingRows; row++) for(col = 0; col < mappingCols; col++) msg->array[row*mappingCols+col] &= (0xff ^ DMTX_MODULE_VISITED); ModulePlacementEcc200(msg->array, gMesg.code, reg->sizeIdx, DMTX_MODULE_ON_GREEN); if(DecodeCheckErrors(gMesg.code, reg->sizeIdx, fix) != DMTX_SUCCESS) { dmtxMessageFree(&msg); return NULL; } for(row = 0; row < mappingRows; row++) for(col = 0; col < mappingCols; col++) msg->array[row*mappingCols+col] &= (0xff ^ DMTX_MODULE_VISITED); ModulePlacementEcc200(msg->array, bMesg.code, reg->sizeIdx, DMTX_MODULE_ON_BLUE); if(DecodeCheckErrors(bMesg.code, reg->sizeIdx, fix) != DMTX_SUCCESS) { dmtxMessageFree(&msg); return NULL; } DecodeDataStream(&rMesg, reg->sizeIdx, NULL); DecodeDataStream(&gMesg, reg->sizeIdx, rMesg.output + rMesg.outputIdx); DecodeDataStream(&bMesg, reg->sizeIdx, gMesg.output + gMesg.outputIdx); msg->outputIdx = rMesg.outputIdx + gMesg.outputIdx + bMesg.outputIdx; return msg;}/** * @brief Translate encoded data stream into final output * @param msg * @param sizeIdx * @param outputStart * @return void */static voidDecodeDataStream(DmtxMessage *msg, int sizeIdx, unsigned char *outputStart){ DmtxSchemeDecode encScheme; unsigned char *ptr, *dataEnd; msg->output = (outputStart == NULL) ? msg->output : outputStart; msg->outputIdx = 0; ptr = msg->code; dataEnd = ptr + dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx); while(ptr < dataEnd) { ptr = NextEncodationScheme(&encScheme, ptr); switch(encScheme) { case DmtxSchemeDecodeAsciiStd: ptr = DecodeSchemeAsciiStd(msg, ptr, dataEnd); break; case DmtxSchemeDecodeAsciiExt: ptr = DecodeSchemeAsciiExt(msg, ptr, dataEnd); break; case DmtxSchemeDecodeC40: case DmtxSchemeDecodeText: ptr = DecodeSchemeC40Text(msg, ptr, dataEnd, encScheme); break; case DmtxSchemeDecodeX12: ptr = DecodeSchemeX12(msg, ptr, dataEnd); break; case DmtxSchemeDecodeEdifact: ptr = DecodeSchemeEdifact(msg, ptr, dataEnd); break; case DmtxSchemeDecodeBase256: ptr = DecodeSchemeBase256(msg, ptr, dataEnd); break; } }}/** * @brief Determine next encodation scheme * @param encScheme * @param ptr * @return Pointer to next undecoded codeword */static unsigned char *NextEncodationScheme(DmtxSchemeDecode *encScheme, unsigned char *ptr){ switch(*ptr) { case 230: *encScheme = DmtxSchemeDecodeC40; break; case 231: *encScheme = DmtxSchemeDecodeBase256; break; case 235: *encScheme = DmtxSchemeDecodeAsciiExt; break; case 238: *encScheme = DmtxSchemeDecodeX12; break; case 239: *encScheme = DmtxSchemeDecodeText; break; case 240: *encScheme = DmtxSchemeDecodeEdifact; break; default: *encScheme = DmtxSchemeDecodeAsciiStd; return ptr; } return ptr + 1;}/** * @brief Decode stream assuming standard ASCII encodation * @param msg * @param ptr * @param dataEnd * @return Pointer to next undecoded codeword */static unsigned char *DecodeSchemeAsciiStd(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd){ int digits; if(*ptr <= 128) { msg->output[msg->outputIdx++] = *ptr - 1; } else if(*ptr == 129) { return dataEnd; } else if(*ptr <= 229) { digits = *ptr - 130; msg->output[msg->outputIdx++] = digits/10 + '0'; msg->output[msg->outputIdx++] = digits - (digits/10)*10 + '0'; } return ptr + 1;}/** * @brief Decode stream assuming extended ASCII encodation * @param msg * @param ptr * @param dataEnd * @return Pointer to next undecoded codeword */static unsigned char *DecodeSchemeAsciiExt(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd){ msg->output[msg->outputIdx++] = *ptr + 128; return ptr + 1;}/** * @brief Decode stream assuming C40 or Text encodation * @param msg * @param ptr * @param dataEnd * @param encScheme * @return Pointer to next undecoded codeword */static unsigned char *DecodeSchemeC40Text(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd, DmtxSchemeDecode encScheme){ int i; int packed; int shift = 0; unsigned char c40Values[3]; assert(encScheme == DmtxSchemeDecodeC40 || encScheme == DmtxSchemeDecodeText); while(ptr < dataEnd) { /* FIXME Also check that ptr+1 is safe to access */ packed = (*ptr << 8) | *(ptr+1); c40Values[0] = ((packed - 1)/1600); c40Values[1] = ((packed - 1)/40) % 40; c40Values[2] = (packed - 1) % 40; ptr += 2; for(i = 0; i < 3; i++) { if(shift == 0) { /* Basic set */ if(c40Values[i] <= 2) { shift = c40Values[i] + 1; } else if(c40Values[i] == 3) { msg->output[msg->outputIdx++] = ' '; /* Space */ } else if(c40Values[i] <= 13) { msg->output[msg->outputIdx++] = c40Values[i] - 13 + '9'; /* 0-9 */ } else if(c40Values[i] <= 39) { if(encScheme == DmtxSchemeDecodeC40) { msg->output[msg->outputIdx++] = c40Values[i] - 39 + 'Z'; /* A-Z */ } else if(encScheme == DmtxSchemeDecodeText) { msg->output[msg->outputIdx++] = c40Values[i] - 39 + 'z'; /* a-z */ } } } else if(shift == 1) { /* Shift 1 set */ msg->output[msg->outputIdx++] = c40Values[i]; /* ASCII 0 - 31 */ shift = 0; } else if(shift == 2) { /* Shift 2 set */ if(c40Values[i] <= 14) msg->output[msg->outputIdx++] = c40Values[i] + 33; /* ASCII 33 - 47 */ else if(c40Values[i] <= 21) msg->output[msg->outputIdx++] = c40Values[i] + 43; /* ASCII 58 - 64 */ else if(c40Values[i] <= 26) msg->output[msg->outputIdx++] = c40Values[i] + 69; /* ASCII 91 - 95 */ else if(c40Values[i] == 27) fprintf(stdout, "FNC1 (?)"); /* FNC1 (eh?) */ else if(c40Values[i] == 30)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -