/// <summary> /// Draws the QR code to the specified graphics context (canvas). The QR code will /// always be 46 mm by 46 mm. /// </summary> /// <param name="graphics">The graphics context.</param> /// <param name="offsetX">The x offset.</param> /// <param name="offsetY">The y offset.</param> internal void Draw(ICanvas graphics, double offsetX, double offsetY) { QrCode qrCode = QrCode.EncodeText(_embeddedText, QrCode.Ecc.Medium); bool[,] modules = CopyModules(qrCode); ClearSwissCrossArea(modules); int modulesPerSide = modules.GetLength(0); graphics.SetTransformation(offsetX, offsetY, 0, Size / modulesPerSide / 25.4 * 72, Size / modulesPerSide / 25.4 * 72); graphics.StartPath(); DrawModulesPath(graphics, modules); graphics.FillPath(0); graphics.SetTransformation(offsetX, offsetY, 0, 1, 1); // Swiss cross graphics.StartPath(); graphics.AddRectangle(20, 20, 6, 6); graphics.FillPath(0); const double barWidth = 7 / 6.0; const double barLength = 35 / 9.0; graphics.StartPath(); graphics.AddRectangle(23 - barWidth / 2, 23 - barLength / 2, barWidth, barLength); graphics.AddRectangle(23 - barLength / 2, 23 - barWidth / 2, barLength, barWidth); graphics.FillPath(0xffffff); }
// Simple algorithms to reduce the number of rectangles for drawing the QR code // and reduce SVG size private static void DrawLargestRectangle(ICanvas graphics, bool[,] modules, int x, int y) { int size = modules.GetLength(0); int bestW = 1; int bestH = 1; int maxArea = 1; int xLimit = size; int iy = y; while (iy < size && modules[iy, x]) { int w = 0; while (x + w < xLimit && modules[iy, x + w]) { w++; } int area = w * (iy - y + 1); if (area > maxArea) { maxArea = area; bestW = w; bestH = iy - y + 1; } xLimit = x + w; iy++; } double unit = 25.4 / 72; graphics.AddRectangle(x * unit, (size - y - bestH) * unit, bestW * unit, bestH * unit); ClearRectangle(modules, x, y, bestW, bestH); }
/// <summary> /// Produces a mapping to a sprite that has given maximum dimensions. /// If the mapping can not be done inside those dimensions, returns null. /// </summary> /// <param name="images"> /// List of image infos. /// /// This method will not sort this list. /// All images in this collection will be used, regardless of size. /// </param> /// <param name="maxWidth"> /// The sprite won't be wider than this. /// </param> /// <param name="maxHeight"> /// The generated sprite won't be higher than this. /// </param> /// <param name="canvasStats"> /// The statistics produced by the canvas. These numbers are since the last call to its SetCanvasDimensions method. /// </param> /// <param name="lowestFreeHeightDeficitTallestRightFlushedImage"> /// The lowest free height deficit for the images up to and including the tallest rectangle whose right hand border sits furthest to the right /// of all images. /// /// This is the minimum amount by which the height of the canvas needs to be increased to accommodate that rectangle. /// if the width of the canvas is decreased to one less than the width now taken by images. /// /// Note that providing the additional height might get some other (not right flushed) image to be placed higher, thereby /// making room for the flushed right image. /// /// This will be set to Int32.MaxValue if there was never any free height deficit. /// </param> /// <returns> /// The generated sprite. /// /// null if not all the images could be placed within the size limitations. /// </returns> protected virtual S MappingRestrictedBox( IOrderedEnumerable <IImageInfo> images, int maxWidth, int maxHeight, ICanvasStats canvasStats, out int lowestFreeHeightDeficitTallestRightFlushedImage) { lowestFreeHeightDeficitTallestRightFlushedImage = 0; _canvas.SetCanvasDimensionsbis(maxWidth, maxHeight); S spriteInfo = new S(); int heightHighestRightFlushedImage = 0; int furthestRightEdge = 0; foreach (IImageInfo image in images) { int xOffset; int yOffset; int lowestFreeHeightDeficit; if (!_canvas.AddRectangle( image.Width, image.Height, out xOffset, out yOffset, out lowestFreeHeightDeficit)) { // Not enough room on the canvas to place the rectangle spriteInfo = null; break; } MappedImageInfo imageLocation = new MappedImageInfo(xOffset, yOffset, image); spriteInfo.AddMappedImage(imageLocation); // Update the lowestFreeHeightDeficitTallestRightFlushedImage int rightEdge = image.Width + xOffset; if ((rightEdge > furthestRightEdge) || ((rightEdge == furthestRightEdge) && (image.Height > heightHighestRightFlushedImage))) { // The image is flushed the furthest right of all images, or it is flushed equally far to the right // as the furthest flushed image but it is taller. lowestFreeHeightDeficitTallestRightFlushedImage = lowestFreeHeightDeficit; heightHighestRightFlushedImage = image.Height; furthestRightEdge = rightEdge; } } _canvas.GetStatistics(canvasStats); return(spriteInfo); }
/// <summary> /// Draws the QR code to the specified graphics context (canvas). The QR code will /// always be 46 mm by 46 mm. /// </summary> /// <param name="graphics">The graphics context.</param> /// <param name="offsetX">The x offset.</param> /// <param name="offsetY">The y offset.</param> internal void Draw(ICanvas graphics, double offsetX, double offsetY) { var qrCode = QrCode.EncodeText(_embeddedText, QrCode.Ecc.Medium); var modules = CopyModules(qrCode); ClearSwissCrossArea(modules); var modulesPerSide = modules.GetLength(0); graphics.SetTransformation(offsetX, offsetY, 0, Size / modulesPerSide / 25.4 * 72, Size / modulesPerSide / 25.4 * 72); graphics.StartPath(); DrawModulesPath(graphics, modules); graphics.FillPath(0, false); graphics.SetTransformation(offsetX, offsetY, 0, 1, 1); // Swiss cross graphics.StartPath(); graphics.AddRectangle(20, 20, 6, 6); graphics.FillPath(0, false); const double barWidth = 7 / 6.0; const double barLength = 35 / 9.0; graphics.StartPath(); // A----B // | | // | | // K-----L C-----D // | | // | | // J-----I F-----E // | | // | | // H----G // Center is (23;23) // Start in A graphics.MoveTo(23 - barWidth / 2, 23 - barLength / 2); // Line to B graphics.LineTo(23 + barWidth / 2, 23 - barLength / 2); // Line to C graphics.LineTo(23 + barWidth / 2, 23 - barWidth / 2); // Line to D graphics.LineTo(23 + barLength / 2, 23 - barWidth / 2); // Line to E graphics.LineTo(23 + barLength / 2, 23 + barWidth / 2); // Line to F graphics.LineTo(23 + barWidth / 2, 23 + barWidth / 2); // Line to G graphics.LineTo(23 + barWidth / 2, 23 + barLength / 2); // Line to H graphics.LineTo(23 - barWidth / 2, 23 + barLength / 2); // Line to I graphics.LineTo(23 - barWidth / 2, 23 + barWidth / 2); // Line to J graphics.LineTo(23 - barLength / 2, 23 + barWidth / 2); // Line to K graphics.LineTo(23 - barLength / 2, 23 - barWidth / 2); // Line to K graphics.LineTo(23 - barWidth / 2, 23 - barWidth / 2); graphics.FillPath(0xffffff, false); }