The task - to stamp different images on the canvas. That's just the size of the canvas is unknown in advance. Stamped with Graphics

 var bmp = new Bitmap(1, 1); var g = Graphics.FromImage(bmp); g.DrawImage(someImage, 0,0, someImage.Width,someImage.Height); 

The last action may not be the only one. That is, I may need to insert a lot of pictures, text, and even hell knows what. Nor do I want to bother calculating the size of the image. Are there any automatic tools for this?

    2 answers 2

    Most likely a bicycle, but since no solutions were proposed, he invented himself. Suddenly someone come in handy.

    Here is the class of the canvas itself.

     public class InfinityCanvas { List<ImageLayer> _layers { get; } = new List<ImageLayer>(); int _minLeftTopX = int.MaxValue; int _minLeftTopY = int.MaxValue; int _maxRightBottomX = int.MinValue; int _maxRightBottomY = int.MinValue; public void AddImage(Image image, Point position) { AddImage(image, position.X, position.Y); } public void AddImage(Image image, int x, int y) { _layers.Add(new ImageLayer(image, x, y)); if (_minLeftTopX >= x) _minLeftTopX = x; if (_minLeftTopY >= y) _minLeftTopY = y; if (_maxRightBottomX <= x + image.Width) _maxRightBottomX = x + image.Width; if (_maxRightBottomY <= y + image.Height) _maxRightBottomY = y + image.Height; } public Image GetResult() { if (_layers.Count == 0) { var b = new Bitmap(1, 1); return b; } var res = new Bitmap(_maxRightBottomX - _minLeftTopX, _maxRightBottomY - _minLeftTopY); var g = Graphics.FromImage(res); for (var i = 0; i < _layers.Count; i++) { var lay = _layers[i]; g.DrawImage(lay.Image, lay.LeftTopX - _minLeftTopX, lay.LeftTopY - _minLeftTopY, lay.Image.Width, lay.Image.Height); } return res; } } 

    Here is the layer class

     class ImageLayer { public Image Image { get; set; } public int LeftTopX { get; set; } public int LeftTopY { get; set; } public ImageLayer(Image image, int x, int y) { Image = image; LeftTopX = x; LeftTopY = y; } } 

    Here we use

     var ic = new InfinityCanvas(); ic.AddImage(someImage, -100, -100); ic.AddImage(someImage, someImage.Width, someImage.Height); ic.GetResult().Save("1.png"); 

    The result is a picture in the upper left and lower right corners of which the image is contained in someImage . The distance between the images is 100 in both axes.

    • Bike, but good. - VladD

    You can create a fairly large canvas, for example 10,000 by 10,000 pixels and draw as much as you need on it. Then trim the unnecessary part (s) with this :

     static Bitmap TrimBitmap(Bitmap source) { Rectangle srcRect = default(Rectangle); BitmapData data = null; try { data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte[] buffer = new byte[data.Height * data.Stride]; Marshal.Copy(data.Scan0, buffer, 0, buffer.Length); int xMin = int.MaxValue; int xMax = 0; int yMin = int.MaxValue; int yMax = 0; for (int y = 0; y < data.Height; y++) { for (int x = 0; x < data.Width; x++) { byte alpha = buffer[y * data.Stride + 4 * x + 3]; if (alpha != 0) { if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } } } if (xMax < xMin || yMax < yMin) { // Image is empty... return null; } srcRect = Rectangle.FromLTRB(xMin, yMin, xMax, yMax); } finally { if (data != null) source.UnlockBits(data); } Bitmap dest = new Bitmap(srcRect.Width, srcRect.Height); Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height); using (Graphics graphics = Graphics.FromImage(dest)) { graphics.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel); } return dest; } 
    • canvas may be larger. In addition, there may be several such paintings at one time. These are huge RAM costs - iRumba
    • Not without it, but under your conditions nothing else comes to mind. - Daniel Protopopov
    • Well, why. At the moment, the most optimal solution is to keep in memory all parts of the picture (with their global position). then from all parts to collect the whole picture. But I thought that perhaps there is already a ready-made solution for this, maybe even as part of .net. - iRumba
    • And yes, this solution does not meet my conditions. - iRumba