/// <summary> /// Creates a bitmap of the requested size that covers the specified geographic extent using /// the current symbolizer for this layer. This does not have any drawing optimizations, /// or techniques to speed up performance and should only be used in special cases like /// draping of vector content onto a texture. It also doesn't worry about selections. /// </summary> /// <param name="geographicExtent">The extent to use when computing the snapshot.</param> /// <param name="width">The integer height of the bitmap. The height is calculated based on /// the aspect ratio of the specified geographic extent.</param> /// <returns>A Bitmap object</returns> public Bitmap SnapShot(IEnvelope geographicExtent, int width) { int height = Convert.ToInt32((geographicExtent.Height / geographicExtent.Width) * width); Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(bmp); ImageProjection p = new ImageProjection(geographicExtent, new Rectangle(0, 0, width, height)); DrawSnapShot(g, p); g.Dispose(); OnSnapShotTaken(bmp); return bmp; }
/// <summary> /// Creates a bmp texture and saves it to the specified filename. The filename should end in bmp. /// This also generates a bpw world file for the texture. /// </summary> /// <param name="filename">The string filename to write to</param> /// <param name="progressHandler">The progress handler for creating a new bitmap.</param> /// <exception cref="MapWindow.Main.FileCantBeDeletedException">The file could not be deleted because it is in use by another application.</exception> public void WriteBitmap(string filename, IProgressHandler progressHandler) { try { if (File.Exists(filename)) File.Delete(filename); // we expect textures to get overwritten a lot, so just delete this } catch { throw new FileCantBeDeletedException(filename); } Bitmap bmp = new Bitmap(DataSet.NumColumns, DataSet.NumRows, System.Drawing.Imaging.PixelFormat.Format32bppArgb); bmp.Save(filename); // for some reason lockbits doesn't work unless we save a copy first. if (_symbolizer.DrapeVectorLayers == false) { // Generate the colorscheme, modified by hillshading if that hillshading is used all in one pass DataSet.DrawToBitmap(Symbolizer, bmp, progressHandler); } else { // work backwards. when we get to this layer do the colorscheme. // First, use this raster and its colorschme to drop the background DataSet.PaintColorSchemeToBitmap(Symbolizer, bmp, progressHandler); // Set up a graphics object with a transformation pre-set so drawing a geographic coordinate // will draw to the correct location on the bitmap Graphics g = Graphics.FromImage(bmp); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; IEnvelope extents = DataSet.Bounds.Envelope; Rectangle target = new Rectangle(0, 0, bmp.Width, bmp.Height); ImageProjection ip = new ImageProjection(extents, target); // Cycle through each layer, and as long as it is not this layer, draw the bmp foreach (ILegendItem layer in GetParentItem().LegendItems) { // Temporarilly I am only interested in doing this for vector datasets IFeatureLayer fl = layer as IFeatureLayer; if (fl == null) continue; fl.DrawSnapShot(g, ip); } if (Symbolizer.ShadedRelief.IsUsed) { // After we have drawn the underlying texture, apply a hillshade if it is requested Symbolizer.PaintShadingToBitmap(bmp, progressHandler); } } bmp.Save(Path.ChangeExtension(DataSet.Filename, ".bmp"), System.Drawing.Imaging.ImageFormat.Bmp); bmp.Dispose(); // Create a world file so that the bmp itself becomes geo-referenced string worldFile = Path.ChangeExtension(DataSet.Filename, ".bpw"); if (File.Exists(worldFile)) File.Delete(worldFile); FileStream fs = new FileStream(worldFile, FileMode.CreateNew, FileAccess.Write); StreamWriter tw = new StreamWriter(fs); // Affine Coefficients // X = 0 + 1 * column + 2 * row // Y = 3 + 4 * column + 5 * row double[] aff = DataSet.Bounds.AffineCoefficients; tw.WriteLine(aff[1].ToString()); tw.WriteLine(aff[2].ToString()); tw.WriteLine(aff[4].ToString()); tw.WriteLine(aff[5].ToString()); tw.WriteLine(aff[0].ToString()); tw.WriteLine(aff[3].ToString()); tw.Close(); // closes both tw and fs // World file organization (six values written in string format on separate lines) // ----------------------- // dx // rotationX // rotationY // dy // X - position // Y - position Symbolizer.Validate(); // Symbolizer.ColorSchemeHasChanged = false; //OnColorSchemeUpdated(); OnInvalidate(this, new EventArgs()); OnItemChanged(); }