5

I'm writing an application that requires me to split a large image into small tiles, where each tile is essentially a cropped version of the original image.

Currently my split operation looks something like this

tile.Image = new BitmapImage();
tile.Image.BeginInit();
tile.Image.UriSource = OriginalImage.UriSource;
tile.Image.SourceRect = new Int32Rect(x * tileWidth + x, y * tileHeight, tileWidth, tileHeight);
tile.Image.EndInit();

Intuitively, I thought that this would create basically a "reference" to the original image, and would just display as a sub rectangle of the image. However, the slow speed at which my split operation performs has lead me to believe that this is actually copying the source rect of the original image, which is very slow for large images (There is a noticeable 3-4 second pause when splitting a decent size image).

I looked around a bit but haven't been able to find a way to draw a bitmap as a sub rect of a large image, without copying any data. Any suggestions?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
phosphoer
  • 433
  • 6
  • 16
  • Have you tried creating a new `Bitmap` and blitting into it? I think that might be faster than trying to crop the image inline. – Mike Caron Mar 26 '13 at 22:14
  • Your `tile` class could store a reference to the original image and a rectangle to copy when drawing itself? Graphics.DrawImage has overloads to draw a portion of a bitmap: http://msdn.microsoft.com/en-us/library/3tf158xz.aspx – Blorgbeard Mar 26 '13 at 22:15
  • I'm admittedly not an expert on image manipulation, but I'm not sure what you're asking for makes sense. While there may be a mechanism to hide the copy, I suspect the image data need to be "realigned" (copied) in memory either way. – svidgen Mar 26 '13 at 22:17
  • Clarifying my last comment, I'm just thinking about the internal storage format -- it's likely just a byte array. Simplifying a great deal, a 4x4 image is *ABCD EFGH IJKL MNOP* in memory, for instance. If you want the 2x2 on the top left, for instance, you need a new byte array like *ABEF*. It's not a subarray. – svidgen Mar 26 '13 at 22:21
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Mar 27 '13 at 01:00
  • The Graphics.DrawImage is a nice suggestion but unfortunately my drawing happens in XAML, via bound BitmapImages so I don't think I have control over that. The next thing to try is probably Mike's suggestion. – phosphoer Mar 27 '13 at 21:45

1 Answers1

4

Use the System.Windows.Media.Imaging.CroppedBitmap class:

// Create a CroppedBitmap from the original image.
Int32Rect rect = new Int32Rect(x * tileWidth + x, y * tileHeight, tileWidth, tileHeight);
CroppedBitmap croppedBitmap = new CroppedBitmap(originalImage, rect);

// Create an Image element.
Image tileImage = new Image();
tileImage.Width = tileWidth;
tileImage.Height = tileHeight;
tileImage.Source = croppedBitmap;
intrepidis
  • 2,870
  • 1
  • 34
  • 36
  • 1
    Earlier I commented that this didn't increase performance that much but I just tried the old way again and this does in fact produce a significant performance gain (from close to 6 seconds for a split to more like 1 second). – phosphoer Mar 27 '13 at 22:04