Example #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;
}
Example #2
0
/**
 * @brief  Multiply vector and matrix in place
 * @param  v Vector (input and output)
 * @param  m Matrix to be multiplied
 * @return DmtxPass | DmtxFail
 */
extern int
dmtxMatrix3VMultiplyBy(DmtxVector2 *v, DmtxMatrix3 m)
{
   int success;
   DmtxVector2 vOut;

   success = dmtxMatrix3VMultiply(&vOut, v, m);
   *v = vOut;

   return success;
}
Example #3
0
/**
 * @brief  XXX
 * @param  image
 * @param  reg
 * @return DMTX_SUCCESS | DMTX_FAILURE
 */
static int
MatrixRegionAlignSecondEdge(DmtxImage *image, DmtxRegion *reg)
{
   DmtxVector2 p0[4], p1[4], pCorner[4];
   int hitCount[4] = { 0, 0, 0, 0 };
   int weakCount[4] = { 0, 0, 0, 0 };
   DmtxMatrix3 xlate, flip, shear;
   DmtxMatrix3 preFit2Raw, postRaw2Fit;
   DmtxVector2 O, T, R;
   DmtxVector2 fitO, fitT;
   DmtxVector2 oldRawO, oldRawT;
   int i, bestFit;
   DmtxRay2 rayOT, rayNew;
   double ratio, maxRatio;

   /* Corners are named using the following layout:
    *
    *  T |
    *    |
    *    |
    *    +-----
    *  O      R
    *
    */

/*fprintf(stdout, "MatrixRegionAlignSecondEdge()\n"); */

   /* Scan top edge left-to-right (shear only)

      +---   O = intersection of known edges
      |      T = farthest known point along scanned edge
      |      R = old O
   */
   dmtxMatrix3Shear(postRaw2Fit, 0.0, 1.0);
   dmtxMatrix3Shear(preFit2Raw, 0.0, -1.0);

   hitCount[0] = MatrixRegionAlignEdge(image, reg, postRaw2Fit,
         preFit2Raw, &p0[0], &p1[0], &pCorner[0], &weakCount[0]);

   /* Scan top edge right-to-left (horizontal flip and shear)

      ---+   O = intersection of known edges
         |   T = old O
         |   R = farthest known point along scanned edge
   */
   dmtxMatrix3Scale(flip, -1.0, 1.0);
   dmtxMatrix3Shear(shear, 0.0, 1.0);
   dmtxMatrix3Multiply(postRaw2Fit, flip, shear);

   dmtxMatrix3Shear(shear, 0.0, -1.0);
   dmtxMatrix3Scale(flip, -1.0, 1.0);
   dmtxMatrix3Multiply(preFit2Raw, shear, flip);

   hitCount[1] = MatrixRegionAlignEdge(image, reg, postRaw2Fit,
         preFit2Raw, &p0[1], &p1[1], &pCorner[1], &weakCount[1]);

   /* Scan bottom edge left-to-right (vertical flip and shear)

      |      O = intersection of known edges
      |      T = old T
      +---   R = farthest known point along scanned edge
   */
   dmtxMatrix3Scale(flip, 1.0, -1.0);
   dmtxMatrix3Translate(xlate, 0.0, 1.0);
   dmtxMatrix3Shear(shear, 0.0, 1.0);
   dmtxMatrix3Multiply(postRaw2Fit, flip, xlate);
   dmtxMatrix3MultiplyBy(postRaw2Fit, shear);

   dmtxMatrix3Shear(shear, 0.0, -1.0);
   dmtxMatrix3Translate(xlate, 0.0, -1.0);
   dmtxMatrix3Scale(flip, 1.0, -1.0);
   dmtxMatrix3Multiply(preFit2Raw, shear, xlate);
   dmtxMatrix3MultiplyBy(preFit2Raw, flip);

   hitCount[2] = MatrixRegionAlignEdge(image, reg, postRaw2Fit,
         preFit2Raw, &p0[2], &p1[2], &pCorner[2], &weakCount[2]);

   /* Scan bottom edge right-to-left (flip flip shear)

         |   O = intersection of known edges
         |   T = farthest known point along scanned edge
      ---+   R = old T
   */
   dmtxMatrix3Scale(flip, -1.0, -1.0);
   dmtxMatrix3Translate(xlate, 0.0, 1.0);
   dmtxMatrix3Shear(shear, 0.0, 1.0);
   dmtxMatrix3Multiply(postRaw2Fit, flip, xlate);
   dmtxMatrix3MultiplyBy(postRaw2Fit, shear);

   dmtxMatrix3Shear(shear, 0.0, -1.0);
   dmtxMatrix3Translate(xlate, 0.0, -1.0);
   dmtxMatrix3Scale(flip, -1.0, -1.0);
   dmtxMatrix3Multiply(preFit2Raw, shear, xlate);
   dmtxMatrix3MultiplyBy(preFit2Raw, flip);

   hitCount[3] = MatrixRegionAlignEdge(image, reg, postRaw2Fit,
         preFit2Raw, &p0[3], &p1[3], &pCorner[3], &weakCount[3]);

/**
Simplify StepAlongEdge() and avoid complicated error-prone counters.
Instead just find all 4 edges, and then prune out edges according to
early criteria:

   a) Exited based on step limit without touching anything (p0-p1
      length is <8 pixels)

   b) If length (p0-p1) of top is <1/8 of bottom (or vice versa)

For those that remain, choose the winner based on least variation
among module samples and proximity of color to initial edge

   for(each edge orientation option) {
      if(hitCount[i] < 3)
         option[i] = invalid;
      else if(length[p1-p0] < 8 pixels)
         option[i] = invalid;
   }

   if(option[0].valid && option[2].valid) {
      ratio = length[0]/length[2];
      if(ratio > 8)
         option[2] = invalid;
      else if(ration < 1/8)
         option[0] = invalid;
   }
   // XXX then also same thing for option[0] and option[1]

   // Determine winner among remaining options
   winner = NULL;
   currentMin = max or first;
   for(each sizeIdx) {
      for(each edge orientation option) {
         if(edge orientation is ruled out)
            continue;

         if(ColorDevianceSum(sizeIdx, matrix, gradient, &currentMin))
            winner = thisOrientation;
      }
   }
   if(winner == NULL)
      return FAILURE;

     - step along imaginary center (same # steps for each test),
       summing color difference between sample and ON color in known
       gradient. As soon as sum exceeds previous best, then eliminate
       from candidacy. record best minimum difference for each leg
       candidate. candidate with smallest diff wins.

     - maybe round-robin the tests, so the winning leg will get a foot
       in the door sooner, speeding things up significantly
*/

   /* choose orientation with highest hitCount/(weakCount + 1) ratio */
   for(i = 0; i < 4; i++) {
      ratio = (double)hitCount[i]/(weakCount[i] + 1);

      if(i == 0 || ratio > maxRatio) {
         bestFit = i;
         maxRatio = ratio;
      }
   }

   if(hitCount[bestFit] < 5)
      return DMTX_FAILURE;

   fitT.X = 0.0;
   fitT.Y = 1.0;
   dmtxMatrix3VMultiply(&oldRawT, &fitT, reg->fit2raw);

   fitO.X = 0.0;
   fitO.Y = 0.0;
   dmtxMatrix3VMultiply(&oldRawO, &fitO, reg->fit2raw);

   if(bestFit == 0 || bestFit == 1)
      oldRawT = pCorner[bestFit];
   else
      oldRawO = pCorner[bestFit];

   rayOT.p = oldRawO;
   dmtxVector2Sub(&rayOT.v, &oldRawT, &oldRawO);
   if(dmtxVector2Norm(&rayOT.v) != DMTX_SUCCESS)
      return DMTX_FAILURE;

   rayNew.p = p0[bestFit];
   dmtxVector2Sub(&rayNew.v, &p1[bestFit], &p0[bestFit]);
   if(dmtxVector2Norm(&rayNew.v) != DMTX_SUCCESS)
      return DMTX_FAILURE;

   /* New origin is always origin of both known edges */
   dmtxRay2Intersect(&O, &rayOT, &rayNew);

   if(bestFit == 0) {
      T = p1[bestFit];
      R = oldRawO;
   }
   else if(bestFit == 1) {
      T = oldRawO;
      R = p1[bestFit];
   }
   else if(bestFit == 2) {
      T = oldRawT;
      R = p1[bestFit];
   }
   else {
      assert(bestFit == 3);
      T = p1[bestFit];
      R = oldRawT;
   }

   SetCornerLoc(reg, DmtxCorner00, O);
   SetCornerLoc(reg, DmtxCorner01, T);
   SetCornerLoc(reg, DmtxCorner10, R);

   if(MatrixRegionUpdateXfrms(image, reg) != DMTX_SUCCESS)
      return DMTX_FAILURE;

   /* Skewed barcode in the bottom middle pane */
/* CALLBACK_DECODE_FUNC1(buildMatrixCallback4, dec, reg->fit2raw); */

   return DMTX_SUCCESS;
}
Example #4
0
/**
 * @brief Update transformations based on known region attributes
 * @param image
 * @param reg
 * @return DMTX_SUCCESS | DMTX_FAILURE
 */
static int
MatrixRegionUpdateXfrms(DmtxImage *image, DmtxRegion *reg)
{
   DmtxVector2 vOT, vOR, vTmp;
   double tx, ty, phi, shx, scx, scy, skx, sky;
   double dimOT, dimOR, dimTX, dimRX, ratio;
   DmtxMatrix3 m, mtxy, mphi, mshx, mscxy, msky, mskx, mTmp;
   DmtxCorners corners;

   assert((reg->corners.known & DmtxCorner00) && (reg->corners.known & DmtxCorner01));

   /* Make copy of known corners to update with temporary values */
   corners = reg->corners;

   if(corners.c00.X < 0.0 || corners.c00.Y < 0.0 ||
      corners.c01.X < 0.0 || corners.c01.Y < 0.0)
      return DMTX_FAILURE;

   if(corners.c00.X > image->width - 1 || corners.c00.Y > image->height - 1 ||
      corners.c01.X > image->width - 1 || corners.c01.Y > image->height - 1)
      return DMTX_FAILURE;

   dimOT = dmtxVector2Mag(dmtxVector2Sub(&vOT, &corners.c01, &corners.c00)); /* XXX could use MagSquared() */
   if(dimOT < 8)
      return DMTX_FAILURE;

   /* Bottom-right corner -- validate if known or create temporary value */
   if(corners.known & DmtxCorner10) {
      if(corners.c10.X < 0.0 || corners.c10.Y < 0.0 ||
            corners.c10.X > image->width - 1 ||
            corners.c10.Y > image->height - 1)
         return DMTX_FAILURE;
   }
   else {
      dmtxMatrix3Rotate(mTmp, -M_PI_2);
      dmtxMatrix3VMultiply(&vTmp, &vOT, mTmp);
      dmtxVector2Add(&corners.c10, &corners.c00, &vTmp);
   }

   dimOR = dmtxVector2Mag(dmtxVector2Sub(&vOR, &corners.c10, &corners.c00)); /* XXX could use MagSquared() */
   if(dimOR < 8)
      return DMTX_FAILURE;

   /* Solid edges are both defined now */
   if(RightAngleTrueness(corners.c01, corners.c00, corners.c10, M_PI_2) < 0.7)
      return DMTX_FAILURE;

   /* Top-right corner -- validate if known or create temporary value */
   if(corners.known & DmtxCorner11) {
      if(corners.c11.X < 0.0 || corners.c11.Y < 0.0 ||
            corners.c11.X > image->width - 1 ||
            corners.c11.Y > image->height - 1)
         return DMTX_FAILURE;
   }
   else {
      dmtxVector2Add(&corners.c11, &corners.c01, &vOR);
   }

   /* Verify that the 4 corners define a reasonably fat quadrilateral */
   dimTX = dmtxVector2Mag(dmtxVector2Sub(&vTmp, &corners.c11, &corners.c01)); /* XXX could use MagSquared() */
   dimRX = dmtxVector2Mag(dmtxVector2Sub(&vTmp, &corners.c11, &corners.c10)); /* XXX could use MagSquared() */
   if(dimTX < 8 || dimRX < 8)
      return DMTX_FAILURE;

   ratio = dimOT / dimRX;
   if(ratio < 0.5 || ratio > 2.0)
      return DMTX_FAILURE;

   ratio = dimOR / dimTX;
   if(ratio < 0.5 || ratio > 2.0)
      return DMTX_FAILURE;

   /* Test top-left corner for trueness */
   if(RightAngleTrueness(corners.c11, corners.c01, corners.c00, M_PI_2) < 0.7)
      return DMTX_FAILURE;

   /* Test bottom-right corner for trueness */
   if(RightAngleTrueness(corners.c00, corners.c10, corners.c11, M_PI_2) < 0.7)
      return DMTX_FAILURE;

   /* Test top-right corner for trueness */
   if(RightAngleTrueness(corners.c10, corners.c11, corners.c01, M_PI_2) < 0.7)
      return DMTX_FAILURE;

   /* Calculate values needed for transformations */
   tx = -1 * corners.c00.X;
   ty = -1 * corners.c00.Y;
   dmtxMatrix3Translate(mtxy, tx, ty);

   phi = atan2(vOT.X, vOT.Y);
   dmtxMatrix3Rotate(mphi, phi);

   /* Update transformation with values known so far */
   dmtxMatrix3Multiply(m, mtxy, mphi);

   dmtxMatrix3VMultiply(&vTmp, &corners.c10, m);

   shx = -vTmp.Y / vTmp.X;
   dmtxMatrix3Shear(mshx, 0.0, shx);

   scx = 1.0/vTmp.X;
   scy = 1.0/dmtxVector2Mag(&vOT);
   dmtxMatrix3Scale(mscxy, scx, scy);

   /* Update transformation with values known so far */
   dmtxMatrix3MultiplyBy(m, mshx);
   dmtxMatrix3MultiplyBy(m, mscxy);

   dmtxMatrix3VMultiply(&vTmp, &corners.c11, m);
   skx = vTmp.X;
   dmtxMatrix3LineSkewSide(mskx, 1.0, skx, 1.0);

   /* Update transformation with values known so far */
   dmtxMatrix3MultiplyBy(m, mskx);

   /* Update transformation with values known so far */
   dmtxMatrix3VMultiply(&vTmp, &corners.c11, m);
   sky = vTmp.Y;
   dmtxMatrix3LineSkewTop(msky, 1.0, sky, 1.0);

   /* Update region with final update */
   dmtxMatrix3Multiply(reg->raw2fit, m, msky);

   /* Create inverse matrix by reverse (avoid straight matrix inversion) */
   dmtxMatrix3LineSkewTopInv(msky, 1.0, sky, 1.0);
   dmtxMatrix3LineSkewSideInv(mskx, 1.0, skx, 1.0);
   dmtxMatrix3Scale(mscxy, 1.0/scx, 1.0/scy);
   dmtxMatrix3Shear(mshx, 0.0, -shx);
   dmtxMatrix3Rotate(mphi, -phi);
   dmtxMatrix3Translate(mtxy, -tx, -ty);

   dmtxMatrix3Multiply(m, msky, mskx);
   dmtxMatrix3MultiplyBy(m, mscxy);
   dmtxMatrix3MultiplyBy(m, mshx);
   dmtxMatrix3MultiplyBy(m, mphi);
   dmtxMatrix3Multiply(reg->fit2raw, m, mtxy);

   return DMTX_SUCCESS;
}
Example #5
0
/**
 * @brief  XXX
 * @param  image
 * @param  reg
 * @param  postRaw2Fit
 * @param  preFit2Raw
 * @param  p0
 * @param  p1
 * @param  pCorner
 * @param  weakCount
 * @return 3 points in raw coordinates
 */
static int
MatrixRegionAlignEdge(DmtxImage *image, DmtxRegion *reg,
      DmtxMatrix3 postRaw2Fit, DmtxMatrix3 preFit2Raw, DmtxVector2 *p0,
      DmtxVector2 *p1, DmtxVector2 *pCorner, int *weakCount)
{
   int hitCount, edgeHit, prevEdgeHit;
   DmtxVector2 c00, c10, c01;
   DmtxMatrix3 sRaw2Fit, sFit2Raw;
   DmtxVector2 forward, lateral;
   DmtxVector2 pFitExact, pFitProgress, pRawProgress, pRawExact, pLast;
   double interceptTest, intercept[8];
   DmtxVector2 adjust[8];
   double slope[8];
   int i;
   int stepsSinceStarAdjust;
   DmtxVector2 pTmp;

/*fprintf(stdout, "MatrixRegionAlignEdge()\n"); */
   dmtxMatrix3Multiply(sRaw2Fit, reg->raw2fit, postRaw2Fit);
   dmtxMatrix3Multiply(sFit2Raw, preFit2Raw, reg->fit2raw);

   /* Draw skewed image in bottom left pane */
/* CALLBACK_DECODE_FUNC1(buildMatrixCallback3, dec, sFit2Raw); */

   /* Set starting point */
   pFitProgress.X = -0.003;
   pFitProgress.Y = 0.9;
   *pCorner = pFitExact = pFitProgress;
   dmtxMatrix3VMultiply(&pRawProgress, &pFitProgress, sFit2Raw);

   /* Initialize star lines */
   for(i = 0; i < 8; i++) {
      slope[i] = tan((M_PI_2/8.0) * i);
      intercept[i] = 0.9;
      adjust[i].X = 0.0;
      adjust[i].Y = 0.9;
   }

   hitCount = 0;
   stepsSinceStarAdjust = 0;
   *weakCount = 0;

   prevEdgeHit = edgeHit = DMTX_EDGE_STEP_EXACT;

   for(;;) {
      /* XXX technically we don't need to recalculate lateral & forward once we have left the finder bar */
      dmtxMatrix3VMultiply(&pTmp, &pRawProgress, sRaw2Fit);

      /* XXX move this outside of this loop ? */
      c00 = pTmp;
      c10.X = c00.X + 1;
      c10.Y = c00.Y;
      c01.X = c00.X - 0.087155743;
      c01.Y = c00.Y + 0.996194698;

      if(dmtxMatrix3VMultiplyBy(&c00, sFit2Raw) != DMTX_SUCCESS)
         return 0;

      if(dmtxMatrix3VMultiplyBy(&c10, sFit2Raw) != DMTX_SUCCESS)
         return 0;

      if(dmtxMatrix3VMultiplyBy(&c01, sFit2Raw) != DMTX_SUCCESS)
         return 0;

      if(RightAngleTrueness(c01, c00, c10, M_PI) < 0.1) {
         /* XXX instead of just failing here, hopefully find what happened
                upstream to trigger this condition. we can probably avoid
                this earlier on, and even avoid assertion failures elsewhere */
         return 0;
      }

      /* Calculate forward and lateral directions in raw coordinates */
      dmtxVector2Sub(&forward, &c10, &c00);
      if(dmtxVector2Norm(&forward) != DMTX_SUCCESS)
         return 0;

      dmtxVector2Sub(&lateral, &c01, &c00);
      if(dmtxVector2Norm(&lateral) != DMTX_SUCCESS)
         return 0;

      prevEdgeHit = edgeHit;
      edgeHit = StepAlongEdge(image, reg, &pRawProgress, &pRawExact, forward, lateral);
      dmtxMatrix3VMultiply(&pFitProgress, &pRawProgress, sRaw2Fit);

      if(edgeHit == DMTX_EDGE_STEP_EXACT) {
/**
         if(prevEdgeHit == DMTX_EDGE_STEP_TOO_WEAK) <-- XXX REVIST LATER ... doesn't work
            hitCount++;
*/
         hitCount++;

         dmtxMatrix3VMultiply(&pFitExact, &pRawExact, sRaw2Fit);

         /* Adjust star lines upward (non-vertical) */
         for(i = 0; i < 8; i++) {
            interceptTest = pFitExact.Y - slope[i] * pFitExact.X;
            if(interceptTest > intercept[i]) {
               intercept[i] = interceptTest;
               adjust[i] = pFitExact;
               stepsSinceStarAdjust = 0;

               /* XXX still "turning corner" but not as bad anymore */
               if(i == 7) {
                  *pCorner = pFitExact;
/*                CALLBACK_DECODE_FUNC4(plotPointCallback, dec, pRawExact, 1, 1, DMTX_DISPLAY_POINT); */
               }

               if(i == 0) {
                  pLast = pFitExact;
/*                CALLBACK_DECODE_FUNC4(plotPointCallback, dec, pRawExact, 1, 1, DMTX_DISPLAY_POINT); */
               }
            }
         }

         /* Draw edge hits along skewed edge in bottom left pane */
/*       CALLBACK_DECODE_FUNC4(xfrmPlotPointCallback, dec, pFitExact, NULL, 4, DMTX_DISPLAY_POINT); */
      }
      else if(edgeHit == DMTX_EDGE_STEP_TOO_WEAK) {
         stepsSinceStarAdjust++;
         if(prevEdgeHit == DMTX_EDGE_STEP_TOO_WEAK)
            (*weakCount)++;
      }

      /* XXX also change stepsSinceNear and use this in the break condition */
      if(hitCount >= 20 && stepsSinceStarAdjust > hitCount)
         break;

      if(pFitProgress.X > 1.0) {
/*       CALLBACK_DECODE_FUNC4(plotPointCallback, dec, pRawProgress, 1, 1, DMTX_DISPLAY_SQUARE); */
         break;
      }

      if(pRawProgress.X < 1 || pRawProgress.X > image->width - 1 ||
         pRawProgress.Y < 1 || pRawProgress.Y > image->height - 1)
         break;
   }

   /* Find lowest available horizontal starline adjustment */
   for(i = 0; i < 8; i++) {
      if(adjust[i].X < 0.1)
         break;
   }
   if(i == -1)
      return 0;

   *p0 = adjust[i];

   /* Find highest available non-horizontal starline adjustment */
   for(i = 7; i > 1; i--) {
      if(adjust[i].X > 0.8)
         break;
   }
   if(i == -1)
      return 0;

   *p1 = adjust[i];

   if(fabs(p0->X - p1->X) < 0.1 || p0->Y < 0.2 || p1->Y < 0.2) {
      return 0;
   }

   dmtxMatrix3VMultiplyBy(pCorner, sFit2Raw);
   dmtxMatrix3VMultiplyBy(p0, sFit2Raw);
   dmtxMatrix3VMultiplyBy(p1, sFit2Raw);

   return hitCount;
}
Example #6
0
/**
 * \brief  Write encoded message to image
 * \param  enc
 * \return void
 */
static void
PrintPattern(DmtxEncode *enc)
{
   int i, j;
   int symbolRow, symbolCol;
   int pixelRow, pixelCol;
   int moduleStatus;
   size_t rowSize, height;
   int rgb[3];
   double sxy, txy;
   DmtxMatrix3 m1, m2;
   DmtxVector2 vIn, vOut;

   txy = enc->marginSize;
   sxy = 1.0/enc->moduleSize;

   dmtxMatrix3Translate(m1, -txy, -txy);
   dmtxMatrix3Scale(m2, sxy, -sxy);
   dmtxMatrix3Multiply(enc->xfrm, m1, m2);

   dmtxMatrix3Translate(m1, txy, txy);
   dmtxMatrix3Scale(m2, enc->moduleSize, enc->moduleSize);
   dmtxMatrix3Multiply(enc->rxfrm, m2, m1);

   rowSize = dmtxImageGetProp(enc->image, DmtxPropRowSizeBytes);
   height = dmtxImageGetProp(enc->image, DmtxPropHeight);

   memset(enc->image->pxl, 0xff, rowSize * height);

   for(symbolRow = 0; symbolRow < enc->region.symbolRows; symbolRow++) {
      for(symbolCol = 0; symbolCol < enc->region.symbolCols; symbolCol++) {

         vIn.X = symbolCol;
         vIn.Y = symbolRow;

         dmtxMatrix3VMultiply(&vOut, &vIn, enc->rxfrm);

         pixelCol = (int)(vOut.X);
         pixelRow = (int)(vOut.Y);

         moduleStatus = dmtxSymbolModuleStatus(enc->message,
               enc->region.sizeIdx, symbolRow, symbolCol);

		 if (enc->image->bytesPerPixel == 1)
		 {
			 for(i = pixelRow; i < pixelRow + enc->moduleSize; i++) {
				for(j = pixelCol; j < pixelCol + enc->moduleSize; j++) {
				   rgb[0] = ((moduleStatus & DmtxModuleOnRed) != 0x00) ? 0 : 255;
				   dmtxImageSetPixelValue(enc->image, j, i, 0, rgb[0]);
				}
			 }
		 }
		 else
		 {
			 for(i = pixelRow; i < pixelRow + enc->moduleSize; i++) {
				 for(j = pixelCol; j < pixelCol + enc->moduleSize; j++) {
					 rgb[0] = ((moduleStatus & DmtxModuleOnRed) != 0x00) ? 0 : 255;
					 rgb[1] = ((moduleStatus & DmtxModuleOnGreen) != 0x00) ? 0 : 255;
					 rgb[2] = ((moduleStatus & DmtxModuleOnBlue) != 0x00) ? 0 : 255;
					 /*             dmtxImageSetRgb(enc->image, j, i, rgb); */
					 dmtxImageSetPixelValue(enc->image, j, i, 0, rgb[0]);
					 dmtxImageSetPixelValue(enc->image, j, i, 1, rgb[1]);
					 dmtxImageSetPixelValue(enc->image, j, i, 2, rgb[2]);
				 }
			 }
		 }
      }
   }
}