/** * \brief Convert fitted Data Matrix region into a decoded message * \param dec * \param reg * \param fix * \return Decoded message */ extern DmtxMessage * dmtxDecodeMatrixRegion(DmtxDecode *dec, DmtxRegion *reg, int fix) { DmtxMessage *msg; DmtxVector2 topLeft, topRight, bottomLeft, bottomRight; DmtxPixelLoc pxTopLeft, pxTopRight, pxBottomLeft, pxBottomRight; msg = dmtxMessageCreate(reg->sizeIdx, DmtxFormatMatrix); if(msg == NULL) return NULL; if(PopulateArrayFromMatrix(dec, reg, msg) != DmtxPass) { dmtxMessageDestroy(&msg); return NULL; } /* maybe place remaining logic into new dmtxDecodePopulatedArray() function so other people can pass in their own arrays */ ModulePlacementEcc200(msg->array, msg->code, reg->sizeIdx, DmtxModuleOnRed | DmtxModuleOnGreen | DmtxModuleOnBlue); if(RsDecode(msg->code, reg->sizeIdx, fix) == DmtxFail) { dmtxMessageDestroy(&msg); return NULL; } topLeft.X = bottomLeft.X = topLeft.Y = topRight.Y = -0.1; topRight.X = bottomRight.X = bottomLeft.Y = bottomRight.Y = 1.1; dmtxMatrix3VMultiplyBy(&topLeft, reg->fit2raw); dmtxMatrix3VMultiplyBy(&topRight, reg->fit2raw); dmtxMatrix3VMultiplyBy(&bottomLeft, reg->fit2raw); dmtxMatrix3VMultiplyBy(&bottomRight, reg->fit2raw); pxTopLeft.X = (int)(0.5 + topLeft.X); pxTopLeft.Y = (int)(0.5 + topLeft.Y); pxBottomLeft.X = (int)(0.5 + bottomLeft.X); pxBottomLeft.Y = (int)(0.5 + bottomLeft.Y); pxTopRight.X = (int)(0.5 + topRight.X); pxTopRight.Y = (int)(0.5 + topRight.Y); pxBottomRight.X = (int)(0.5 + bottomRight.X); pxBottomRight.Y = (int)(0.5 + bottomRight.Y); CacheFillQuad(dec, pxTopLeft, pxTopRight, pxBottomRight, pxBottomLeft); DecodeDataStream(msg, reg->sizeIdx, NULL); return msg; }
/** * \brief Convert message into Data Mosaic image * * 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 * * \param enc * \param inputSize * \param inputString * \param sizeIdxRequest * \return DmtxPass | DmtxFail */ extern DmtxPassFail dmtxEncodeDataMosaic(DmtxEncode *enc, int inputSize, unsigned char *inputString) { unsigned char *inputStringR, *inputStringG, *inputStringB; int tmpInputSize; int inputSizeR, inputSizeG, inputSizeB; int sizeIdxAttempt, sizeIdxFirst, sizeIdxLast; int row, col, mappingRows, mappingCols; DmtxEncode *encR, *encG, *encB; /* Use 1/3 (ceiling) of inputSize establish input size target */ tmpInputSize = (inputSize + 2) / 3; inputSizeR = tmpInputSize; inputSizeG = tmpInputSize; inputSizeB = inputSize - (inputSizeR + inputSizeG); inputStringR = inputString; inputStringG = inputStringR + inputSizeR; inputStringB = inputStringG + inputSizeG; /* Use 1/3 (floor) of dataWordCount establish first symbol size attempt */ sizeIdxFirst = FindSymbolSize(tmpInputSize, enc->sizeIdxRequest); if(sizeIdxFirst == DmtxUndefined) return DmtxFail; /* Set the last possible symbol size for this symbol shape or specific size request */ if(enc->sizeIdxRequest == DmtxSymbolSquareAuto) sizeIdxLast = DmtxSymbolSquareCount - 1; else if(enc->sizeIdxRequest == DmtxSymbolRectAuto) sizeIdxLast = DmtxSymbolSquareCount + DmtxSymbolRectCount - 1; else sizeIdxLast = sizeIdxFirst; encR = encG = encB = NULL; /* Try increasing symbol sizes until 3 of them can hold all input values */ for(sizeIdxAttempt = sizeIdxFirst; sizeIdxAttempt <= sizeIdxLast; sizeIdxAttempt++) { dmtxEncodeDestroy(&encR); dmtxEncodeDestroy(&encG); dmtxEncodeDestroy(&encB); encR = dmtxEncodeCreate(); encG = dmtxEncodeCreate(); encB = dmtxEncodeCreate(); /* Copy all settings from master DmtxEncode, including pointer to image and message, which is initially null */ *encR = *encG = *encB = *enc; dmtxEncodeSetProp(encR, DmtxPropSizeRequest, sizeIdxAttempt); dmtxEncodeSetProp(encG, DmtxPropSizeRequest, sizeIdxAttempt); dmtxEncodeSetProp(encB, DmtxPropSizeRequest, sizeIdxAttempt); /* RED LAYER - Holds temporary copy */ dmtxEncodeDataMatrix(encR, inputSizeR, inputStringR); if(encR->region.sizeIdx != sizeIdxAttempt) continue; /* GREEN LAYER - Holds temporary copy */ dmtxEncodeDataMatrix(encG, inputSizeG, inputStringG); if(encG->region.sizeIdx != sizeIdxAttempt) continue; /* BLUE LAYER - Holds temporary copy */ dmtxEncodeDataMatrix(encB, inputSizeB, inputStringB); if(encB->region.sizeIdx != sizeIdxAttempt) continue; /* If we get this far we found a fit */ break; } if(encR == NULL || encG == NULL || encB == NULL) { dmtxEncodeDestroy(&encR); dmtxEncodeDestroy(&encG); dmtxEncodeDestroy(&encB); return DmtxFail; } /* Now we have the correct sizeIdxAttempt, and they all fit into the desired size */ /* Perform the red portion of the final encode to set internals correctly */ dmtxEncodeSetProp(enc, DmtxPropSizeRequest, sizeIdxAttempt); dmtxEncodeDataMatrix(enc, inputSizeR, inputStringR); /* Zero out the array and overwrite the bits in 3 passes */ mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdxAttempt); mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdxAttempt); memset(enc->message->array, 0x00, sizeof(unsigned char) * enc->region.mappingRows * enc->region.mappingCols); ModulePlacementEcc200(enc->message->array, encR->message->code, sizeIdxAttempt, DmtxModuleOnRed); /* Reset DmtxModuleAssigned and DMX_MODULE_VISITED bits */ for(row = 0; row < mappingRows; row++) { for(col = 0; col < mappingCols; col++) { enc->message->array[row*mappingCols+col] &= (0xff ^ (DmtxModuleAssigned | DmtxModuleVisited)); } } ModulePlacementEcc200(enc->message->array, encG->message->code, sizeIdxAttempt, DmtxModuleOnGreen); /* Reset DmtxModuleAssigned and DMX_MODULE_VISITED bits */ for(row = 0; row < mappingRows; row++) { for(col = 0; col < mappingCols; col++) { enc->message->array[row*mappingCols+col] &= (0xff ^ (DmtxModuleAssigned | DmtxModuleVisited)); } } ModulePlacementEcc200(enc->message->array, encB->message->code, sizeIdxAttempt, DmtxModuleOnBlue); /* Destroy encR, encG, and encB */ dmtxEncodeDestroy(&encR); dmtxEncodeDestroy(&encG); dmtxEncodeDestroy(&encB); PrintPattern(enc); return DmtxPass; }
/** * \brief Convert message into Data Matrix image * \param enc * \param inputSize * \param inputString * \param sizeIdxRequest * \return DmtxPass | DmtxFail */ extern DmtxPassFail dmtxEncodeDataMatrix(DmtxEncode *enc, int inputSize, unsigned char *inputString) { int sizeIdx; int width, height, bitsPerPixel; unsigned char *pxl; DmtxByte outputStorage[4096]; DmtxByteList output = dmtxByteListBuild(outputStorage, sizeof(outputStorage)); DmtxByteList input = dmtxByteListBuild(inputString, inputSize); input.length = inputSize; /* Future: stream = StreamInit() ... */ /* Future: EncodeDataCodewords(&stream) ... */ /* Encode input string into data codewords */ sizeIdx = EncodeDataCodewords(&input, &output, enc->sizeIdxRequest, enc->scheme, enc->fnc1); if(sizeIdx == DmtxUndefined || output.length <= 0) return DmtxFail; /* EncodeDataCodewords() should have updated any auto sizeIdx to a real one */ assert(sizeIdx != DmtxSymbolSquareAuto && sizeIdx != DmtxSymbolRectAuto); /* 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 = dmtxMessageCreate(sizeIdx, DmtxFormatMatrix); enc->message->padCount = 0; /* XXX this needs to be added back */ memcpy(enc->message->code, output.b, output.length); /* Generate error correction codewords */ RsEncode(enc->message, enc->region.sizeIdx); /* Module placement in region */ ModulePlacementEcc200(enc->message->array, enc->message->code, enc->region.sizeIdx, DmtxModuleOnRGB); width = 2 * enc->marginSize + (enc->region.symbolCols * enc->moduleSize); height = 2 * enc->marginSize + (enc->region.symbolRows * enc->moduleSize); bitsPerPixel = GetBitsPerPixel(enc->pixelPacking); if(bitsPerPixel == DmtxUndefined) return DmtxFail; assert(bitsPerPixel % 8 == 0); /* Allocate memory for the image to be generated */ pxl = (unsigned char *)malloc((width * bitsPerPixel / 8 + enc->rowPadBytes) * height); if(pxl == NULL) { perror("pixel malloc error"); return DmtxFail; } enc->image = dmtxImageCreate(pxl, width, height, enc->pixelPacking); if(enc->image == NULL) { perror("image malloc error"); return DmtxFail; } dmtxImageSetProp(enc->image, DmtxPropImageFlip, enc->imageFlip); dmtxImageSetProp(enc->image, DmtxPropRowPadBytes, enc->rowPadBytes); /* Insert finder and aligment pattern modules */ PrintPattern(enc); return DmtxPass; }