ThinkGeo.com    |     Documentation    |     Premium Support

Best way to display a jpeg in an in memory layer

We have a custom storage system that returns geo-reference images, basicly an object with the lat/lon bounding box, a byte[] of the image and the information needed to construct a world file.  I'd like to be able to display the image without the need to write it out to disk.


I've looked around and have seen a few topics that are similiar, but most of involved a custom drawn image and not just showing a geo-referenced image.  I was thinking about doing a sub-class of layer or GdiPlusRasterLayer or the GdiPlusRasterSource but I'm not sure how all the classes interact and what would produce the best results.


Any suggestions would be great!


Thanks


Brian



I think what I need to do is sub class GdiPlusRasterSource and GdiPlusRasterLayer...where in the source I just need to hook up to the StreamLoading event and give it a memory stream of my byte arrray.


But what I can't figure out is how do I load the world file information, all the methods that seem to deal with the world file are not virtual so I can't override them.


Brian



Brian, 
  
 You can also load the world file in the StreamLoading event. Here is the sample codes for that. 
   
 
 GdiPlusRasterSource gdiPlusRasterSource = new GdiPlusRasterSource("notExist.jpg");
            gdiPlusRasterSource.StreamLoading += new EventHandler<StreamLoadingEventArgs>(gdiPlusRasterSource_StreamLoading);

//…
  void gdiPlusRasterSource_StreamLoading(object sender, StreamLoadingEventArgs e)
        {
            if (e.AlternateStreamName.Contains(".JPG"))
            {
                //e.AlternateStream = imageStream;
            }

            else if (e.AlternateStreamName.Contains(".JGW"))
            {
                //e.AlternateStream = worldFileStream;
            }
        }
 
  
 Thanks, 
  
 Ben

Hi Ben,


Thanks for the info, I tried doing that and I get the streams loaded but I'm getting a new error now when opening the RasterLayer.  Its below, I'm also attaching a dumb of the memory stream I created the world file in to the hard drive, which has six lines in it.  Below is the exception and the code that writes to the stream.


Thanks


System.ArgumentException occurred

  Message="World file should has 6 lines.\r\nParameter name: worldFileText"

  Source="MapSuiteCore"

  ParamName="worldFileText"

  StackTrace:

       at ThinkGeo.MapSuite.Core.WorldFile..ctor(String worldFileText)

       at ThinkGeo.MapSuite.Core.GdiPlusRasterSource.xa52a84e48240d21b(Stream xf616ee320c8f54d8)

       at ThinkGeo.MapSuite.Core.GdiPlusRasterSource.OpenCore()

       at ThinkGeo.MapSuite.Core.RasterSource.Open()

       at ThinkGeo.MapSuite.Core.RasterLayer.OpenCore()

       at ThinkGeo.MapSuite.Core.Layer.Open()

       at Tcc.Gis.ThinkGeoTestApp.Form1..ctor() in C:\TFSSource\TCC\GIS\Tcc.Gis.ThinkGeoTestApp\Form1.cs:line 42

  InnerException: 

 



public void SaveToStream(Stream stream, bool closeStreamWhenFinished)
        {
            // Nothing to save if embedded
            if( IsEmbedded )
                return;

            StreamWriter writer = null;
            try
            {
                writer = new StreamWriter(stream);

                // Write 6 lines.
                writer.WriteLine(PixelSizeX);
                writer.WriteLine(RotationX);
                writer.WriteLine(RotationY);
                writer.WriteLine(PixelSizeY);
                writer.WriteLine(UtmX);
                writer.Write(UtmY);

                //Flush the writer in case we don't close it
                writer.Flush();
            }
            catch( Exception exc )
            {
                throw exc;
            }
            finally
            {
                if( writer != null && closeStreamWhenFinished )
                    writer.Close();
            }
        }


580-worldfile.txt (48 Bytes)

I just tested using that worldfile I exported from the memory stream in a GdiPlusRasterLayer just loading from the hard disk and it worked fine.

Another quick note, when I close the MemoryStream I’m writing the world file to, get it as an byte[] and put in a new memory stream I don’t get the error anymore.  But even though the world file is small, seems like a waste to create two streams to read it.  Maybe I’m just missing someting.

In implementing my own custom layer to display an in-memory geo-referenced image I had to sub-class GdiPlusRasterLayer to be able to just set the ImageSource as my custom sub-classed GdiPlusRasterSource. I've attached the class below.  While I don't mind creating the layer sub-class, I've been spending a lot of time in WPFs programming model where its more common to attach new code/features then extend a base class.  In general this keeps the depth of inheritance shallower which seems to be a good practice to do.  So I was wondering if it would be possible to add a ctor overload to accept an ImageSource (or GdiPlusRasterSource) in GdiPlusRasterLayer instead of having to sub-class or use a couple lines of code to do the same thing>



Thanks
Brian


public class TccRasterLayerThinkGeoLayer : GdiPlusRasterLayer
    {
        #region Construct/Initialize

        public TccRasterLayerThinkGeoLayer(ITccRasterLayer layerToWrap)
        {
            this.ImageSource = new TccRasterSource(layerToWrap);
        }

        #endregion
    }


Brian, 
  
 To work around the exception, you can add stream.Seek(0, SeekOrigin.Begin) at the end of SaveToStream() method. This is a bug in our system and we will fix it in next version. 
  
 As ImageSource is a protected set property,which means you can only set this property in its sub class, I am afraid you have to inherite from GdiPlusRasterLayer to accomplish your requirements.  If it’s not protected set though, you can easily create an extension method and integrate it into the class.  
  
 Thanks, 
  
 Ben 
  


Thanks Ben,


That makes sense now that the stream position was at the end, I'll put that change in.


I ended up creating an extension method for our own layer objects to create the wrapper ThinkGeo layer/source for them which makes it a nice simple call to create now.


Brian



Brian, 
  
 That’s great you make it around.  Let me know if anything else we can help. 
  
 Thanks, 
  
 Ben