// False if the user canceled, true otherwise
        private static bool Do_ApplyFilter(MapWinGIS.Image SourceImage, ref MapWinGIS.Image DestImage, float[,] filter, bool ShowProgressDialog, MapWinGIS.ICallback ICallBack)
        {
            int Prog    = 0;
            int OldProg = 0;


            // Report unnamed as differently from null
            string SourceFile = "null";
            string DestFile   = "null";

            if (SourceImage != null)
            {
                SourceFile = SourceImage.Filename;
                if (SourceFile == null)
                {
                    SourceFile = "Unnamed";
                }
            }
            else
            {
                MapWinUtility.Logger.Dbg("Argument Exception: SourceImage cannot be null.");
                throw new ArgumentException("SourceImage cannot be null.");
            }
            if (DestImage != null)
            {
                DestFile = SourceImage.Filename;
                if (DestFile == null)
                {
                    DestFile = "Unnamed";
                }
            }
            else
            {
                MapWinUtility.Logger.Dbg("Argument Exception: DestImage cannot be null.");
                throw new ArgumentException("DestImage cannot be null.");
            }

            MapWinUtility.Logger.Dbg("Do_ApplyFilter(SourceImage: " + SourceImage.Filename + ",\n" +
                                     "            DestImage: " + DestImage.Filename + ",\n" +
                                     "            filter: [" + filter.GetUpperBound(0) + ", " + filter.GetUpperBound(1) + "],\n" +
                                     "            ShowProgressDialog: " + ShowProgressDialog.ToString() + ",\n" +
                                     "            ICallback)");

            ProgressDialog MyProgress = new ProgressDialog();


            if (filter.GetUpperBound(0) == 0 || filter.GetUpperBound(1) == 0)
            {
                MapWinUtility.Logger.Dbg("Argument Exception: Filter must have values.");
                throw new ArgumentException("Filter must have values.");
            }

            // Ensure the filter is smaller than the image.
            if (filter.GetUpperBound(0) > SourceImage.Height || filter.GetUpperBound(1) > SourceImage.Width)
            {
                throw new ArgumentException("The filter is too large for this image.  In order for convolution to work, the image must be larger than the filter.");
            }

            // We are going to assume mirror handling of edges
            ExtHandler LocHandler = new ExtHandler(SourceImage.Height, SourceImage.Width);

            // convolve
            int R, G, B, color;
            int Xcor = 0, Ycor = 0; // Corrected X and Y locations to take into account mirror
            int fH, fW;             // stores the values of half the height and width of the filter

            fH = (int)filter.GetUpperBound(0) / 2;
            fW = (int)filter.GetUpperBound(1) / 2;

            if (ICallBack == null)
            {
                MyProgress.Show();
                MyProgress.WriteMessage("Applying Filter...");
                MapWinUtility.Logger.Progress("Applying Filter...", Prog, OldProg);
            }
            for (int row = 0; row < SourceImage.Height; row++)
            {
                for (int col = 0; col < SourceImage.Width; col++)
                {
                    float fR = 0;
                    float fG = 0;
                    float fB = 0;

                    for (int Y = 0; Y <= filter.GetUpperBound(0); Y++)
                    {
                        for (int X = 0; X <= filter.GetUpperBound(1); X++)
                        {
                            // Read the color for this spot
                            LocHandler.CorrectLocation(col + X - fW, row + Y - fH, ref Xcor, ref Ycor);
                            color = SourceImage.get_Value(Ycor, Xcor);
                            R     = color % 256;
                            G     = (int)(color / 256) % 256;
                            B     = (int)(color / (256 * 256));

                            // convolve the values with the filter and add them to the accumulators
                            fR += filter[Y, X] * R;
                            fG += filter[Y, X] * G;
                            fB += filter[Y, X] * B;
                        }
                    }
                    // After convolution, write the combined value to the file
                    R = (int)fR;
                    if (R > 255)
                    {
                        R = 255;
                    }
                    G = (int)fG;
                    if (G > 255)
                    {
                        G = 255;
                    }
                    B = (int)fB;
                    if (B > 255)
                    {
                        B = 255;
                    }
                    color = (256 * 256) * B + 256 * G + R;
                    DestImage.set_Value(row, col, color);
                }
                Prog = (100 * row) / SourceImage.Height;
                if (Prog > OldProg)
                {
                    if (ICallBack != null)
                    {
                        ICallBack.Progress("Status", Prog, "Filtering Image...");
                    }


                    if (ShowProgressDialog == true)
                    {
                        MyProgress.Progress = Prog;

                        if (MyProgress.IsCanceled == true)
                        {
                            MapWinUtility.Logger.Message("Apply Filter was canceled.", "Process Canceled", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information, System.Windows.Forms.DialogResult.OK);
                            return(false);
                        }
                    }

                    MapWinUtility.Logger.Progress("Filtering Image..." + Prog.ToString() + "%Complete", Prog, OldProg);
                    OldProg = Prog;
                }
            }
            MyProgress.Hide();
            DestImage.dX = SourceImage.dX;
            DestImage.dY = SourceImage.dY;
            DestImage.SetProjection(SourceImage.GetProjection());
            DestImage.Save(DestImage.Filename, true, MapWinGIS.ImageType.USE_FILE_EXTENSION, null);
            MapWinUtility.Logger.Dbg("Finsihed ApplyFilter");
            return(true);
        }
        /// <summary>
        /// Reprojects an image using the currently defined projective transform.
        /// Be sure to call Derive_Coefficients first.  This loops through point by point
        /// so won't be very fast.
        /// </summary>
        /// <param name="SourceImage">A MapWinGIS.Image object to be transformed</param>
        /// <param name="resultImage">A string representing the destination filename</param>
        /// <param name="ICallBack">A MapWinGIS.ICallback interface for progress messages</param>
        /// <remarks>ArgumentExceptions should be trapped for user error, but other types should be reported as bugs</remarks>
        public void ProjectImage(MapWinGIS.Image SourceImage, string resultImage, MapWinGIS.ICallback ICallBack)
        {
            bool res;

            if (SourceImage == null)
            {
                throw new ArgumentException("Source Image cannot be null.");
            }
            if (resultImage == null)
            {
                resultImage = System.IO.Path.ChangeExtension(SourceImage.Filename, "_Projected" + System.IO.Path.GetExtension(SourceImage.Filename));
            }
            if (Defined == false)
            {
                throw new ApplicationException("You first have to define the coefficients by calling Derive_Coefficients.");
            }
            MapWinGIS.Image DestImage = new MapWinGIS.Image();
            try
            {
                res = DestImage.CreateNew(m_OutputWidth, m_OutputHeight);
            }
            catch
            {
                throw new ApplicationException("The current Image object crashes with images too large to fit in memory.");
            }
            if (res == false)
            {
                throw new ApplicationException("Application Exception when Creating New: " + DestImage.get_ErrorMsg(DestImage.LastErrorCode));
            }
            if (res == false)
            {
                throw new ApplicationException("Image object is having trouble creating a new image.");
            }
            for (int Yprj = 0; Yprj < m_OutputHeight; Yprj++)
            {
                for (int Xprj = 0; Xprj < m_OutputWidth; Xprj++)
                {
                    double X, Y;
                    double X1, Y1;
                    int    Xorig = 0;
                    int    Yorig = 0;

                    X1 = (double)Xprj;
                    Y1 = (double)Yprj;
                    X  = -(b * Y1 - Y1 * h * c + e * c - X1 * e + f * X1 * h - f * b) / (X1 * h * d + b * Y1 * g - b * d - X1 * g * e + a * e - a * Y1 * h);
                    Y  = -(c * Y1 * g + X1 * d - a * Y1 - X1 * g * f - c * d + a * f) / (X1 * h * d + b * Y1 * g - b * d - X1 * g * e + a * e - a * Y1 * h);

                    if (X < 0 || Y < 0 || X > m_InputWidth || Y > m_InputHeight)
                    {
                        continue;
                    }
                    // using nearest neighbors
                    Xorig = rnd(X);
                    Yorig = rnd(Y);

                    int Rowo = (m_InputHeight - 1) - Yorig;
                    int pVal = SourceImage.get_Value(Rowo, Xorig);

                    int row = (m_OutputHeight - 1) - Yprj;
                    DestImage.set_Value(row, Xprj, pVal);
                }
                if (ICallBack != null)
                {
                    ICallBack.Progress("Status", (Yprj * 100) / m_OutputHeight, "Row: " + Yprj.ToString());
                }
            }

            DestImage.dX        = m_OutputCellWidth;
            DestImage.dY        = m_OutputCellHeight;
            DestImage.XllCenter = m_XllCenter;
            DestImage.YllCenter = m_YllCenter;
            string dir = System.IO.Path.GetDirectoryName(resultImage);

            if (!System.IO.Directory.Exists(dir))
            {
                System.IO.Directory.CreateDirectory(dir);
            }
            if (System.IO.Path.GetExtension(resultImage) == ".jpg")
            {
                resultImage = System.IO.Path.ChangeExtension(resultImage, ".bmp");
            }
            res = DestImage.Save(resultImage, true, MapWinGIS.ImageType.USE_FILE_EXTENSION, ICallBack);
            if (res == false)
            {
                throw new ApplicationException(DestImage.get_ErrorMsg(DestImage.LastErrorCode));
            }
            DestImage.SetProjection(SourceImage.GetProjection());
            DestImage.Close();
            if (ICallBack != null)
            {
                ICallBack.Progress("Status", 0, "Saved output as " + DestImage.Filename);
            }
        }