Ejemplo n.º 1
0
/**
 * @brief  XXX
 * @param  image
 * @param  reg
 * @param  symbolRow
 * @param  symbolCol
 * @param  sizeIdx
 * @return Averaged module color
 */
static DmtxColor3
ReadModuleColor(DmtxImage *image, DmtxRegion *reg, int symbolRow, int symbolCol, int sizeIdx)
{
   int i;
   int symbolRows, symbolCols;
   double sampleX[] = { 0.5, 0.4, 0.5, 0.6, 0.5 };
   double sampleY[] = { 0.5, 0.5, 0.4, 0.5, 0.6 };
   DmtxVector2 p, p0;
   DmtxColor3 cPoint, cAverage;

   cAverage.R = cAverage.G = cAverage.B = 0.0;

   symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
   symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx);

   for(i = 0; i < 5; i++) {

      p.X = (1.0/symbolCols) * (symbolCol + sampleX[i]);
      p.Y = (1.0/symbolRows) * (symbolRow + sampleY[i]);

      dmtxMatrix3VMultiply(&p0, &p, reg->fit2raw);
      dmtxColor3FromImage2(&cPoint, image, p0);
/*    dmtxColor3FromImage(&cPoint, image, p0.X, p0.Y); */

      dmtxColor3AddTo(&cAverage, &cPoint);

/*    CALLBACK_DECODE_FUNC4(plotPointCallback, dec, p0, 1, 1, DMTX_DISPLAY_POINT); */
   }
   dmtxColor3ScaleBy(&cAverage, 0.2);

   return cAverage;
}
Ejemplo n.º 2
0
/**
 * receives symbol row and col and returns status
 * DMTX_MODULE_ON / !DMTX_MODULE_ON (DMTX_MODULE_OFF)
 * DMTX_MODULE_ASSIGNED
 * DMTX_MODULE_VISITED
 * DMTX_MODULE_DATA / !DMTX_MODULE_DATA (DMTX_MODULE_ALIGNMENT)
 * row and col are expressed in symbol coordinates, so (0,0) is the intersection of the "L"
 */
int
dmtxSymbolModuleStatus(DmtxMessage *message, int sizeIdx, int symbolRow, int symbolCol)
{
   int symbolRowReverse;
   int mappingRow, mappingCol;
   int dataRegionRows, dataRegionCols;
   int symbolRows, mappingCols;

   dataRegionRows = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionRows, sizeIdx);
   dataRegionCols = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionCols, sizeIdx);
   symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
   mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx);

   symbolRowReverse = symbolRows - symbolRow - 1;
   mappingRow = symbolRowReverse - 1 - 2 * (symbolRowReverse / (dataRegionRows+2));
   mappingCol = symbolCol - 1 - 2 * (symbolCol / (dataRegionCols+2));

   /* Solid portion of alignment patterns */
   if(symbolRow % (dataRegionRows+2) == 0 ||
         symbolCol % (dataRegionCols+2) == 0)
      return (DMTX_MODULE_ON_RGB | (!DMTX_MODULE_DATA));

   /* Horinzontal calibration bars */
   if((symbolRow+1) % (dataRegionRows+2) == 0)
      return (((symbolCol & 0x01) ? 0 : DMTX_MODULE_ON_RGB) | (!DMTX_MODULE_DATA));

   /* Vertical calibration bars */
   if((symbolCol+1) % (dataRegionCols+2) == 0)
      return (((symbolRow & 0x01) ? 0 : DMTX_MODULE_ON_RGB) | (!DMTX_MODULE_DATA));

   /* Data modules */
   return (message->array[mappingRow * mappingCols + mappingCol] | DMTX_MODULE_DATA);
}
Ejemplo n.º 3
0
/**
 * @brief  Allocate memory for message
 * @param  sizeIdx
 * @param  symbolFormat DmtxFormatMatrix | DmtxFormatMosaic
 * @return Address of allocated memory
 */
extern DmtxMessage *
dmtxMessageCreate(int sizeIdx, int symbolFormat)
{
   DmtxMessage *message;
   int mappingRows, mappingCols;

   assert(symbolFormat == DmtxFormatMatrix || symbolFormat == DmtxFormatMosaic);

   mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx);
   mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx);

   message = (DmtxMessage *)calloc(1, sizeof(DmtxMessage));
   if(message == NULL)
      return NULL;

   message->arraySize = sizeof(unsigned char) * mappingRows * mappingCols;

   message->array = (unsigned char *)calloc(1, message->arraySize);
   if(message->array == NULL) {
      perror("Calloc failed");
      dmtxMessageDestroy(&message);
      return NULL;
   }

   message->codeSize = sizeof(unsigned char) *
         dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx) +
         dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx);

   if(symbolFormat == DmtxFormatMosaic)
      message->codeSize *= 3;

   message->code = (unsigned char *)calloc(message->codeSize, sizeof(unsigned char));
   if(message->code == NULL) {
      perror("Calloc failed");
      dmtxMessageDestroy(&message);
      return NULL;
   }

   /* XXX not sure if this is the right place or even the right approach.
      Trying to allocate memory for the decoded data stream and will
      initially assume that decoded data will not be larger than 2x encoded data */
   message->outputSize = sizeof(unsigned char) * message->codeSize * 10;
   message->output = (unsigned char *)calloc(message->outputSize, sizeof(unsigned char));
   if(message->output == NULL) {
      perror("Calloc failed");
      dmtxMessageDestroy(&message);
      return NULL;
   }

   return message;
}
Ejemplo n.º 4
0
DmtxPassFail
RsEncode(DmtxMessage *message, int sizeIdx)
{
   int i, j;
   int blockStride, blockIdx;
   int blockErrorWords, symbolDataWords, symbolErrorWords, symbolTotalWords;
   DmtxPassFail passFail;
   DmtxByte val, *eccPtr;
   DmtxByte genStorage[MAX_ERROR_WORD_COUNT];
   DmtxByte eccStorage[MAX_ERROR_WORD_COUNT];
   DmtxByteList gen = dmtxByteListBuild(genStorage, sizeof(genStorage));
   DmtxByteList ecc = dmtxByteListBuild(eccStorage, sizeof(eccStorage));

   blockStride = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx);
   blockErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockErrorWords, sizeIdx);
   symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
   symbolErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx);
   symbolTotalWords = symbolDataWords + symbolErrorWords;

   /* Populate generator polynomial */
   RsGenPoly(&gen, blockErrorWords);

   /* For each interleaved block... */
   for(blockIdx = 0; blockIdx < blockStride; blockIdx++)
   {
      /* Generate error codewords */
      dmtxByteListInit(&ecc, blockErrorWords, 0, &passFail); CHKPASS;
      for(i = blockIdx; i < symbolDataWords; i += blockStride)
      {
         val = GfAdd(ecc.b[blockErrorWords-1], message->code[i]);

         for(j = blockErrorWords - 1; j > 0; j--)
         {
            DMTX_CHECK_BOUNDS(&ecc, j); DMTX_CHECK_BOUNDS(&ecc, j-1); DMTX_CHECK_BOUNDS(&gen, j);
            ecc.b[j] = GfAdd(ecc.b[j-1], GfMult(gen.b[j], val));
         }

         ecc.b[0] = GfMult(gen.b[0], val);
      }

      /* Copy to output message */
      eccPtr = ecc.b + blockErrorWords;
      for(i = symbolDataWords + blockIdx; i < symbolTotalWords; i += blockStride)
         message->code[i] = *(--eccPtr);

      assert(ecc.b == eccPtr);
   }

   return DmtxPass;
}
Ejemplo n.º 5
0
/**
 * @brief  XXX
 * @param  message
 * @param  sizeIdx
 * @return void
 */
static void
GenReedSolEcc(DmtxMessage *message, int sizeIdx)
{
   int i, j, val;
   int step, block;
   int blockSize;
   int dataLength;
   int errorWordCount;
   int totalLength;
   unsigned char g[69], b[68], *bPtr;
   unsigned char *codewords = message->code;

   dataLength = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
   errorWordCount = dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx);
   totalLength = dataLength + errorWordCount;

   step = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx);
   blockSize = errorWordCount / step;

   memset(g, 0x01, sizeof(g));

   /* Generate ECC polynomial */
   for(i = 1; i <= blockSize; i++) {
      for(j = i - 1; j >= 0; j--) {
         g[j] = GfDoublify(g[j], i);     /* g[j] *= 2**i */
         if(j > 0)
            g[j] = GfSum(g[j], g[j-1]);  /* g[j] += g[j-1] */
      }
   }

   /* Populate error codeword array */
   for(block = 0; block < step; block++) {

      memset(b, 0x00, sizeof(b));
      for(i = block; i < dataLength; i += step) {
         val = GfSum(b[blockSize-1], codewords[i]);
         for(j = blockSize - 1; j > 0; j--) {
            b[j] = GfSum(b[j-1], GfProduct(g[j], val));
         }
         b[0] = GfProduct(g[0], val);
      }

      bPtr = b + blockSize - 1;
      for(i = dataLength + block; i < totalLength; i += step) {
         codewords[i] = *(bPtr--);
      }

      assert(b - bPtr == 1);
   }
}
Ejemplo n.º 6
0
/**
 * @brief  XXX
 * @param  code
 * @param  sizeIdx
 * @param  fix
 * @return DMTX_SUCCESS | DMTX_FAILURE
 */
static int
DecodeCheckErrors(unsigned char *code, int sizeIdx, int fix)
{
   int i, j;
   int interleavedBlocks;
   int blockErrorWords;
   int blockTotalWords;
   int blockMaxCorrectable;
   struct rs *rs;
   int fixedErr, fixedErrSum;
   unsigned char data[255];

   interleavedBlocks = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx);
   blockErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockErrorWords, sizeIdx);
   blockTotalWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockTotalWords, sizeIdx);
   blockMaxCorrectable = dmtxGetSymbolAttribute(DmtxSymAttribBlockMaxCorrectable, sizeIdx);

   rs = init_rs_char(blockErrorWords, 255 - blockTotalWords);
   if(rs == NULL)
      return DMTX_FAILURE;

   fixedErrSum = 0;
   for(i = 0; i < interleavedBlocks; i++) {

      for(j = 0; j < blockTotalWords; j++)
         data[j] = code[j*interleavedBlocks+i];

      fixedErr = decode_rs_char(rs, data, NULL, 0, fix);

      if(fixedErr < 0 || fixedErr > blockMaxCorrectable) {
         free_rs_char(rs);
         return DMTX_FAILURE;
      }

      fixedErrSum += fixedErr;

      for(j = 0; j < blockTotalWords; j++)
         code[j*interleavedBlocks+i] = data[j];
   }

   free_rs_char(rs);

   if(fix >= 0 && fixedErrSum > fix)
      return DMTX_FAILURE;

   return DMTX_SUCCESS;
}
Ejemplo n.º 7
0
/**
 * \brief  Retrieve data size for a specific symbol size and block number
 * \param  sizeIdx
 * \param  blockIdx
 * \return Attribute value
 */
int
dmtxGetBlockDataSize(int sizeIdx, int blockIdx)
{
    int symbolDataWords;
    int interleavedBlocks;
    int count;

    symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
    interleavedBlocks = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx);

    if(symbolDataWords < 1 || interleavedBlocks < 1)
        return DmtxUndefined;

    count = (int)(symbolDataWords/interleavedBlocks);

    return (sizeIdx == DmtxSymbol144x144 && blockIdx < 8) ? count + 1 : count;
}
Ejemplo n.º 8
0
/**
 * \brief  Determine symbol size based on data size and requested properties
 * \param  dataWords
 * \param  sizeIdxRequest
 * \return Symbol size index (or DmtxUndefined if none)
 */
static int
FindSymbolSize(int dataWords, int sizeIdxRequest)
{
    int sizeIdx;
    int idxBeg, idxEnd;

    if(dataWords <= 0)
        return DmtxUndefined;

    if(sizeIdxRequest == DmtxSymbolSquareAuto || sizeIdxRequest == DmtxSymbolRectAuto) {

        if(sizeIdxRequest == DmtxSymbolSquareAuto) {
            idxBeg = 0;
            idxEnd = DmtxSymbolSquareCount;
        }
        else {
            idxBeg = DmtxSymbolSquareCount;
            idxEnd = DmtxSymbolSquareCount + DmtxSymbolRectCount;
        }

        for(sizeIdx = idxBeg; sizeIdx < idxEnd; sizeIdx++) {
            if(dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx) >= dataWords)
                break;
        }

        if(sizeIdx == idxEnd)
            return DmtxUndefined;
    }
    else {
        sizeIdx = sizeIdxRequest;
    }

    if(dataWords > dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx))
        return DmtxUndefined;

    return sizeIdx;
}
Ejemplo n.º 9
0
static void
UpdateBase256ChainHeader(DmtxEncodeStream *stream, int perfectSizeIdx)
{
   int headerIndex;
   int outputLength;
   int headerByteCount;
   int symbolDataWords;
   DmtxBoolean perfectFit;
   DmtxByte headerValue0;
   DmtxByte headerValue1;

   outputLength = stream->outputChainValueCount;
   headerIndex = stream->output->length - stream->outputChainWordCount;
   headerByteCount = stream->outputChainWordCount - stream->outputChainValueCount;
   perfectFit = (perfectSizeIdx == DmtxUndefined) ? DmtxFalse : DmtxTrue;

   /*
    * If requested perfect fit verify symbol capacity against final length
    */

   if(perfectFit)
   {
      symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, perfectSizeIdx);
      if(symbolDataWords != stream->output->length - 1)
      {
         StreamMarkFatal(stream, DmtxErrorUnknown);
         return;
      }
   }

   /*
    * Adjust header to hold correct number of bytes, not worrying about the
    * values held there until below. Note: Header bytes are not considered
    * scheme "values" so we can insert or remove them without updating the
    * outputChainValueCount.
    */

   if(headerByteCount == 0 && stream->outputChainWordCount == 0)
   {
      /* No output words written yet -- insert single header byte */
      StreamOutputChainAppend(stream, 0); CHKERR;
      headerByteCount++;
   }
   else if(!perfectFit && headerByteCount == 1 && outputLength > 249)
   {
      /* Beyond 249 bytes requires a second header byte */
      Base256OutputChainInsertFirst(stream); CHKERR;
      headerByteCount++;
   }
   else if(perfectFit && headerByteCount == 2)
   {
      /* Encoding to exact end of symbol only requires single byte */
      Base256OutputChainRemoveFirst(stream); CHKERR;
      headerByteCount--;
   }

   /*
    * Encode header byte(s) with current length
    */

   if(!perfectFit && headerByteCount == 1 && outputLength <= 249)
   {
      /* Normal condition for chain length < 250 bytes */
      headerValue0 = Randomize255State(outputLength, headerIndex + 1);
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;
   }
   else if(!perfectFit && headerByteCount == 2 && outputLength > 249)
   {
      /* Normal condition for chain length >= 250 bytes */
      headerValue0 = Randomize255State(outputLength/250 + 249, headerIndex + 1);
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;

      headerValue1 = Randomize255State(outputLength%250, headerIndex + 2);
      StreamOutputSet(stream, headerIndex + 1, headerValue1); CHKERR;
   }
   else if(perfectFit && headerByteCount == 1)
   {
      /* Special condition when Base 256 stays in effect to end of symbol */
      headerValue0 = Randomize255State(0, headerIndex + 1); /* XXX replace magic value 0? */
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;
   }
   else
   {
      StreamMarkFatal(stream, DmtxErrorUnknown);
      return;
   }
}
Ejemplo n.º 10
0
DmtxPassFail
RsDecode(unsigned char *code, int sizeIdx, int fix)
{
   int i;
   int blockStride, blockIdx;
   int blockDataWords, blockErrorWords, blockTotalWords, blockMaxCorrectable;
   int symbolDataWords, symbolErrorWords, symbolTotalWords;
   DmtxBoolean error, repairable;
   DmtxPassFail passFail;
   unsigned char *word;
   DmtxByte elpStorage[MAX_ERROR_WORD_COUNT];
   DmtxByte synStorage[MAX_ERROR_WORD_COUNT+1];
   DmtxByte recStorage[NN];
   DmtxByte locStorage[NN];
   DmtxByteList elp = dmtxByteListBuild(elpStorage, sizeof(elpStorage));
   DmtxByteList syn = dmtxByteListBuild(synStorage, sizeof(synStorage));
   DmtxByteList rec = dmtxByteListBuild(recStorage, sizeof(recStorage));
   DmtxByteList loc = dmtxByteListBuild(locStorage, sizeof(locStorage));

   blockStride = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx);
   blockErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockErrorWords, sizeIdx);
   blockMaxCorrectable = dmtxGetSymbolAttribute(DmtxSymAttribBlockMaxCorrectable, sizeIdx);
   symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
   symbolErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx);
   symbolTotalWords = symbolDataWords + symbolErrorWords;

   /* For each interleaved block */
   for(blockIdx = 0; blockIdx < blockStride; blockIdx++)
   {
      /* Data word count depends on blockIdx due to special case at 144x144 */
      blockDataWords = dmtxGetBlockDataSize(sizeIdx, blockIdx);
      blockTotalWords = blockErrorWords + blockDataWords;

      /* Populate received list (rec) with data and error codewords */
      dmtxByteListInit(&rec, 0, 0, &passFail); CHKPASS;

      /* Start with final error word and work backward */
      word = code + symbolTotalWords + blockIdx - blockStride;
      for(i = 0; i < blockErrorWords; i++)
      {
         dmtxByteListPush(&rec, *word, &passFail); CHKPASS;
         word -= blockStride;
      }

      /* Start with final data word and work backward */
      word = code + blockIdx + (blockStride * (blockDataWords - 1));
      for(i = 0; i < blockDataWords; i++)
      {
         dmtxByteListPush(&rec, *word, &passFail); CHKPASS;
         word -= blockStride;
      }

      /* Compute syndromes (syn) */
      error = RsComputeSyndromes(&syn, &rec, blockErrorWords);

      /* Error(s) detected: Attempt repair */
      if(error)
      {
         /* Find error locator polynomial (elp) */
         repairable = RsFindErrorLocatorPoly(&elp, &syn, blockErrorWords, blockMaxCorrectable);
         if(!repairable)
            return DmtxFail;

         /* Find error positions (loc) */
         repairable = RsFindErrorLocations(&loc, &elp);
         if(!repairable)
            return DmtxFail;

         /* Find error values and repair */
         RsRepairErrors(&rec, &loc, &elp, &syn);
      }

      /*
       * Overwrite output with correct/corrected values
       */

      /* Start with first data word and work forward */
      word = code + blockIdx;
      for(i = 0; i < blockDataWords; i++)
      {
         *word = dmtxByteListPop(&rec, &passFail); CHKPASS;
         word += blockStride;
      }

      /* Start with first error word and work forward */
      word = code + symbolDataWords + blockIdx;
      for(i = 0; i < blockErrorWords; i++)
      {
         *word = dmtxByteListPop(&rec, &passFail); CHKPASS;
         word += blockStride;
      }
   }

   return DmtxPass;
}
Ejemplo n.º 11
0
/**
 * \brief  Populate array with codeword values based on module colors
 * \param  msg
 * \param  img
 * \param  reg
 * \return DmtxPass | DmtxFail
 */
DmtxPassFail
PopulateArrayFromMatrix(DmtxDecode *dec, DmtxRegion *reg, DmtxMessage *msg)
{
   int weightFactor;
   int mapWidth, mapHeight;
   int xRegionTotal, yRegionTotal;
   int xRegionCount, yRegionCount;
   int xOrigin, yOrigin;
   int mapCol, mapRow;
   int colTmp, rowTmp, idx;
   int tally[24][24]; /* Large enough to map largest single region */

/* memset(msg->array, 0x00, msg->arraySize); */

   /* Capture number of regions present in barcode */
   xRegionTotal = dmtxGetSymbolAttribute(DmtxSymAttribHorizDataRegions, reg->sizeIdx);
   yRegionTotal = dmtxGetSymbolAttribute(DmtxSymAttribVertDataRegions, reg->sizeIdx);

   /* Capture region dimensions (not including border modules) */
   mapWidth = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionCols, reg->sizeIdx);
   mapHeight = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionRows, reg->sizeIdx);

   weightFactor = 2 * (mapHeight + mapWidth + 2);
   assert(weightFactor > 0);

   /* Tally module changes for each region in each direction */
   for(yRegionCount = 0; yRegionCount < yRegionTotal; yRegionCount++) {

      /* Y location of mapping region origin in symbol coordinates */
      yOrigin = yRegionCount * (mapHeight + 2) + 1;

      for(xRegionCount = 0; xRegionCount < xRegionTotal; xRegionCount++) {

         /* X location of mapping region origin in symbol coordinates */
         xOrigin = xRegionCount * (mapWidth + 2) + 1;

         memset(tally, 0x00, 24 * 24 * sizeof(int));
         TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirUp);
         TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirLeft);
         TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirDown);
         TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirRight);

         /* Decide module status based on final tallies */
         for(mapRow = 0; mapRow < mapHeight; mapRow++) {
            for(mapCol = 0; mapCol < mapWidth; mapCol++) {

               rowTmp = (yRegionCount * mapHeight) + mapRow;
               rowTmp = yRegionTotal * mapHeight - rowTmp - 1;
               colTmp = (xRegionCount * mapWidth) + mapCol;
               idx = (rowTmp * xRegionTotal * mapWidth) + colTmp;

               if(tally[mapRow][mapCol]/(double)weightFactor >= 0.5)
                  msg->array[idx] = DmtxModuleOnRGB;
               else
                  msg->array[idx] = DmtxModuleOff;

               msg->array[idx] |= DmtxModuleAssigned;
            }
         }
      }
   }

   return DmtxPass;
}
Ejemplo n.º 12
0
/**
 * @brief  XXX
 * @param  image
 * @param  reg
 * @return DMTX_SUCCESS | DMTX_FAILURE
 */
static int
MatrixRegionFindSize(DmtxImage *image, DmtxRegion *reg)
{
   int sizeIdx;
   int errors[30] = { 0 };
   int minErrorsSizeIdx;
   int row, col, symbolRows, symbolCols;
   double tOff, tOn, jumpThreshold;
   DmtxColor3 colorOn, colorOff;
   DmtxColor3 colorOnAvg, colorOffAvg;
   DmtxColor3 black = { 0.0, 0.0, 0.0 };
   DmtxGradient gradient, testGradient;
   int sizeIdxAttempts[] = { 23, 22, 21, 20, 19, 18, 17, 16, 15, 14,
                             13, 29, 12, 11, 10, 28, 27,  9, 25,  8,
                             26,  7,  6,  5,  4, 24,  3,  2,  1,  0 };
   int *ptr;

   /* First try all sizes to determine which sizeIdx with best contrast */
   ptr = sizeIdxAttempts;
   gradient.tMin = gradient.tMid = gradient.tMax = 0;
   do {
      sizeIdx = *ptr;
      symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
      symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx);

      colorOnAvg = colorOffAvg = black;

      for(row = 0, col = 0; col < symbolCols; col++) {
         colorOn = ReadModuleColor(image, reg, row, col, sizeIdx);
         colorOff = ReadModuleColor(image, reg, row-1, col, sizeIdx);
         dmtxColor3AddTo(&colorOnAvg, &colorOn);
         dmtxColor3AddTo(&colorOffAvg, &colorOff);
      }

      for(row = 0, col = 0; row < symbolRows; row++) {
         colorOn = ReadModuleColor(image, reg, row, col, sizeIdx);
         colorOff = ReadModuleColor(image, reg, row, col-1, sizeIdx);
         dmtxColor3AddTo(&colorOnAvg, &colorOn);
         dmtxColor3AddTo(&colorOffAvg, &colorOff);
      }

      dmtxColor3ScaleBy(&colorOnAvg, 1.0/(symbolRows + symbolCols));
      dmtxColor3ScaleBy(&colorOffAvg, 1.0/(symbolRows + symbolCols));

      testGradient.ray.p = colorOffAvg;
      dmtxColor3Sub(&testGradient.ray.c, &colorOnAvg, &colorOffAvg);
      if(dmtxColor3Mag(&testGradient.ray.c) < 20)
         continue;

      dmtxColor3Norm(&testGradient.ray.c);
      testGradient.tMin = 0;
      testGradient.tMax = dmtxDistanceAlongRay3(&testGradient.ray, &colorOnAvg);
      testGradient.tMid = (testGradient.tMin + testGradient.tMax) / 2.0;

      if(testGradient.tMax > gradient.tMax)
         gradient = testGradient;
   } while(*(ptr++) != 0);

   jumpThreshold = 0.4 * (gradient.tMax - gradient.tMin);
   if(jumpThreshold < 20)
      return DMTX_FAILURE;

   /* Start with largest possible pattern size and work downward.  If done
      in other direction then false positive is possible. */

   ptr = sizeIdxAttempts;
   minErrorsSizeIdx = *ptr;
   do {
      sizeIdx = *ptr;
      symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
      symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx);

      /* Test each pair of ON/OFF modules in the calibration bars */

      /* Top calibration row */
      row = symbolRows - 1;
      for(col = 0; col < symbolCols; col += 2) {
         colorOff = ReadModuleColor(image, reg, row, col + 1, sizeIdx);
         tOff = dmtxDistanceAlongRay3(&gradient.ray, &colorOff);
         colorOn = ReadModuleColor(image, reg, row, col, sizeIdx);
         tOn = dmtxDistanceAlongRay3(&gradient.ray, &colorOn);

         if(tOn - tOff < jumpThreshold)
            errors[sizeIdx]++;

         if(errors[sizeIdx] > errors[minErrorsSizeIdx])
            break;
      }

      /* Right calibration column */
      col = symbolCols - 1;
      for(row = 0; row < symbolRows; row += 2) {
         colorOff = ReadModuleColor(image, reg, row + 1, col, sizeIdx);
         tOff = dmtxDistanceAlongRay3(&gradient.ray, &colorOff);
         colorOn = ReadModuleColor(image, reg, row, col, sizeIdx);
         tOn = dmtxDistanceAlongRay3(&gradient.ray, &colorOn);

         if(tOn - tOff < jumpThreshold)
            errors[sizeIdx]++;

         if(errors[sizeIdx] > errors[minErrorsSizeIdx])
            break;
      }

      /* Track of which sizeIdx has the fewest errors */
      if(errors[sizeIdx] < errors[minErrorsSizeIdx])
         minErrorsSizeIdx = sizeIdx;

   } while(*(ptr++) != 0);

   reg->gradient = gradient;
   reg->sizeIdx = minErrorsSizeIdx;

   reg->symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, reg->sizeIdx);
   reg->symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, reg->sizeIdx);
   reg->mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, reg->sizeIdx);
   reg->mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, reg->sizeIdx);

   if(errors[minErrorsSizeIdx] >= 4)
      return DMTX_FAILURE;

   return DMTX_SUCCESS;
}
Ejemplo n.º 13
0
/**
 * \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;
}
Ejemplo n.º 14
0
/**
 * \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;
}
Ejemplo n.º 15
0
/**
 * @brief  XXX
 * @param  modules
 * @param  codewords
 * @param  sizeIdx
 * @param  moduleOnColor
 * @return Number of codewords read
 */
static int
ModulePlacementEcc200(unsigned char *modules, unsigned char *codewords, int sizeIdx, int moduleOnColor)
{
   int row, col, chr;
   int mappingRows, mappingCols;

   assert(moduleOnColor & (DMTX_MODULE_ON_RED | DMTX_MODULE_ON_GREEN | DMTX_MODULE_ON_BLUE));

   mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx);
   mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx);

   /* Start in the nominal location for the 8th bit of the first character */
   chr = 0;
   row = 4;
   col = 0;

   do {
      /* Repeatedly first check for one of the special corner cases */
      if((row == mappingRows) && (col == 0))
         PatternShapeSpecial1(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor);
      else if((row == mappingRows-2) && (col == 0) && (mappingCols%4))
         PatternShapeSpecial2(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor);
      else if((row == mappingRows-2) && (col == 0) && (mappingCols%8 == 4))
         PatternShapeSpecial3(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor);
      else if((row == mappingRows+4) && (col == 2) && (!(mappingCols%8)))
         PatternShapeSpecial4(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor);

      /* Sweep upward diagonally, inserting successive characters */
      do {
         if((row < mappingRows) && (col >= 0) &&
               !(modules[row*mappingCols+col] & DMTX_MODULE_VISITED))
            PatternShapeStandard(modules, mappingRows, mappingCols, row, col, &(codewords[chr++]), moduleOnColor);
         row -= 2;
         col += 2;
      } while ((row >= 0) && (col < mappingCols));
      row += 1;
      col += 3;

      /* Sweep downward diagonally, inserting successive characters */
      do {
         if((row >= 0) && (col < mappingCols) &&
               !(modules[row*mappingCols+col] & DMTX_MODULE_VISITED))
            PatternShapeStandard(modules, mappingRows, mappingCols, row, col, &(codewords[chr++]), moduleOnColor);
         row += 2;
         col -= 2;
      } while ((row < mappingRows) && (col >= 0));
      row += 3;
      col += 1;
      /* ... until the entire modules array is scanned */
   } while ((row < mappingRows) || (col < mappingCols));

   /* If lower righthand corner is untouched then fill in the fixed pattern */
   if(!(modules[mappingRows * mappingCols - 1] &
         DMTX_MODULE_VISITED)) {

      modules[mappingRows * mappingCols - 1] |= moduleOnColor;
      modules[(mappingRows * mappingCols) - mappingCols - 2] |= moduleOnColor;
   } /* XXX should this fixed pattern also be used in reading somehow? */

   /* XXX compare that chr == region->dataSize here */
   return chr; /* XXX number of codewords read off */
}
Ejemplo n.º 16
0
/**
 * \brief  Retrieve property based on symbol size
 * \param  attribute
 * \param  sizeIdx
 * \return Attribute value
 */
int
dmtxGetSymbolAttribute(int attribute, int sizeIdx)
{
    static const int symbolRows[] = { 10, 12, 14, 16, 18, 20,  22,  24,  26,
                                      32, 36, 40,  44,  48,  52,
                                      64, 72, 80,  88,  96, 104,
                                      120, 132, 144,
                                      8,  8, 12,  12,  16,  16
                                    };

    static const int symbolCols[] = { 10, 12, 14, 16, 18, 20,  22,  24,  26,
                                      32, 36, 40,  44,  48,  52,
                                      64, 72, 80,  88,  96, 104,
                                      120, 132, 144,
                                      18, 32, 26,  36,  36,  48
                                    };

    static const int dataRegionRows[] = { 8, 10, 12, 14, 16, 18, 20, 22, 24,
                                          14, 16, 18, 20, 22, 24,
                                          14, 16, 18, 20, 22, 24,
                                          18, 20, 22,
                                          6,  6, 10, 10, 14, 14
                                        };

    static const int dataRegionCols[] = { 8, 10, 12, 14, 16, 18, 20, 22, 24,
                                          14, 16, 18, 20, 22, 24,
                                          14, 16, 18, 20, 22, 24,
                                          18, 20, 22,
                                          16, 14, 24, 16, 16, 22
                                        };

    static const int horizDataRegions[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1,
                                            2, 2, 2, 2, 2, 2,
                                            4, 4, 4, 4, 4, 4,
                                            6, 6, 6,
                                            1, 2, 1, 2, 2, 2
                                          };

    static const int interleavedBlocks[] = { 1, 1, 1, 1, 1, 1, 1,  1, 1,
                                             1, 1, 1, 1,  1, 2,
                                             2, 4, 4, 4,  4, 6,
                                             6, 8, 10,
                                             1, 1, 1, 1,  1, 1
                                           };

    static const int symbolDataWords[] = { 3, 5, 8,  12,   18,   22,   30,   36,  44,
                                           62,   86,  114,  144,  174, 204,
                                           280,  368,  456,  576,  696, 816,
                                           1050, 1304, 1558,
                                           5,   10,   16,   22,   32,  49
                                         };

    static const int blockErrorWords[] = { 5, 7, 10, 12, 14, 18, 20, 24, 28,
                                           36, 42, 48, 56, 68, 42,
                                           56, 36, 48, 56, 68, 56,
                                           68, 62, 62,
                                           7, 11, 14, 18, 24, 28
                                         };

    static const int blockMaxCorrectable[] = { 2, 3, 5,  6,  7,  9,  10,  12,  14,
                                               18, 21, 24,  28,  34,  21,
                                               28, 18, 24,  28,  34,  28,
                                               34,  31,  31,
                                               3,  5,  7,   9,  12,  14
                                             };

    if(sizeIdx < 0 || sizeIdx >= DmtxSymbolSquareCount + DmtxSymbolRectCount)
        return DmtxUndefined;

    switch(attribute) {
    case DmtxSymAttribSymbolRows:
        return symbolRows[sizeIdx];
    case DmtxSymAttribSymbolCols:
        return symbolCols[sizeIdx];
    case DmtxSymAttribDataRegionRows:
        return dataRegionRows[sizeIdx];
    case DmtxSymAttribDataRegionCols:
        return dataRegionCols[sizeIdx];
    case DmtxSymAttribHorizDataRegions:
        return horizDataRegions[sizeIdx];
    case DmtxSymAttribVertDataRegions:
        return (sizeIdx < DmtxSymbolSquareCount) ? horizDataRegions[sizeIdx] : 1;
    case DmtxSymAttribMappingMatrixRows:
        return dataRegionRows[sizeIdx] *
               dmtxGetSymbolAttribute(DmtxSymAttribVertDataRegions, sizeIdx);
    case DmtxSymAttribMappingMatrixCols:
        return dataRegionCols[sizeIdx] * horizDataRegions[sizeIdx];
    case DmtxSymAttribInterleavedBlocks:
        return interleavedBlocks[sizeIdx];
    case DmtxSymAttribBlockErrorWords:
        return blockErrorWords[sizeIdx];
    case DmtxSymAttribBlockMaxCorrectable:
        return blockMaxCorrectable[sizeIdx];
    case DmtxSymAttribSymbolDataWords:
        return symbolDataWords[sizeIdx];
    case DmtxSymAttribSymbolErrorWords:
        return blockErrorWords[sizeIdx] * interleavedBlocks[sizeIdx];
    case DmtxSymAttribSymbolMaxCorrectable:
        return blockMaxCorrectable[sizeIdx] * interleavedBlocks[sizeIdx];
    }

    return DmtxUndefined;
}