Example #1
0
        /// <summary>
        /// This takes an original image and calculates the header content for all the lower resolution tiles.
        /// This does not actually write the bytes for those images.
        /// </summary>
        /// <param name="numRows">The number of rows in the original image</param>
        /// <param name="numColumns">The number of columns in the original image</param>
        /// <param name="affineCoefficients">
        /// the array of doubles in ABCDEF order
        /// X' = A + Bx + Cy
        /// Y' = D + Ex + Fy
        /// </param>
        public void CreateHeaders(int numRows, int numColumns, double[] affineCoefficients)
        {
            Header = new PyramidHeader();
            List <PyramidImageHeader> headers = new List <PyramidImageHeader>();
            int  scale  = 0;
            long offset = 0;
            int  nr     = numRows;
            int  nc     = numColumns;

            while (nr > 2 && nc > 2)
            {
                PyramidImageHeader ph = new PyramidImageHeader();
                ph.SetAffine(affineCoefficients, scale);
                ph.SetNumRows(numRows, scale);
                ph.SetNumColumns(numColumns, scale);
                ph.Offset = offset;
                offset   += ph.NumRows * ph.NumColumns * 4;
                nr        = nr / 2;
                nc        = nc / 2;
                scale++;
                headers.Add(ph);
            }

            Header.ImageHeaders = headers.ToArray();
        }
Example #2
0
        /// <summary>
        /// This assumes that the base image has been written to the file. This will now attempt to calculate
        /// the down-sampled images.
        /// </summary>
        public void CreatePyramids2()
        {
            double        count = Header.ImageHeaders[0].NumRows;
            ProgressMeter pm    = new ProgressMeter(ProgressHandler, "Generating Pyramids", count);
            int           prog  = 0;

            for (int scale = 0; scale < Header.ImageHeaders.Length - 1; scale++)
            {
                PyramidImageHeader ph = Header.ImageHeaders[scale];
                int rows = ph.NumRows;
                int cols = ph.NumColumns;

                // Horizontal Blur Pass
                byte[] r1 = ReadWindow(0, 0, 1, cols, scale);
                byte[] r2 = ReadWindow(1, 0, 1, cols, scale);

                byte[] vals = Blur(null, r1, r2);
                vals = DownSample(vals);
                WriteWindow(vals, 0, 0, 1, cols / 2, scale + 1);
                prog++;
                pm.CurrentValue = prog;

                byte[] r3 = ReadWindow(2, 0, 1, cols, scale);
                vals = Blur(r1, r2, r3);
                vals = DownSample(vals);
                WriteWindow(vals, 1, 0, 1, cols / 2, scale + 1);
                prog++;
                pm.CurrentValue = prog;
                for (int row = 3; row < rows - 1; row++)
                {
                    r1 = r2;
                    r2 = r3;
                    r3 = ReadWindow(row, 0, 1, cols, scale);
                    prog++;
                    pm.CurrentValue = prog;
                    if (row % 2 == 1)
                    {
                        continue;
                    }

                    vals = Blur(r1, r2, r3);
                    vals = DownSample(vals);
                    WriteWindow(vals, (row / 2) - 1, 0, 1, cols / 2, scale + 1);
                }

                if ((rows - 1) % 2 == 0)
                {
                    vals = Blur(r2, r3, r2);
                    vals = DownSample(vals);
                    WriteWindow(vals, (rows / 2) - 1, 0, 1, cols / 2, scale + 1);
                }

                prog++;
                pm.CurrentValue = prog;
            }

            pm.Reset();
        }
Example #3
0
        /// <summary>
        /// For big images this won't work, but this gets the 0 scale original image as a bitmap.
        /// </summary>
        /// <returns>The original image as bitmap.</returns>
        public override Bitmap GetBitmap()
        {
            PyramidImageHeader ph   = Header.ImageHeaders[0];
            Rectangle          bnds = new Rectangle(0, 0, ph.NumColumns, ph.NumRows);

            byte[]     data  = ReadWindow(0, 0, ph.NumRows, ph.NumColumns, 0);
            Bitmap     bmp   = new Bitmap(ph.NumColumns, ph.NumRows);
            BitmapData bData = bmp.LockBits(bnds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            Marshal.Copy(data, 0, bData.Scan0, data.Length);
            bmp.UnlockBits(bData);
            return(bmp);
        }
Example #4
0
        /// <summary>
        /// Reads the header only from the specified mwi file.  The header is in xml format.
        /// This is a test.  We may have to jurry rig the thing to ensure it ignores the actual
        /// image content.
        /// </summary>
        /// <param name="fileName">Whether this is the mwi or mwh file, this reads the mwh file for the fileName.</param>
        public void ReadHeader(string fileName)
        {
            string        header = Path.ChangeExtension(fileName, "mwh");
            XmlSerializer s      = new XmlSerializer(typeof(PyramidHeader));
            TextReader    r      = new StreamReader(header);

            _header = (PyramidHeader)s.Deserialize(r);
            PyramidImageHeader ph = _header.ImageHeaders[0];

            Bounds = new RasterBounds(ph.NumRows, ph.NumColumns, ph.Affine);
            Width  = _header.ImageHeaders[0].NumColumns;
            Height = _header.ImageHeaders[0].NumRows;
            r.Close();
        }
Example #5
0
        /// <summary>
        /// This writes a window of byte values (ARGB order) to the file. This assumes that the headers already exist.
        /// If the headers have not been created or the bounds extend beyond the header numRows and numColumns for the
        /// specified scale, this will throw an exception.
        /// </summary>
        /// <param name="startRow">The integer start row</param>
        /// <param name="startColumn">The integer start column</param>
        /// <param name="numRows">The integer number of rows in the window</param>
        /// <param name="numColumns">The integer number of columns in the window</param>
        /// <param name="scale">The integer scale. 0 is the original image.</param>
        /// <returns>The bytes created by this process</returns>
        /// <exception cref="PyramidUndefinedHeaderException">Occurs when attempting to write data before the headers are defined.</exception>
        /// <exception cref="PyramidOutOfBoundsException">Occurs if the range specified is outside the bounds for the specified image scale.</exception>
        public byte[] ReadWindow(int startRow, int startColumn, int numRows, int numColumns, int scale)
        {
            byte[] bytes = new byte[numRows * numColumns * 4];
            if (Header == null || Header.ImageHeaders.Length <= scale || Header.ImageHeaders[scale] == null)
            {
                throw new PyramidUndefinedHeaderException();
            }

            PyramidImageHeader ph = Header.ImageHeaders[scale];

            if (startRow < 0 || startColumn < 0 || numRows + startRow > ph.NumRows || numColumns + startColumn > ph.NumColumns)
            {
                throw new PyramidOutOfBoundsException();
            }

            if (startColumn == 0 && numColumns == ph.NumColumns)
            {
                // write all in one pass.
                FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.Read);

                fs.Seek(ph.Offset, SeekOrigin.Begin);
                fs.Seek((startRow * ph.NumColumns) * 4, SeekOrigin.Current);
                fs.Read(bytes, 0, bytes.Length);
                fs.Close();
            }
            else
            {
                // write all in one pass.
                FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.Read);
                fs.Seek(ph.Offset, SeekOrigin.Begin);
                fs.Seek((startRow * ph.NumColumns) * 4, SeekOrigin.Current);
                int before = startColumn * 4;
                int after  = (ph.NumColumns - (startColumn + numColumns)) * 4;
                for (int row = startRow; row < startRow + numRows; row++)
                {
                    fs.Seek(before, SeekOrigin.Current);
                    fs.Read(bytes, (row - startRow) * numColumns * 4, numColumns * 4);
                    fs.Seek(after, SeekOrigin.Current);
                }

                fs.Close();
            }

            return(bytes);
        }
Example #6
0
        /// <summary>
        /// This writes a window of byte values (ARGB order) to the file. This assumes that the headers already exist.
        /// If the headers have not been created or the bounds extend beyond the header numRows and numColumns for the
        /// specified scale, this will throw an exception.
        /// </summary>
        /// <param name="bytes">The byte array.</param>
        /// <param name="startRow">The integer start row.</param>
        /// <param name="startColumn">The integer start column.</param>
        /// <param name="numRows">The integer number of rows in the window.</param>
        /// <param name="numColumns">The integer number of columns in the window.</param>
        /// <param name="scale">The integer scale. 0 is the original image.</param>
        /// <param name="pm">The progress meter to advance by row. Calls Next() for each row.</param>
        /// <exception cref="PyramidUndefinedHeaderException">Occurs when attempting to write data before the headers are defined.</exception>
        /// <exception cref="PyramidOutOfBoundsException">Occurs if the range specified is outside the bounds for the specified image scale.</exception>
        public void WriteWindow(byte[] bytes, int startRow, int startColumn, int numRows, int numColumns, int scale, ProgressMeter pm)
        {
            if (Header == null || Header.ImageHeaders.Length <= scale || Header.ImageHeaders[scale] == null)
            {
                throw new PyramidUndefinedHeaderException();
            }

            PyramidImageHeader ph = Header.ImageHeaders[scale];

            if (startRow < 0 || startColumn < 0 || numRows + startRow > ph.NumRows || numColumns + startColumn > ph.NumColumns)
            {
                throw new PyramidOutOfBoundsException();
            }

            if (startColumn == 0 && numColumns == ph.NumColumns)
            {
                // write all in one pass.
                FileStream fs = new(Filename, FileMode.OpenOrCreate, FileAccess.Write);

                fs.Seek(ph.Offset, SeekOrigin.Begin);
                fs.Seek((startRow * ph.NumColumns) * 4, SeekOrigin.Current);
                fs.Write(bytes, 0, bytes.Length);
                fs.Close();
            }
            else
            {
                // write one row at a time
                FileStream fs = new(Filename, FileMode.Open, FileAccess.Write);
                fs.Seek(ph.Offset, SeekOrigin.Begin);
                fs.Seek((startRow * ph.NumColumns) * 4, SeekOrigin.Current);
                int before = startColumn * 4;
                int after  = (ph.NumColumns - (startColumn + numColumns)) * 4;
                for (int row = startRow; row < startRow + numRows; row++)
                {
                    fs.Seek(before, SeekOrigin.Current);
                    fs.Write(bytes, (row - startRow) * numColumns * 4, numColumns * 4);
                    fs.Seek(after, SeekOrigin.Current);
                    pm.Next();
                }

                fs.Write(bytes, 0, bytes.Length);
                fs.Close();
            }
        }
Example #7
0
        /// <summary>
        /// For big images the scale that is just one step larger than the specified window will be used.
        /// </summary>
        /// <param name="envelope">The envelope containing the geographic extent.</param>
        /// <param name="window">The rectangle containing the window extent.</param>
        /// <returns>The bitmap.</returns>
        public override Bitmap GetBitmap(Extent envelope, Rectangle window)
        {
            if (window.Width == 0 || window.Height == 0)
            {
                return(null);
            }
            if (Header?.ImageHeaders?[0] == null)
            {
                return(null);
            }

            Rectangle expWindow   = window.ExpandBy(1);
            Envelope  expEnvelope = envelope.ToEnvelope().Reproportion(window, expWindow);

            Envelope env = expEnvelope.Intersection(Bounds.Extent.ToEnvelope());

            if (env == null || env.IsNull || env.Height == 0 || env.Width == 0)
            {
                return(null);
            }

            PyramidImageHeader he = Header.ImageHeaders[0];
            int scale;

            double cwa = expWindow.Width / expEnvelope.Width;
            double cha = expWindow.Height / expEnvelope.Height;

            for (scale = 0; scale < Header.ImageHeaders.Length; scale++)
            {
                PyramidImageHeader ph = Header.ImageHeaders[scale];

                if (cwa > ph.NumColumns / Bounds.Width || cha > ph.NumRows / Bounds.Height)
                {
                    if (scale > 0)
                    {
                        scale -= 1;
                    }
                    break;
                }

                he = ph;
            }

            RasterBounds overviewBounds = new RasterBounds(he.NumRows, he.NumColumns, he.Affine);
            Rectangle    r = overviewBounds.CellsContainingExtent(envelope);

            if (r.Width == 0 || r.Height == 0)
            {
                return(null);
            }

            byte[]     vals  = ReadWindow(r.Y, r.X, r.Height, r.Width, scale);
            Bitmap     bmp   = new Bitmap(r.Width, r.Height);
            BitmapData bData = bmp.LockBits(new Rectangle(0, 0, r.Width, r.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            Marshal.Copy(vals, 0, bData.Scan0, vals.Length);
            bmp.UnlockBits(bData);

            // Use the cell coordinates to determine the affine coefficients for the cells retrieved.
            double[] affine = new double[6];
            Array.Copy(he.Affine, affine, 6);
            affine[0] = affine[0] + (r.X * affine[1]) + (r.Y * affine[2]);
            affine[3] = affine[3] + (r.X * affine[4]) + (r.Y * affine[5]);

            if (window.Width == 0 || window.Height == 0)
            {
                return(null);
            }

            Bitmap   result = new Bitmap(window.Width, window.Height);
            Graphics g      = Graphics.FromImage(result);

            // Gets the scaling factor for converting from geographic to pixel coordinates
            double dx = window.Width / envelope.Width;
            double dy = window.Height / envelope.Height;

            double[] a = affine;

            // gets the affine scaling factors.
            float  m11    = Convert.ToSingle(a[1] * dx);
            float  m22    = Convert.ToSingle(a[5] * -dy);
            float  m21    = Convert.ToSingle(a[2] * dx);
            float  m12    = Convert.ToSingle(a[4] * -dy);
            double l      = a[0] - (.5 * (a[1] + a[2])); // Left of top left pixel
            double t      = a[3] - (.5 * (a[4] + a[5])); // top of top left pixel
            float  xShift = (float)((l - envelope.MinX) * dx);
            float  yShift = (float)((envelope.MaxY - t) * dy);

            g.Transform       = new Matrix(m11, m12, m21, m22, xShift, yShift);
            g.PixelOffsetMode = PixelOffsetMode.Half;
            if (m11 > 1 || m22 > 1)
            {
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
            }

            g.DrawImage(bmp, new PointF(0, 0));
            bmp.Dispose();
            g.Dispose();
            return(result);
        }
Example #8
0
 /// <summary>
 /// This takes an original image and calculates the header content for all the lower resolution tiles.
 /// This does not actually write the bytes for those images.
 /// </summary>
 /// <param name="numRows">The number of rows in the original image</param>
 /// <param name="numColumns">The number of columns in the original image</param>
 /// <param name="affineCoefficients">
 /// the array of doubles in ABCDEF order
 /// X' = A + Bx + Cy
 /// Y' = D + Ex + Fy
 /// </param>
 public void CreateHeaders(int numRows, int numColumns, double[] affineCoefficients)
 {
     _header = new PyramidHeader();
     List<PyramidImageHeader> headers = new List<PyramidImageHeader>();
     int scale = 0;
     long offset = 0;
     int nr = numRows;
     int nc = numColumns;
     while (nr > 2 && nc > 2)
     {
         PyramidImageHeader ph = new PyramidImageHeader();
         ph.SetAffine(affineCoefficients, scale);
         ph.SetNumRows(numRows, scale);
         ph.SetNumColumns(numColumns, scale);
         ph.Offset = offset;
         offset += (ph.NumRows * ph.NumColumns * 4);
         nr = nr / 2;
         nc = nc / 2;
         scale++;
         headers.Add(ph);
     }
     _header.ImageHeaders = headers.ToArray();
 }