private DmtxEncode(DmtxEncode src) { this._scheme = src._scheme; this._sizeIdxRequest = src._sizeIdxRequest; this._marginSize = src._marginSize; this._moduleSize = src._moduleSize; this._pixelPacking = src._pixelPacking; this._imageFlip = src._imageFlip; this._rowPadBytes = src._rowPadBytes; this._image = src._image; this._message = src._message; this._method = src._method; this._region = src._region; }
private List <string> DecodeImage(Bitmap image, int maxResultCount, TimeSpan timeOut, bool isMosaic) { List <string> result = new List <string>(); int stride; byte[] rawImg = ImageToByteArray(image, out stride); DmtxImage dmtxImg = new DmtxImage(rawImg, image.Width, image.Height, DmtxPackOrder.DmtxPack24bppRGB); dmtxImg.RowPadBytes = stride % 3; DmtxDecode decode = new DmtxDecode(dmtxImg, 1); TimeSpan timeLeft = new TimeSpan(timeOut.Ticks); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); while (true) { if (stopWatch.Elapsed > timeOut) { break; } DmtxRegion region = decode.RegionFindNext(timeOut); if (region != null) { DmtxMessage msg = isMosaic ? decode.MosaicRegion(region, -1) : decode.MatrixRegion(region, -1); string message = Encoding.ASCII.GetString(msg.Output); message = message.Substring(0, message.IndexOf('\0')); if (!result.Contains(message)) { result.Add(message); if (result.Count >= maxResultCount) { break; } } } else { break; } } return(result); }
internal DmtxRegion(DmtxRegion src) { this._bottomAngle = src._bottomAngle; this._bottomKnown = src._bottomKnown; this._bottomLine = src._bottomLine; this._bottomLoc = src._bottomLoc; this._boundMax = src._boundMax; this._boundMin = src._boundMin; this._finalNeg = src._finalNeg; this._finalPos = src._finalPos; this._fit2raw = new DmtxMatrix3(src._fit2raw); this._flowBegin = src._flowBegin; this._jumpToNeg = src._jumpToNeg; this._jumpToPos = src._jumpToPos; this._leftAngle = src._leftAngle; this._leftKnown = src._leftKnown; this._leftLine = src._leftLine; this._leftLoc = src._leftLoc; this._locR = src._locR; this._locT = src._locT; this._mappingCols = src._mappingCols; this._mappingRows = src._mappingRows; this._offColor = src._offColor; this._onColor = src._onColor; this._polarity = src._polarity; this._raw2fit = new DmtxMatrix3(src._raw2fit); this._rightAngle = src._rightAngle; this._rightKnown = src._rightKnown; this._rightLoc = src._rightLoc; this._sizeIdx = src._sizeIdx; this._stepR = src._stepR; this._stepsTotal = src._stepsTotal; this._stepT = src._stepT; this._symbolCols = src._symbolCols; this._symbolRows = src._symbolRows; this._topAngle = src._topAngle; this._topKnown = src._topKnown; this._topLoc = src._topLoc; }
int TrailClear(DmtxRegion reg, int clearMask) { int clears; DmtxFollow follow; if (!((clearMask | 0xff) == 0xff)) { throw new Exception("TrailClear mask is invalid!"); } /* Clear "visited" bit from trail */ clears = 0; follow = FollowSeek(reg, 0); while (Math.Abs(follow.Step) <= reg.StepsTotal) { if (!((int)(follow.CurrentPtr & clearMask) != 0x00)) { throw new Exception("Error performing TrailClear"); } follow.CurrentPtr &= (byte)(clearMask ^ 0xff); follow = FollowStep(reg, follow, +1); clears++; } return clears; }
int TrailBlazeGapped(DmtxRegion reg, DmtxBresLine line, int streamDir) { bool onEdge; int distSq, distSqMax; int travel = 0; int outward = 0; int xDiff, yDiff; int steps; int stepDir = 0; int[] dirMap = { 0, 1, 2, 7, 8, 3, 6, 5, 4 }; bool err; DmtxPixelLoc beforeStep, afterStep; DmtxPointFlow flow, flowNext; DmtxPixelLoc loc0; int xStep, yStep; loc0 = line.Loc; flow = GetPointFlow(reg.FlowBegin.Plane, loc0, DmtxConstants.DmtxNeighborNone); distSqMax = (line.XDelta * line.XDelta) + (line.YDelta * line.YDelta); steps = 0; onEdge = true; beforeStep = loc0; int beforeCacheIndex = DecodeGetCache(loc0.X, loc0.Y); if (beforeCacheIndex == -1) return 0; else _cache[beforeCacheIndex] = 0; do { if (onEdge == true) { flowNext = FindStrongestNeighbor(flow, streamDir); if (flowNext.Mag == DmtxConstants.DmtxUndefined) break; err = (new DmtxBresLine(line)).GetStep(flowNext.Loc, ref travel, ref outward); if (flowNext.Mag < 50 || outward < 0 || (outward == 0 && travel < 0)) { onEdge = false; } else { line.Step(travel, outward); flow = flowNext; } } if (!onEdge) { line.Step(1, 0); flow = GetPointFlow(reg.FlowBegin.Plane, line.Loc, DmtxConstants.DmtxNeighborNone); if (flow.Mag > 50) onEdge = true; } afterStep = line.Loc; int afterCacheIndex = DecodeGetCache(afterStep.X, afterStep.Y); if (afterCacheIndex == -1) break; /* Determine step direction using pure magic */ xStep = afterStep.X - beforeStep.X; yStep = afterStep.Y - beforeStep.Y; if (Math.Abs(xStep) > 1 || Math.Abs(yStep) > 1) { throw new Exception("Invalid step directions!"); } stepDir = dirMap[3 * yStep + xStep + 4]; if (stepDir == 8) { throw new Exception("Invalid step direction!"); } if (streamDir < 0) { this._cache[beforeCacheIndex] |= (byte)(0x40 | stepDir); this._cache[afterCacheIndex] = (byte)(((stepDir + 4) % 8) << 3); } else { this._cache[beforeCacheIndex] |= (byte)(0x40 | (stepDir << 3)); this._cache[afterCacheIndex] = (byte)((stepDir + 4) % 8); } /* Guaranteed to have taken one step since top of loop */ xDiff = line.Loc.X - loc0.X; yDiff = line.Loc.Y - loc0.Y; distSq = (xDiff * xDiff) + (yDiff * yDiff); beforeStep = line.Loc; beforeCacheIndex = afterCacheIndex; steps++; } while (distSq < distSqMax); return steps; }
bool TrailBlazeContinuous(DmtxRegion reg, DmtxPointFlow flowBegin, int maxDiagonal) { int posAssigns, negAssigns, clears; int sign; int steps; DmtxPointFlow flow, flowNext; DmtxPixelLoc boundMin, boundMax; boundMin = boundMax = flowBegin.Loc; int cacheBegIndex = DecodeGetCache(flowBegin.Loc.X, flowBegin.Loc.Y); this._cache[cacheBegIndex] = 0x80 | 0x40; reg.FlowBegin = flowBegin; posAssigns = negAssigns = 0; for (sign = 1; sign >= -1; sign -= 2) { flow = flowBegin; int cacheIndex = cacheBegIndex; for (steps = 0; ; steps++) { if (maxDiagonal != DmtxConstants.DmtxUndefined && (boundMax.X - boundMin.X > maxDiagonal || boundMax.Y - boundMin.Y > maxDiagonal)) break; /* Find the strongest eligible neighbor */ flowNext = FindStrongestNeighbor(flow, sign); if (flowNext.Mag < 50) break; /* Get the neighbor's cache location */ int cacheNextIndex = DecodeGetCache(flowNext.Loc.X, flowNext.Loc.Y); if ((this._cache[cacheNextIndex] & 0x80) != 0) { throw new Exception("Error creating Trail Blaze"); } /* Mark departure from current location. If flowing downstream * (sign < 0) then departure vector here is the arrival vector * of the next location. Upstream flow uses the opposite rule. */ this._cache[cacheIndex] |= (sign < 0) ? (byte)(flowNext.Arrive) : (byte)(flowNext.Arrive << 3); /* Mark known direction for next location */ /* If testing downstream (sign < 0) then next upstream is opposite of next arrival */ /* If testing upstream (sign > 0) then next downstream is opposite of next arrival */ this._cache[cacheNextIndex] = (sign < 0) ? (byte)(((flowNext.Arrive + 4) % 8) << 3) : (byte)((flowNext.Arrive + 4) % 8); this._cache[cacheNextIndex] |= (0x80 | 0x40); /* Mark location as visited and assigned */ if (sign > 0) posAssigns++; else negAssigns++; cacheIndex = cacheNextIndex; flow = flowNext; if (flow.Loc.X > boundMax.X) boundMax.X = flow.Loc.X; else if (flow.Loc.X < boundMin.X) boundMin.X = flow.Loc.X; if (flow.Loc.Y > boundMax.Y) boundMax.Y = flow.Loc.Y; else if (flow.Loc.Y < boundMin.Y) boundMin.Y = flow.Loc.Y; /* CALLBACK_POINT_PLOT(flow.loc, (sign > 0) ? 2 : 3, 1, 2); */ } if (sign > 0) { reg.FinalPos = flow.Loc; reg.JumpToNeg = steps; } else { reg.FinalNeg = flow.Loc; reg.JumpToPos = steps; } } reg.StepsTotal = reg.JumpToPos + reg.JumpToNeg; reg.BoundMin = boundMin; reg.BoundMax = boundMax; /* Clear "visited" bit from trail */ clears = TrailClear(reg, 0x80); if (!(posAssigns + negAssigns == clears - 1)) { throw new Exception("Error cleaning after trail blaze continuous"); } /* XXX clean this up ... redundant test above */ if (maxDiagonal != DmtxConstants.DmtxUndefined && (boundMax.X - boundMin.X > maxDiagonal || boundMax.Y - boundMin.Y > maxDiagonal)) return false; return true; }
bool FindTravelLimits(DmtxRegion reg, ref DmtxBestLine line) { int i; int distSq, distSqMax; int xDiff, yDiff; bool posRunning, negRunning; int posTravel, negTravel; int posWander, posWanderMin, posWanderMax, posWanderMinLock, posWanderMaxLock; int negWander, negWanderMin, negWanderMax, negWanderMinLock, negWanderMaxLock; int cosAngle, sinAngle; DmtxFollow followPos, followNeg; DmtxPixelLoc loc0, posMax, negMax; /* line->stepBeg is already known to sit on the best Hough line */ followPos = followNeg = FollowSeek(reg, line.StepBeg); loc0 = followPos.Loc; cosAngle = DmtxConstants.rHvX[line.Angle]; sinAngle = DmtxConstants.rHvY[line.Angle]; distSqMax = 0; posMax = negMax = followPos.Loc; posTravel = negTravel = 0; posWander = posWanderMin = posWanderMax = posWanderMinLock = posWanderMaxLock = 0; negWander = negWanderMin = negWanderMax = negWanderMinLock = negWanderMaxLock = 0; for (i = 0; i < reg.StepsTotal / 2; i++) { posRunning = (i < 10 || Math.Abs(posWander) < Math.Abs(posTravel)); negRunning = (i < 10 || Math.Abs(negWander) < Math.Abs(negTravel)); if (posRunning) { xDiff = followPos.Loc.X - loc0.X; yDiff = followPos.Loc.Y - loc0.Y; posTravel = (cosAngle * xDiff) + (sinAngle * yDiff); posWander = (cosAngle * yDiff) - (sinAngle * xDiff); if (posWander >= -3 * 256 && posWander <= 3 * 256) { distSq = DistanceSquared(followPos.Loc, negMax); if (distSq > distSqMax) { posMax = followPos.Loc; distSqMax = distSq; line.StepPos = followPos.Step; line.LocPos = followPos.Loc; posWanderMinLock = posWanderMin; posWanderMaxLock = posWanderMax; } } else { posWanderMin = DmtxCommon.Min<int>(posWanderMin, posWander); posWanderMax = DmtxCommon.Max<int>(posWanderMax, posWander); } } else if (!negRunning) { break; } if (negRunning) { xDiff = followNeg.Loc.X - loc0.X; yDiff = followNeg.Loc.Y - loc0.Y; negTravel = (cosAngle * xDiff) + (sinAngle * yDiff); negWander = (cosAngle * yDiff) - (sinAngle * xDiff); if (negWander >= -3 * 256 && negWander < 3 * 256) { distSq = DistanceSquared(followNeg.Loc, posMax); if (distSq > distSqMax) { negMax = followNeg.Loc; distSqMax = distSq; line.StepNeg = followNeg.Step; line.LocNeg = followNeg.Loc; negWanderMinLock = negWanderMin; negWanderMaxLock = negWanderMax; } } else { negWanderMin = DmtxCommon.Min<int>(negWanderMin, negWander); negWanderMax = DmtxCommon.Max<int>(negWanderMax, negWander); } } else if (!posRunning) { break; } followPos = FollowStep(reg, followPos, +1); followNeg = FollowStep(reg, followNeg, -1); } line.Devn = DmtxCommon.Max<int>(posWanderMaxLock - posWanderMinLock, negWanderMaxLock - negWanderMinLock) / 256; line.DistSq = distSqMax; return true; }
int CountJumpTally(DmtxRegion reg, int xStart, int yStart, DmtxDirection dir) { int x, xInc = 0; int y, yInc = 0; int state = DmtxConstants.DmtxModuleOn; int jumpCount = 0; int jumpThreshold; int tModule, tPrev; bool darkOnLight; int color; if (xStart != 0 && yStart != 0) { throw new Exception("CountJumpTally failed, xStart or yStart must be zero!"); } if (dir == DmtxDirection.DmtxDirRight) { xInc = 1; } else { yInc = 1; } if (xStart == -1 || xStart == reg.SymbolCols || yStart == -1 || yStart == reg.SymbolRows) { state = DmtxConstants.DmtxModuleOff; } darkOnLight = (reg.OffColor > reg.OnColor); jumpThreshold = Math.Abs((int)(0.4 * (reg.OnColor - reg.OffColor) + 0.5)); color = ReadModuleColor(reg, yStart, xStart, reg.SizeIdx, reg.FlowBegin.Plane); tModule = (darkOnLight) ? reg.OffColor - color : color - reg.OffColor; for (x = xStart + xInc, y = yStart + yInc; (dir == DmtxDirection.DmtxDirRight && x < reg.SymbolCols) || (dir == DmtxDirection.DmtxDirUp && y < reg.SymbolRows); x += xInc, y += yInc) { tPrev = tModule; color = ReadModuleColor(reg, y, x, reg.SizeIdx, reg.FlowBegin.Plane); tModule = (darkOnLight) ? reg.OffColor - color : color - reg.OffColor; if (state == DmtxConstants.DmtxModuleOff) { if (tModule > tPrev + jumpThreshold) { jumpCount++; state = DmtxConstants.DmtxModuleOn; } } else { if (tModule < tPrev - jumpThreshold) { jumpCount++; state = DmtxConstants.DmtxModuleOff; } } } return jumpCount; }
private int ReadModuleColor(DmtxRegion reg, int symbolRow, int symbolCol, DmtxSymbolSize sizeIdx, int colorPlane) { int i; int symbolRows, symbolCols; int color, colorTmp; 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 = new DmtxVector2(); symbolRows = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolRows, sizeIdx); symbolCols = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolCols, sizeIdx); colorTmp = color = 0; for (i = 0; i < 5; i++) { p.X = (1.0 / symbolCols) * (symbolCol + sampleX[i]); p.Y = (1.0 / symbolRows) * (symbolRow + sampleY[i]); p *= reg.Fit2raw; GetPixelValue((int)(p.X + 0.5), (int)(p.Y + 0.5), colorPlane, ref colorTmp); color += colorTmp; } return color / 5; }
private bool PopulateArrayFromMatrix(DmtxRegion reg, DmtxMessage msg) { /* Capture number of regions present in barcode */ int xRegionTotal = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribHorizDataRegions, reg.SizeIdx); int yRegionTotal = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribVertDataRegions, reg.SizeIdx); /* Capture region dimensions (not including border modules) */ int mapWidth = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribDataRegionCols, reg.SizeIdx); int mapHeight = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribDataRegionRows, reg.SizeIdx); int weightFactor = 2 * (mapHeight + mapWidth + 2); if (weightFactor <= 0) { throw new ArgumentException("PopulateArrayFromMatrix error: Weight Factor must be greater 0"); } /* Tally module changes for each region in each direction */ for (int yRegionCount = 0; yRegionCount < yRegionTotal; yRegionCount++) { /* Y location of mapping region origin in symbol coordinates */ int yOrigin = yRegionCount * (mapHeight + 2) + 1; for (int xRegionCount = 0; xRegionCount < xRegionTotal; xRegionCount++) { int[,] tally = new int[24, 24]; /* Large enough to map largest single region */ /* X location of mapping region origin in symbol coordinates */ int xOrigin = xRegionCount * (mapWidth + 2) + 1; for (int i = 0; i < 24; i++) { for (int j = 0; j < 24; j++) { tally[i, j] = 0; } } TallyModuleJumps(reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirection.DmtxDirUp); TallyModuleJumps(reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirection.DmtxDirLeft); TallyModuleJumps(reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirection.DmtxDirDown); TallyModuleJumps(reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirection.DmtxDirRight); /* Decide module status based on final tallies */ for (int mapRow = 0; mapRow < mapHeight; mapRow++) { for (int mapCol = 0; mapCol < mapWidth; mapCol++) { int rowTmp = (yRegionCount * mapHeight) + mapRow; rowTmp = yRegionTotal * mapHeight - rowTmp - 1; int colTmp = (xRegionCount * mapWidth) + mapCol; int idx = (rowTmp * xRegionTotal * mapWidth) + colTmp; if (tally[mapRow, mapCol] / (double)weightFactor >= 0.5) msg.Array[idx] = (byte)DmtxConstants.DmtxModuleOnRGB; else msg.Array[idx] = (byte)DmtxConstants.DmtxModuleOff; msg.Array[idx] |= (byte)DmtxConstants.DmtxModuleAssigned; } } } } return true; }
bool MatrixRegionOrientation(DmtxRegion reg, DmtxPointFlow begin) { int cross; int minArea; int scale; DmtxSymbolSize symbolShape; int maxDiagonal; bool err; DmtxBestLine line1x, line2x; DmtxBestLine line2n, line2p; DmtxFollow fTmp; if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolSquareAuto || (this._sizeIdxExpected >= DmtxSymbolSize.DmtxSymbol10x10 && this._sizeIdxExpected <= DmtxSymbolSize.DmtxSymbol144x144)) symbolShape = DmtxSymbolSize.DmtxSymbolSquareAuto; else if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolRectAuto || (this._sizeIdxExpected >= DmtxSymbolSize.DmtxSymbol8x18 && this._sizeIdxExpected <= DmtxSymbolSize.DmtxSymbol16x48)) symbolShape = DmtxSymbolSize.DmtxSymbolRectAuto; else symbolShape = DmtxSymbolSize.DmtxSymbolShapeAuto; if (_edgeMax != DmtxConstants.DmtxUndefined) { if (symbolShape == DmtxSymbolSize.DmtxSymbolRectAuto) maxDiagonal = (int)(1.23 * _edgeMax + 0.5); /* sqrt(5/4) + 10% */ else maxDiagonal = (int)(1.56 * _edgeMax + 0.5); /* sqrt(2) + 10% */ } else { maxDiagonal = DmtxConstants.DmtxUndefined; } /* Follow to end in both directions */ err = TrailBlazeContinuous(reg, begin, maxDiagonal); if (err == false || reg.StepsTotal < 40) { TrailClear(reg, 0x40); return false; } /* Filter out region candidates that are smaller than expected */ if (this._edgeMin != DmtxConstants.DmtxUndefined) { scale = _scale; if (symbolShape == DmtxSymbolSize.DmtxSymbolSquareAuto) minArea = (this._edgeMin * this._edgeMin) / (scale * scale); else minArea = (2 * this._edgeMin * this._edgeMin) / (scale * scale); if ((reg.BoundMax.X - reg.BoundMin.X) * (reg.BoundMax.Y - reg.BoundMin.Y) < minArea) { TrailClear(reg, 0x40); return false; } } line1x = FindBestSolidLine(reg, 0, 0, 1, DmtxConstants.DmtxUndefined); if (line1x.Mag < 5) { TrailClear(reg, 0x40); return false; } err = FindTravelLimits(reg, ref line1x); if (line1x.DistSq < 100 || line1x.Devn * 10 >= Math.Sqrt((double)line1x.DistSq)) { TrailClear(reg, 0x40); return false; } if (!(line1x.StepPos >= line1x.StepNeg)) { throw new Exception("Error calculating matrix region orientation"); } fTmp = FollowSeek(reg, line1x.StepPos + 5); line2p = FindBestSolidLine(reg, fTmp.Step, line1x.StepNeg, 1, line1x.Angle); fTmp = FollowSeek(reg, line1x.StepNeg - 5); line2n = FindBestSolidLine(reg, fTmp.Step, line1x.StepPos, -1, line1x.Angle); if (DmtxCommon.Max<int>(line2p.Mag, line2n.Mag) < 5) return false; if (line2p.Mag > line2n.Mag) { line2x = line2p; err = FindTravelLimits(reg, ref line2x); if (line2x.DistSq < 100 || line2x.Devn * 10 >= Math.Sqrt((double)line2x.DistSq)) return false; cross = ((line1x.LocPos.X - line1x.LocNeg.X) * (line2x.LocPos.Y - line2x.LocNeg.Y)) - ((line1x.LocPos.Y - line1x.LocNeg.Y) * (line2x.LocPos.X - line2x.LocNeg.X)); if (cross > 0) { /* Condition 2 */ reg.Polarity = +1; reg.LocR = line2x.LocPos; reg.StepR = line2x.StepPos; reg.LocT = line1x.LocNeg; reg.StepT = line1x.StepNeg; reg.LeftLoc = line1x.LocBeg; reg.LeftAngle = line1x.Angle; reg.BottomLoc = line2x.LocBeg; reg.BottomAngle = line2x.Angle; reg.LeftLine = line1x; reg.BottomLine = line2x; } else { /* Condition 3 */ reg.Polarity = -1; reg.LocR = line1x.LocNeg; reg.StepR = line1x.StepNeg; reg.LocT = line2x.LocPos; reg.StepT = line2x.StepPos; reg.LeftLoc = line2x.LocBeg; reg.LeftAngle = line2x.Angle; reg.BottomLoc = line1x.LocBeg; reg.BottomAngle = line1x.Angle; reg.LeftLine = line2x; reg.BottomLine = line1x; } } else { line2x = line2n; err = FindTravelLimits(reg, ref line2x); if (line2x.DistSq < 100 || line2x.Devn / Math.Sqrt((double)line2x.DistSq) >= 0.1) return false; cross = ((line1x.LocNeg.X - line1x.LocPos.X) * (line2x.LocNeg.Y - line2x.LocPos.Y)) - ((line1x.LocNeg.Y - line1x.LocPos.Y) * (line2x.LocNeg.X - line2x.LocPos.X)); if (cross > 0) { /* Condition 1 */ reg.Polarity = -1; reg.LocR = line2x.LocNeg; reg.StepR = line2x.StepNeg; reg.LocT = line1x.LocPos; reg.StepT = line1x.StepPos; reg.LeftLoc = line1x.LocBeg; reg.LeftAngle = line1x.Angle; reg.BottomLoc = line2x.LocBeg; reg.BottomAngle = line2x.Angle; reg.LeftLine = line1x; reg.BottomLine = line2x; } else { /* Condition 4 */ reg.Polarity = +1; reg.LocR = line1x.LocPos; reg.StepR = line1x.StepPos; reg.LocT = line2x.LocNeg; reg.StepT = line2x.StepNeg; reg.LeftLoc = line2x.LocBeg; reg.LeftAngle = line2x.Angle; reg.BottomLoc = line1x.LocBeg; reg.BottomAngle = line1x.Angle; reg.LeftLine = line2x; reg.BottomLine = line1x; } } reg.LeftKnown = reg.BottomKnown = 1; return true; }
bool MatrixRegionFindSize(DmtxRegion reg) { int row, col; DmtxSymbolSize sizeIdxBeg, sizeIdxEnd; DmtxSymbolSize sizeIdx, bestSizeIdx; int symbolRows, symbolCols; int jumpCount, errors; int color; int colorOnAvg, bestColorOnAvg; int colorOffAvg, bestColorOffAvg; int contrast, bestContrast; DmtxImage img; img = this._image; bestSizeIdx = DmtxSymbolSize.DmtxSymbolShapeAuto; bestContrast = 0; bestColorOnAvg = bestColorOffAvg = 0; if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolShapeAuto) { sizeIdxBeg = 0; sizeIdxEnd = (DmtxSymbolSize)(DmtxConstants.DmtxSymbolSquareCount + DmtxConstants.DmtxSymbolRectCount); } else if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolSquareAuto) { sizeIdxBeg = 0; sizeIdxEnd = (DmtxSymbolSize)DmtxConstants.DmtxSymbolSquareCount; } else if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolRectAuto) { sizeIdxBeg = (DmtxSymbolSize)DmtxConstants.DmtxSymbolSquareCount; sizeIdxEnd = (DmtxSymbolSize)(DmtxConstants.DmtxSymbolSquareCount + DmtxConstants.DmtxSymbolRectCount); } else { sizeIdxBeg = this._sizeIdxExpected; sizeIdxEnd = this._sizeIdxExpected + 1; } /* Test each barcode size to find best contrast in calibration modules */ for (sizeIdx = sizeIdxBeg; sizeIdx < sizeIdxEnd; sizeIdx++) { symbolRows = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolRows, sizeIdx); symbolCols = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolCols, sizeIdx); colorOnAvg = colorOffAvg = 0; /* Sum module colors along horizontal calibration bar */ row = symbolRows - 1; for (col = 0; col < symbolCols; col++) { color = ReadModuleColor(reg, row, col, sizeIdx, reg.FlowBegin.Plane); if ((col & 0x01) != 0x00) colorOffAvg += color; else colorOnAvg += color; } /* Sum module colors along vertical calibration bar */ col = symbolCols - 1; for (row = 0; row < symbolRows; row++) { color = ReadModuleColor(reg, row, col, sizeIdx, reg.FlowBegin.Plane); if ((row & 0x01) != 0x00) colorOffAvg += color; else colorOnAvg += color; } colorOnAvg = (colorOnAvg * 2) / (symbolRows + symbolCols); colorOffAvg = (colorOffAvg * 2) / (symbolRows + symbolCols); contrast = Math.Abs(colorOnAvg - colorOffAvg); if (contrast < 20) continue; if (contrast > bestContrast) { bestContrast = contrast; bestSizeIdx = sizeIdx; bestColorOnAvg = colorOnAvg; bestColorOffAvg = colorOffAvg; } } /* If no sizes produced acceptable contrast then call it quits */ if (bestSizeIdx == DmtxSymbolSize.DmtxSymbolShapeAuto || bestContrast < 20) return false; reg.SizeIdx = bestSizeIdx; reg.OnColor = bestColorOnAvg; reg.OffColor = bestColorOffAvg; reg.SymbolRows = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolRows, reg.SizeIdx); reg.SymbolCols = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolCols, reg.SizeIdx); reg.MappingRows = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribMappingMatrixRows, reg.SizeIdx); reg.MappingCols = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribMappingMatrixCols, reg.SizeIdx); /* Tally jumps on horizontal calibration bar to verify sizeIdx */ jumpCount = CountJumpTally(reg, 0, reg.SymbolRows - 1, DmtxDirection.DmtxDirRight); errors = Math.Abs(1 + jumpCount - reg.SymbolCols); if (jumpCount < 0 || errors > 2) return false; /* Tally jumps on vertical calibration bar to verify sizeIdx */ jumpCount = CountJumpTally(reg, reg.SymbolCols - 1, 0, DmtxDirection.DmtxDirUp); errors = Math.Abs(1 + jumpCount - reg.SymbolRows); if (jumpCount < 0 || errors > 2) return false; /* Tally jumps on horizontal finder bar to verify sizeIdx */ errors = CountJumpTally(reg, 0, 0, DmtxDirection.DmtxDirRight); if (jumpCount < 0 || errors > 2) return false; /* Tally jumps on vertical finder bar to verify sizeIdx */ errors = CountJumpTally(reg, 0, 0, DmtxDirection.DmtxDirUp); if (errors < 0 || errors > 2) return false; /* Tally jumps on surrounding whitespace, else fail */ errors = CountJumpTally(reg, 0, -1, DmtxDirection.DmtxDirRight); if (errors < 0 || errors > 2) return false; errors = CountJumpTally(reg, -1, 0, DmtxDirection.DmtxDirUp); if (errors < 0 || errors > 2) return false; errors = CountJumpTally(reg, 0, reg.SymbolRows, DmtxDirection.DmtxDirRight); if (errors < 0 || errors > 2) return false; errors = CountJumpTally(reg, reg.SymbolCols, 0, DmtxDirection.DmtxDirUp); if (errors < 0 || errors > 2) return false; return true; }
bool MatrixRegionAlignCalibEdge(DmtxRegion reg, DmtxEdge edgeLoc) { int streamDir; int steps; int avoidAngle; DmtxSymbolSize symbolShape; DmtxVector2 pTmp = new DmtxVector2(); DmtxPixelLoc loc0 = new DmtxPixelLoc(); DmtxPixelLoc loc1 = new DmtxPixelLoc(); DmtxPixelLoc locOrigin = new DmtxPixelLoc(); DmtxBresLine line; DmtxFollow follow; DmtxBestLine bestLine; /* Determine pixel coordinates of origin */ pTmp.X = 0.0; pTmp.Y = 0.0; pTmp *= reg.Fit2raw; locOrigin.X = (int)(pTmp.X + 0.5); locOrigin.Y = (int)(pTmp.Y + 0.5); if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolSquareAuto || (this._sizeIdxExpected >= DmtxSymbolSize.DmtxSymbol10x10 && this._sizeIdxExpected <= DmtxSymbolSize.DmtxSymbol144x144)) symbolShape = DmtxSymbolSize.DmtxSymbolSquareAuto; else if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolRectAuto || (this._sizeIdxExpected >= DmtxSymbolSize.DmtxSymbol8x18 && this._sizeIdxExpected <= DmtxSymbolSize.DmtxSymbol16x48)) symbolShape = DmtxSymbolSize.DmtxSymbolRectAuto; else symbolShape = DmtxSymbolSize.DmtxSymbolShapeAuto; /* Determine end locations of test line */ if (edgeLoc == DmtxEdge.DmtxEdgeTop) { streamDir = reg.Polarity * -1; avoidAngle = reg.LeftLine.Angle; follow = FollowSeekLoc(reg.LocT); pTmp.X = 0.8; pTmp.Y = (symbolShape == DmtxSymbolSize.DmtxSymbolRectAuto) ? 0.2 : 0.6; } else { streamDir = reg.Polarity; avoidAngle = reg.BottomLine.Angle; follow = FollowSeekLoc(reg.LocR); pTmp.X = (symbolShape == DmtxSymbolSize.DmtxSymbolSquareAuto) ? 0.7 : 0.9; pTmp.Y = 0.8; } pTmp *= reg.Fit2raw; loc1.X = (int)(pTmp.X + 0.5); loc1.Y = (int)(pTmp.Y + 0.5); loc0 = follow.Loc; line = new DmtxBresLine(loc0, loc1, locOrigin); steps = TrailBlazeGapped(reg, line, streamDir); bestLine = FindBestSolidLine2(loc0, steps, streamDir, avoidAngle); if (bestLine.Mag < 5) { ; } if (edgeLoc == DmtxEdge.DmtxEdgeTop) { reg.TopKnown = 1; reg.TopAngle = bestLine.Angle; reg.TopLoc = bestLine.LocBeg; } else { reg.RightKnown = 1; reg.RightAngle = bestLine.Angle; reg.RightLoc = bestLine.LocBeg; } return true; }
DmtxFollow FollowStep(DmtxRegion reg, DmtxFollow followBeg, int sign) { int patternIdx; int stepMod; int factor; DmtxFollow follow = new DmtxFollow(); if (Math.Abs(sign) != 1) { throw new Exception("Invalid parameter 'sign', can only be -1 or +1"); } factor = reg.StepsTotal + 1; if (sign > 0) stepMod = (factor + (followBeg.Step % factor)) % factor; else stepMod = (factor - (followBeg.Step % factor)) % factor; /* End of positive trail -- magic jump */ if (sign > 0 && stepMod == reg.JumpToNeg) { follow.Loc = reg.FinalNeg; } /* End of negative trail -- magic jump */ else if (sign < 0 && stepMod == reg.JumpToPos) { follow.Loc = reg.FinalPos; } /* Trail in progress -- normal jump */ else { patternIdx = (sign < 0) ? followBeg.Neighbor & 0x07 : ((followBeg.Neighbor & 0x38) >> 3); follow.Loc = new DmtxPixelLoc() { X = followBeg.Loc.X + DmtxConstants.DmtxPatternX[patternIdx], Y = followBeg.Loc.Y + DmtxConstants.DmtxPatternY[patternIdx] }; } follow.Step = followBeg.Step + sign; follow.Ptr = this._cache; follow.PtrIndex = DecodeGetCache(follow.Loc.X, follow.Loc.Y); return follow; }
internal DmtxMessage MatrixRegion(DmtxRegion reg, int fix) { DmtxMessage result = new DmtxMessage(reg.SizeIdx, DmtxFormat.Matrix); DmtxVector2 topLeft = new DmtxVector2(); DmtxVector2 topRight = new DmtxVector2(); DmtxVector2 bottomLeft = new DmtxVector2(); DmtxVector2 bottomRight = new DmtxVector2(); DmtxPixelLoc pxTopLeft = new DmtxPixelLoc(); DmtxPixelLoc pxTopRight = new DmtxPixelLoc(); DmtxPixelLoc pxBottomLeft = new DmtxPixelLoc(); DmtxPixelLoc pxBottomRight = new DmtxPixelLoc(); if (!PopulateArrayFromMatrix(reg, result)) { throw new Exception("Populating Array from matrix failed!"); } /* maybe place remaining logic into new dmtxDecodePopulatedArray() function so other people can pass in their own arrays */ ModulePlacementEcc200(result.Array, result.Code, reg.SizeIdx, DmtxConstants.DmtxModuleOnRed | DmtxConstants.DmtxModuleOnGreen | DmtxConstants.DmtxModuleOnBlue); if (DmtxCommon.DecodeCheckErrors(result.Code, 0, reg.SizeIdx, fix) != true) { return null; } topLeft.X = bottomLeft.X = topLeft.Y = topRight.Y = -0.1; topRight.X = bottomRight.X = bottomLeft.Y = bottomRight.Y = 1.1; topLeft *= reg.Fit2raw; topRight *= reg.Fit2raw; bottomLeft *= reg.Fit2raw; bottomLeft *= 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(pxTopLeft, pxTopRight, pxBottomRight, pxBottomLeft); result.DecodeDataStream(reg.SizeIdx, null); return result; }
internal DmtxMessage MosaicRegion(DmtxRegion reg, int fix) { DmtxMessage oMsg; int colorPlane = reg.FlowBegin.Plane; reg.FlowBegin.Plane = 0; /* kind of a hack */ DmtxMessage rMsg = MatrixRegion(reg, fix); reg.FlowBegin.Plane = 1; /* kind of a hack */ DmtxMessage gMsg = MatrixRegion(reg, fix); reg.FlowBegin.Plane = 2; /* kind of a hack */ DmtxMessage bMsg = MatrixRegion(reg, fix); reg.FlowBegin.Plane = colorPlane; oMsg = new DmtxMessage(reg.SizeIdx, DmtxFormat.Mosaic); List<byte> totalMessage = new List<byte>(); for (int i = 0; i < bMsg.OutputSize; i++) { if (bMsg.Output[i] == 0) { break; } totalMessage.Add(bMsg.Output[i]); } for (int i = 0; i < gMsg.OutputSize; i++) { if (gMsg.Output[i] == 0) { break; } totalMessage.Add(gMsg.Output[i]); } for (int i = 0; i < rMsg.OutputSize; i++) { if (rMsg.Output[i] == 0) { break; } totalMessage.Add(rMsg.Output[i]); } totalMessage.Add(0); oMsg.Output = totalMessage.ToArray(); return oMsg; }
DmtxRegion RegionScanPixel(int x, int y) { DmtxRegion reg = new DmtxRegion(); DmtxPointFlow flowBegin; DmtxPixelLoc loc = new DmtxPixelLoc(); loc.X = x; loc.Y = y; int cacheIndex = this.DecodeGetCache(loc.X, loc.Y); if (cacheIndex == -1) return null; if (this._cache[cacheIndex] != 0x00) return null; /* Test for presence of any reasonable edge at this location */ flowBegin = MatrixRegionSeekEdge(loc); if (flowBegin.Mag < (int)(this._edgeThresh * 7.65 + 0.5)) return null; /* Determine barcode orientation */ if (MatrixRegionOrientation(reg, flowBegin) == false) return null; if (RegionUpdateXfrms(reg) == false) return null; /* Define top edge */ if (MatrixRegionAlignCalibEdge(reg, DmtxEdge.DmtxEdgeTop) == false) return null; if (RegionUpdateXfrms(reg) == false) return null; /* Define right edge */ if (MatrixRegionAlignCalibEdge(reg, DmtxEdge.DmtxEdgeRight) == false) return null; if (RegionUpdateXfrms(reg) == false) return null; //CALLBACK_MATRIX(®); /* Calculate the best fitting symbol size */ if (MatrixRegionFindSize(reg) == false) return null; /* Found a valid matrix region */ return new DmtxRegion(reg); }
DmtxBestLine FindBestSolidLine(DmtxRegion reg, int step0, int step1, int streamDir, int houghAvoid) { int[,] hough = new int[3, DmtxConstants.DmtxHoughRes]; int houghMin, houghMax; char[] houghTest = new char[DmtxConstants.DmtxHoughRes]; int i; int step; int sign = 0; int tripSteps = 0; int xDiff, yDiff; int dH; DmtxFollow follow; DmtxBestLine line = new DmtxBestLine(); DmtxPixelLoc rHp; int angleBest = 0; int hOffset = 0; int hOffsetBest = 0; /* Always follow path flowing away from the trail start */ if (step0 != 0) { if (step0 > 0) { sign = +1; tripSteps = (step1 - step0 + reg.StepsTotal) % reg.StepsTotal; } else { sign = -1; tripSteps = (step0 - step1 + reg.StepsTotal) % reg.StepsTotal; } if (tripSteps == 0) tripSteps = reg.StepsTotal; } else if (step1 != 0) { sign = (step1 > 0) ? +1 : -1; tripSteps = Math.Abs(step1); } else if (step1 == 0) { sign = +1; tripSteps = reg.StepsTotal; } if (sign != streamDir) { throw new Exception("Sign must equal stream direction!"); } follow = FollowSeek(reg, step0); rHp = follow.Loc; line.StepBeg = line.StepPos = line.StepNeg = step0; line.LocBeg = follow.Loc; line.LocPos = follow.Loc; line.LocNeg = follow.Loc; /* Predetermine which angles to test */ for (i = 0; i < DmtxConstants.DmtxHoughRes; i++) { if (houghAvoid == DmtxConstants.DmtxUndefined) { houghTest[i] = (char)1; } else { houghMin = (houghAvoid + DmtxConstants.DmtxHoughRes / 6) % DmtxConstants.DmtxHoughRes; houghMax = (houghAvoid - DmtxConstants.DmtxHoughRes / 6 + DmtxConstants.DmtxHoughRes) % DmtxConstants.DmtxHoughRes; if (houghMin > houghMax) houghTest[i] = (i > houghMin || i < houghMax) ? (char)1 : (char)0; else houghTest[i] = (i > houghMin && i < houghMax) ? (char)1 : (char)0; } } /* Test each angle for steps along path */ for (step = 0; step < tripSteps; step++) { xDiff = follow.Loc.X - rHp.X; yDiff = follow.Loc.Y - rHp.Y; /* Increment Hough accumulator */ for (i = 0; i < DmtxConstants.DmtxHoughRes; i++) { if ((int)houghTest[i] == 0) continue; dH = (DmtxConstants.rHvX[i] * yDiff) - (DmtxConstants.rHvY[i] * xDiff); if (dH >= -384 && dH <= 384) { if (dH > 128) hOffset = 2; else if (dH >= -128) hOffset = 1; else hOffset = 0; hough[hOffset, i]++; /* New angle takes over lead */ if (hough[hOffset, i] > hough[hOffsetBest, angleBest]) { angleBest = i; hOffsetBest = hOffset; } } } /* CALLBACK_POINT_PLOT(follow.loc, (sign > 1) ? 4 : 3, 1, 2); */ follow = FollowStep(reg, follow, sign); } line.Angle = angleBest; line.HOffset = hOffsetBest; line.Mag = hough[hOffsetBest, angleBest]; return line; }
bool RegionUpdateCorners(DmtxRegion reg, DmtxVector2 p00, DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01) { double xMax, yMax; double tx, ty, phi, shx, scx, scy, skx, sky; double dimOT, dimOR, dimTX, dimRX, ratio; DmtxVector2 vOT, vOR, vTX, vRX, vTmp; xMax = (double)(this.Width - 1); yMax = (double)(this.Height - 1); if (p00.X < 0.0 || p00.Y < 0.0 || p00.X > xMax || p00.Y > yMax || p01.X < 0.0 || p01.Y < 0.0 || p01.X > xMax || p01.Y > yMax || p10.X < 0.0 || p10.Y < 0.0 || p10.X > xMax || p10.Y > yMax) return false; vOT = p01 - p00; vOR = p10 - p00; vTX = p11 - p01; vRX = p11 - p10; dimOT = vOT.Mag(); /* XXX could use MagSquared() */ dimOR = vOR.Mag(); dimTX = vTX.Mag(); dimRX = vRX.Mag(); /* Verify that sides are reasonably long */ if (dimOT <= 8.0 || dimOR <= 8.0 || dimTX <= 8.0 || dimRX <= 8.0) return false; /* Verify that the 4 corners define a reasonably fat quadrilateral */ ratio = dimOT / dimRX; if (ratio <= 0.5 || ratio >= 2.0) return false; ratio = dimOR / dimTX; if (ratio <= 0.5 || ratio >= 2.0) return false; /* Verify this is not a bowtie shape */ if (vOR.Cross(vRX) <= 0.0 || vOT.Cross(vTX) >= 0.0) return false; if (DmtxCommon.RightAngleTrueness(p00, p10, p11, Math.PI / 2.0) <= this._squareDevn) return false; if (DmtxCommon.RightAngleTrueness(p10, p11, p01, Math.PI / 2.0) <= this._squareDevn) return false; /* Calculate values needed for transformations */ tx = -1 * p00.X; ty = -1 * p00.Y; DmtxMatrix3 mtxy = DmtxMatrix3.Translate(tx, ty); phi = Math.Atan2(vOT.X, vOT.Y); DmtxMatrix3 mphi = DmtxMatrix3.Rotate(phi); DmtxMatrix3 m = mtxy * mphi; vTmp = p10 * m; shx = -vTmp.Y / vTmp.X; DmtxMatrix3 mshx = DmtxMatrix3.Shear(0.0, shx); m *= mshx; scx = 1.0 / vTmp.X; DmtxMatrix3 mscx = DmtxMatrix3.Scale(scx, 1.0); m *= mscx; vTmp = p11 * m; scy = 1.0 / vTmp.Y; DmtxMatrix3 mscy = DmtxMatrix3.Scale(1.0, scy); m *= mscy; vTmp = p11 * m; skx = vTmp.X; DmtxMatrix3 mskx = DmtxMatrix3.LineSkewSide(1.0, skx, 1.0); m *= mskx; vTmp = p01 * m; sky = vTmp.Y; DmtxMatrix3 msky = DmtxMatrix3.LineSkewTop(sky, 1.0, 1.0); reg.Raw2fit = m * msky; /* Create inverse matrix by reverse (avoid straight matrix inversion) */ msky = DmtxMatrix3.LineSkewTopInv(sky, 1.0, 1.0); mskx = DmtxMatrix3.LineSkewSideInv(1.0, skx, 1.0); m = msky * mskx; DmtxMatrix3 mscxy = DmtxMatrix3.Scale(1.0 / scx, 1.0 / scy); m *= mscxy; mshx = DmtxMatrix3.Shear(0.0, -shx); m *= mshx; mphi = DmtxMatrix3.Rotate(-phi); m *= mphi; mtxy = DmtxMatrix3.Translate(-tx, -ty); reg.Fit2raw = m * mtxy; return true; }
DmtxFollow FollowSeek(DmtxRegion reg, int seek) { int i; int sign; DmtxFollow follow = new DmtxFollow(); follow.Loc = reg.FlowBegin.Loc; follow.Step = 0; follow.Ptr = this._cache; follow.PtrIndex = DecodeGetCache(follow.Loc.X, follow.Loc.Y); sign = (seek > 0) ? +1 : -1; for (i = 0; i != seek; i += sign) { follow = FollowStep(reg, follow, sign); if (Math.Abs(follow.Step) > reg.StepsTotal) { throw new Exception("Follow step count larger total step count!"); } } return follow; }
bool RegionUpdateXfrms(DmtxRegion reg) { double radians; DmtxRay2 rLeft = new DmtxRay2(); DmtxRay2 rBottom = new DmtxRay2(); DmtxRay2 rTop = new DmtxRay2(); DmtxRay2 rRight = new DmtxRay2(); DmtxVector2 p00 = new DmtxVector2(); DmtxVector2 p10 = new DmtxVector2(); DmtxVector2 p11 = new DmtxVector2(); DmtxVector2 p01 = new DmtxVector2(); if (!(reg.LeftKnown != 0 && reg.BottomKnown != 0)) { throw new ArgumentException("Error updating Xfrms!"); } /* Build ray representing left edge */ rLeft.P.X = (double)reg.LeftLoc.X; rLeft.P.Y = (double)reg.LeftLoc.Y; radians = reg.LeftAngle * (Math.PI / DmtxConstants.DmtxHoughRes); rLeft.V.X = Math.Cos(radians); rLeft.V.Y = Math.Sin(radians); rLeft.TMin = 0.0; rLeft.TMax = rLeft.V.Norm(); /* Build ray representing bottom edge */ rBottom.P.X = (double)reg.BottomLoc.X; rBottom.P.Y = (double)reg.BottomLoc.Y; radians = reg.BottomAngle * (Math.PI / DmtxConstants.DmtxHoughRes); rBottom.V.X = Math.Cos(radians); rBottom.V.Y = Math.Sin(radians); rBottom.TMin = 0.0; rBottom.TMax = rBottom.V.Norm(); /* Build ray representing top edge */ if (reg.TopKnown != 0) { rTop.P.X = (double)reg.TopLoc.X; rTop.P.Y = (double)reg.TopLoc.Y; radians = reg.TopAngle * (Math.PI / DmtxConstants.DmtxHoughRes); rTop.V.X = Math.Cos(radians); rTop.V.Y = Math.Sin(radians); rTop.TMin = 0.0; rTop.TMax = rTop.V.Norm(); } else { rTop.P.X = (double)reg.LocT.X; rTop.P.Y = (double)reg.LocT.Y; radians = reg.BottomAngle * (Math.PI / DmtxConstants.DmtxHoughRes); rTop.V.X = Math.Cos(radians); rTop.V.Y = Math.Sin(radians); rTop.TMin = 0.0; rTop.TMax = rBottom.TMax; } /* Build ray representing right edge */ if (reg.RightKnown != 0) { rRight.P.X = (double)reg.RightLoc.X; rRight.P.Y = (double)reg.RightLoc.Y; radians = reg.RightAngle * (Math.PI / DmtxConstants.DmtxHoughRes); rRight.V.X = Math.Cos(radians); rRight.V.Y = Math.Sin(radians); rRight.TMin = 0.0; rRight.TMax = rRight.V.Norm(); } else { rRight.P.X = (double)reg.LocR.X; rRight.P.Y = (double)reg.LocR.Y; radians = reg.LeftAngle * (Math.PI / DmtxConstants.DmtxHoughRes); rRight.V.X = Math.Cos(radians); rRight.V.Y = Math.Sin(radians); rRight.TMin = 0.0; rRight.TMax = rLeft.TMax; } /* Calculate 4 corners, real or imagined */ if (!p00.Intersect(rLeft, rBottom)) return false; if (!p10.Intersect(rBottom, rRight)) return false; if (!p11.Intersect(rRight, rTop)) return false; if (!p01.Intersect(rTop, rLeft)) return false; if (!RegionUpdateCorners(reg, p00, p10, p11, p01)) return false; return true; }
private void TallyModuleJumps(DmtxRegion reg, int[,] tally, int xOrigin, int yOrigin, int mapWidth, int mapHeight, DmtxDirection dir) { int extent, weight; int mapRow, mapCol; int lineStart, lineStop; int travelStart, travelStop; int line; int travel; int jumpThreshold; int color; int statusPrev, statusModule; int tPrev, tModule; if (!(dir == DmtxDirection.DmtxDirUp || dir == DmtxDirection.DmtxDirLeft || dir == DmtxDirection.DmtxDirDown || dir == DmtxDirection.DmtxDirRight)) { throw new ArgumentException("Only orthogonal directions are allowed in tally module jumps!"); } int travelStep = (dir == DmtxDirection.DmtxDirUp || dir == DmtxDirection.DmtxDirRight) ? 1 : -1; /* Abstract row and column progress using pointers to allow grid traversal in all 4 directions using same logic */ bool horizontal = false; if ((dir & DmtxDirection.DmtxDirHorizontal) != 0x00) { horizontal = true; line = 0; travel = 0; extent = mapWidth; lineStart = yOrigin; lineStop = yOrigin + mapHeight; travelStart = (travelStep == 1) ? xOrigin - 1 : xOrigin + mapWidth; travelStop = (travelStep == 1) ? xOrigin + mapWidth : xOrigin - 1; } else { line = 0; travel = 0; extent = mapHeight; lineStart = xOrigin; lineStop = xOrigin + mapWidth; travelStart = (travelStep == 1) ? yOrigin - 1 : yOrigin + mapHeight; travelStop = (travelStep == 1) ? yOrigin + mapHeight : yOrigin - 1; } bool darkOnLight = (reg.OffColor > reg.OnColor); jumpThreshold = Math.Abs((int)(0.4 * (reg.OffColor - reg.OnColor) + 0.5)); if (jumpThreshold < 0) { throw new Exception("Negative jump threshold is not allowed in tally module jumps"); } for (line = lineStart; line < lineStop; line++) { /* Capture tModule for each leading border module as normal but decide status based on predictable barcode border pattern */ travel = travelStart; if (horizontal) { color = ReadModuleColor(reg, line, travel, reg.SizeIdx, reg.FlowBegin.Plane); } else { color = ReadModuleColor(reg, travel, line, reg.SizeIdx, reg.FlowBegin.Plane); } tModule = (darkOnLight) ? reg.OffColor - color : color - reg.OffColor; statusModule = (travelStep == 1 || (line & 0x01) == 0) ? DmtxConstants.DmtxModuleOnRGB : DmtxConstants.DmtxModuleOff; weight = extent; while ((travel += travelStep) != travelStop) { tPrev = tModule; statusPrev = statusModule; /* For normal data-bearing modules capture color and decide module status based on comparison to previous "known" module */ if (horizontal) { color = ReadModuleColor(reg, line, travel, reg.SizeIdx, reg.FlowBegin.Plane); } else { color = ReadModuleColor(reg, travel, line, reg.SizeIdx, reg.FlowBegin.Plane); } tModule = (darkOnLight) ? reg.OffColor - color : color - reg.OffColor; if (statusPrev == DmtxConstants.DmtxModuleOnRGB) { if (tModule < tPrev - jumpThreshold) { statusModule = DmtxConstants.DmtxModuleOff; } else { statusModule = DmtxConstants.DmtxModuleOnRGB; } } else if (statusPrev == DmtxConstants.DmtxModuleOff) { if (tModule > tPrev + jumpThreshold) { statusModule = DmtxConstants.DmtxModuleOnRGB; } else { statusModule = DmtxConstants.DmtxModuleOff; } } if (horizontal) { mapRow = line - yOrigin; mapCol = travel - xOrigin; } else { mapRow = travel - yOrigin; mapCol = line - xOrigin; } if (!(mapRow < 24 && mapCol < 24)) { throw new Exception("Tally module mump failed, index out of range!"); } if (statusModule == DmtxConstants.DmtxModuleOnRGB) { tally[mapRow, mapCol] += (2 * weight); } weight--; } if (weight != 0) { throw new Exception("Tally module jump failed, weight <> 0!"); } } }
internal bool EncodeDataMatrix(Color? foreColor, Color? backColor, byte[] inputString) { int padCount; int width, height, bitsPerPixel; byte[] buf = new byte[4096]; byte[] pxl; /* Encode input string into data codewords */ DmtxSymbolSize sizeIdx = this._sizeIdxRequest; int dataWordCount = EncodeDataCodewords(buf, inputString, ref sizeIdx); if (dataWordCount <= 0) { return false; } /* EncodeDataCodewords() should have updated any auto sizeIdx to a real one */ if (sizeIdx == DmtxSymbolSize.DmtxSymbolSquareAuto || sizeIdx == DmtxSymbolSize.DmtxSymbolRectAuto) { throw new Exception("Invalid symbol size for encoding!"); } /* Add pad characters to match a standard symbol size (whether smallest or requested) */ padCount = AddPadChars(buf, ref dataWordCount, DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolDataWords, sizeIdx)); /* XXX we can remove a lot of this redundant data */ this._region = new DmtxRegion(); this._region.SizeIdx = sizeIdx; this._region.SymbolRows = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolRows, sizeIdx); this._region.SymbolCols = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolCols, sizeIdx); this._region.MappingRows = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribMappingMatrixRows, sizeIdx); this._region.MappingCols = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribMappingMatrixCols, sizeIdx); /* Allocate memory for message and array */ this._message = new DmtxMessage(sizeIdx, DmtxFormat.Matrix); this._message.PadCount = padCount; for (int i = 0; i < dataWordCount; i++) { this._message.Code[i] = buf[i]; } /* Generate error correction codewords */ DmtxCommon.GenReedSolEcc(this._message, this._region.SizeIdx); /* Module placement in region */ DmtxDecode.ModulePlacementEcc200(this._message.Array, this._message.Code, this._region.SizeIdx, DmtxConstants.DmtxModuleOnRGB); width = 2 * this._marginSize + (this._region.SymbolCols * this._moduleSize); height = 2 * this._marginSize + (this._region.SymbolRows * this._moduleSize); bitsPerPixel = DmtxCommon.GetBitsPerPixel(this._pixelPacking); if (bitsPerPixel == DmtxConstants.DmtxUndefined) return false; if (bitsPerPixel % 8 != 0) { throw new Exception("Invalid color depth for encoding!"); } /* Allocate memory for the image to be generated */ // pxl = (unsigned char *)malloc(width * height * (bitsPerPixel/8) + enc->rowPadBytes); pxl = new byte[width * height * (bitsPerPixel / 8) + this._rowPadBytes]; this._image = new DmtxImage(pxl, width, height, this._pixelPacking); this._image.ImageFlip = this._imageFlip; this._image.RowPadBytes = this._rowPadBytes; /* Insert finder and aligment pattern modules */ PrintPattern(foreColor, backColor); return true; }