0

I need to extract tiles from a tif image and write them in jpg format.

Based on a previous search, I wrote some C# code that works in a C# WinForm project on my desktop. Then I had the idea to put it as a WebService but i cannot do it, because this code is using Marshal.Copy that doesn't work on the remote server (despite I have there the full trust mode. I have read some comment saying that this could be the problem, but it isn't, in my case).

The source image is Tif, therefore I have read the part of the image corresponding to the tile, in a buffer named output. If nothing better is possible, I could accept to set the resulting image Pixel by Pixel, but I don't see how to do it in C#. In other words I am not able to set the pixels in the resulting image, using the bytes[] that I extracted from the Tif.

The code which works on the desktop is:

using (var image = new Bitmap(W, H, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
{
     var bmpData = image.LockBits(new Rectangle(0, 0, W, H),ImageLockMode.WriteOnly, 
                                               Image.PixelFormat);
     var ptr = bmpData.Scan0;
     Marshal.Copy(output, 0, ptr, output.Length);
     image.UnlockBits(bmpData);
     image.Save(origin + "\\" + TileName, ImageFormat.Png)
}
JuanR
  • 7,405
  • 1
  • 19
  • 30
gpol
  • 39
  • 6
  • Does this answer your question? [C# copy paste an image region into another image](https://stackoverflow.com/questions/9616617/c-sharp-copy-paste-an-image-region-into-another-image) – JuanR Mar 08 '23 at 17:31
  • [.NET Core Image Processing](https://devblogs.microsoft.com/dotnet/net-core-image-processing/) – Alexander Petrov Mar 08 '23 at 17:32
  • @JuanR. Actually, despite the Tif file is obviously an Image, I only found a way to extract the tile as sequence of bytes. So, much probably your suggestion is valid, but my problem now becomes how to put the tif file in an image. Unluckily I am not so fond of C#, and in C++ I usually use libraries for this task. – gpol Mar 08 '23 at 18:54

2 Answers2

0

By the way, @JuanR suggestion allowed me to resolve the problem. The following code works, despite it gives me an out of memory error, after creating some tiles. This latter error should not be related to my original problem. I took the code from Microsoft documentation. With my surprise, despite it was described to use a decoder, I commented it out and used directly a bitmap, as you can see in the following:

   private static void CopyRegionIntoImage(Bitmap srcBitmap, Rectangle srcRegion, ref Bitmap destBitmap, Rectangle destRegion)
    {
        using (Graphics grD = Graphics.FromImage(destBitmap))
        {
            grD.DrawImage(srcBitmap, destRegion, srcRegion, GraphicsUnit.Pixel);
        }
    }

    private static void MakeTile(string Original, int X, int Y, int W, int H, string TileName)
    {
        Stream imageStreamSource = new FileStream(Original, FileMode.Open, FileAccess.Read, FileShare.Read);
        // var decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
        //BitmapSource bitmapSource = decoder.Frames[0];
        Rectangle srcRegion = new Rectangle(X, Y, W, H);
        Rectangle dstRegion = new Rectangle(0, 0, W, H);
        var srcImage = new Bitmap(imageStreamSource);
        var image = new Bitmap(W, H, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        CopyRegionIntoImage(srcImage, srcRegion, ref image, dstRegion);
        image.Save(TileName, ImageFormat.Png);
    }
gpol
  • 39
  • 6
  • 1
    You may be running out of memory because you are not properly disposing of the `FileStream` and the two `Bitmap` instances. Use a `using` statement around each of them. – JuanR Mar 08 '23 at 20:15
  • 1
    But you are warned that all `System.Drawing` family is not designed for web apps, if you read the namespace article on Microsoft Docs. Please find a web friendly library instead. – Lex Li Mar 08 '23 at 21:39
  • @JuanR. Yes, I was concerned on the main problem. Probably you are right. I am neither C# expert nor fan. Therefore I would like to know why the MakeTile, which is called by another function, doesn't free the memory it uses, being all the involved variables local, and, moreover, we should be in a managed environment.. – gpol Mar 09 '23 at 07:44
  • @gpol Classes implement the `IDisposable` interface precisely because they need to be disposed of properly. They usually have internal resources (e.g. file handles, locks, OS resources) that need to be released when the object is no longer being used. The garbage colector on the other hand will automatically release memory, but it does so when it thinks it needs to, not when YOU need it to. You can manually trigger a collection too but this can have performance implications, depending on the memory size. – JuanR Mar 13 '23 at 02:58
  • 1
    @gpol by the way, please avoid posting more than one answer. You can always edit the original one. – JuanR Mar 13 '23 at 13:43
0

Final version without Out of Memory:

private static void MakeTile(string Original, int X, int Y, int W, int H, string TileName)
    {
        using (Stream imageStreamSource = new FileStream(Original, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            Rectangle srcRegion = new Rectangle(X, Y, W, H);
            Rectangle dstRegion = new Rectangle(0, 0, W, H);
            using (var srcImage = new Bitmap(imageStreamSource))
            {
                using (var image = new Bitmap(W, H, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
                {
                    Bitmap outImage = new Bitmap(image);
                    CopyRegionIntoImage(srcImage, srcRegion, ref outImage, dstRegion);
                    outImage.Save(TileName, ImageFormat.Png);
                    outImage.Dispose();

                }
            }
        }
    }
gpol
  • 39
  • 6