public void ApplyFilters(ImageProcessingSettings imageProcessingSettings, Bitmap bitmap)
        {
            var filters = this.GetFilterList(imageProcessingSettings);

            foreach (IInPlaceFilter filter in filters)
            {
                lock (bitmap)
                {
                    filter.ApplyInPlace(bitmap);
                }
            }
        }
        public IList <IFilter> GetFilterList(ImageProcessingSettings imageProcessingSettings)
        {
            var filterList = new List <IFilter>();

            // Brightness
            if (imageProcessingSettings.BrightnessAdjustment.Value != 0)
            {
                BrightnessCorrection filter = new BrightnessCorrection(imageProcessingSettings.BrightnessAdjustment.Value);
                filterList.Add(filter);
            }

            // Contrast
            if (imageProcessingSettings.ContrastAdjustment.Value != 0)
            {
                ContrastCorrection filter = new ContrastCorrection(imageProcessingSettings.ContrastAdjustment.Value);
                filterList.Add(filter);
            }

            // Saturation
            if (imageProcessingSettings.SaturationAdjustment.Value != 0)
            {
                // Only use 60% of the available correction range
                float adjustedValue = ((float)imageProcessingSettings.SaturationAdjustment.Value / 100) * 60;

                float value = (float)adjustedValue / 100;
                SaturationCorrection filter = new SaturationCorrection(value);
                filterList.Add(filter);
            }

            // Sharpness
            if (imageProcessingSettings.SharpnessAdjustment.Value != 0)
            {
                double          sigma  = 1.5;
                GaussianSharpen filter = new GaussianSharpen(sigma, imageProcessingSettings.SharpnessAdjustment.Value);
                filterList.Add(filter);
            }


            // Red, Green, Blue
            if (imageProcessingSettings.RedAdjustment.Value != 0 ||
                imageProcessingSettings.GreenAdjustment.Value != 0 ||
                imageProcessingSettings.BlueAdjustment.Value != 0)
            {
                LevelsLinear filter = new LevelsLinear();

                if (imageProcessingSettings.RedAdjustment.Value != 0)
                {
                    float val = ((float)imageProcessingSettings.RedAdjustment.Value / 100) * 255;

                    if (imageProcessingSettings.RedAdjustment.Value > 0)
                    {
                        var finalVal = 255 - (int)val;
                        filter.InRed = new IntRange(0, finalVal);
                    }
                    else
                    {
                        val          = val * -1;
                        filter.InRed = new IntRange((int)val, 255);
                    }
                }

                if (imageProcessingSettings.GreenAdjustment.Value != 0)
                {
                    float val = ((float)imageProcessingSettings.GreenAdjustment.Value / 100) * 255;

                    if (imageProcessingSettings.GreenAdjustment.Value > 0)
                    {
                        var finalVal = 255 - (int)val;
                        filter.InGreen = new IntRange(0, finalVal);
                    }
                    else
                    {
                        val            = val * -1;
                        filter.InGreen = new IntRange((int)val, 255);
                    }
                }

                if (imageProcessingSettings.BlueAdjustment.Value != 0)
                {
                    float val = ((float)imageProcessingSettings.BlueAdjustment.Value / 100) * 255;

                    if (imageProcessingSettings.BlueAdjustment.Value > 0)
                    {
                        var finalVal = 255 - (int)val;
                        filter.InBlue = new IntRange(0, finalVal);
                    }
                    else
                    {
                        val           = val * -1;
                        filter.InBlue = new IntRange((int)val, 255);
                    }
                }

                filterList.Add(filter);
            }


            return(filterList);
        }
Esempio n. 3
0
        public async Task StitchImageTilesAsync(string tileDownloadDirectory, string stitchedTilesDirectory, bool deleteOriginals, IProgress <TileStitcherProgress> progress)
        {
            await Task.Run(() =>
            {
                var tileStitcherProgress = new TileStitcherProgress();

                this.imageProcessingFilters     = new ImageProcessingFilters();
                this.xmlSerializer              = new XmlSerializer(typeof(ImageTile));
                this.stitchedImageXmlSerializer = new XmlSerializer(typeof(StitchedImage));

                int startTileX;
                int startTileY;
                int endTileX;
                int endTileY;

                // Get the top left tile X & Y and the bottom right tile X & Y
                // We can work everything else out from this
                this.GetStartingAndEndTileXY(tileDownloadDirectory, out startTileX, out startTileY, out endTileX, out endTileY);

                //Debug.WriteLine("startTileX " + startTileX);
                //Debug.WriteLine("startTileY " + startTileY);
                //Debug.WriteLine("endTileX " + endTileX);
                //Debug.WriteLine("endTileY " + endTileY);

                int numberOfTilesX = (endTileX - startTileX) + 1;
                int numberOfTilesY = (endTileY - startTileY) + 1;

                //Debug.WriteLine("Tiles X " + numberOfTilesX);
                //Debug.WriteLine("Tiles Y " + numberOfTilesY);
                //Debug.WriteLine("Filename prefix " + filenamePrefix);

                var firstImageTile = this.LoadImageTile(tileDownloadDirectory, startTileX, startTileY);

                // Get some info from the first tile. We can assume all tiles have these
                // properties or something is very wrong
                var imageSource = firstImageTile.Source;
                var zoomLevel   = firstImageTile.ZoomLevel;
                var tileWidth   = firstImageTile.Width;
                var tileHeight  = firstImageTile.Height;

                int maxTilesPerStitchedImageX = AeroSceneryManager.Instance.Settings.MaximumStitchedImageSize.Value;
                int maxTilesPerStitchedImageY = AeroSceneryManager.Instance.Settings.MaximumStitchedImageSize.Value;

                // Calculate the size of our stitched images in each direction
                var imageSizeX = maxTilesPerStitchedImageX * tileWidth;
                var imageSizeY = maxTilesPerStitchedImageY * tileHeight;

                // Calculate how many images we need
                var requiredStitchedImagesX = (int)Math.Ceiling((float)numberOfTilesX / (float)maxTilesPerStitchedImageX);
                var requiredStitchedImagesY = (int)Math.Ceiling((float)numberOfTilesY / (float)maxTilesPerStitchedImageY);
                var requiredStichedImages   = requiredStitchedImagesX * requiredStitchedImagesY;

                int imageTileOffsetX = 0;
                int imagetileOffsetY = 0;

                tileStitcherProgress.TotalStitchedImages = requiredStichedImages;

                // Loop through each stitched image that we will need
                for (int stitchedImagesYIx = 0; stitchedImagesYIx < requiredStitchedImagesY; stitchedImagesYIx++)
                {
                    for (int stitchedImagesXIx = 0; stitchedImagesXIx < requiredStitchedImagesX; stitchedImagesXIx++)
                    {
                        imageTileOffsetX = stitchedImagesXIx * maxTilesPerStitchedImageX;
                        imagetileOffsetY = stitchedImagesYIx * maxTilesPerStitchedImageY;

                        // This might not be right, but it's a reasonable estimate. We wont know until we read each file
                        tileStitcherProgress.TotalImageTilesForCurrentStitchedImage = maxTilesPerStitchedImageX * maxTilesPerStitchedImageY;

                        int columnsUsed = 0;
                        int rowsUsed    = 0;

                        // By giving these incorrect values, we can be sure they will we overwritten without having
                        // to make them nullable and do null checks
                        double northLatitude = -500;
                        double westLongitude = 500;
                        double southLatitude = 500;
                        double eastLongitude = -500;

                        using (Bitmap bitmap = new System.Drawing.Bitmap(imageSizeX, imageSizeY))
                        {
                            bitmap.MakeTransparent();

                            using (Graphics g = Graphics.FromImage(bitmap))
                            {
                                tileStitcherProgress.CurrentTilesRenderedForCurrentStitchedImage = 0;

                                // Work left to right, top to bottom
                                // Loop through rows
                                for (int yIx = 0; yIx < maxTilesPerStitchedImageY; yIx++)
                                {
                                    bool rowHasImages = false;

                                    // Loop through columns
                                    for (int xIx = 0; xIx < maxTilesPerStitchedImageX; xIx++)
                                    {
                                        int currentTileX = xIx + imageTileOffsetX + startTileX;
                                        int currentTileY = yIx + imagetileOffsetY + startTileY;

                                        var imageTileData = this.LoadImageTile(tileDownloadDirectory, currentTileX, currentTileY);

                                        if (imageTileData != null)
                                        {
                                            // Even if all the images in this row are invalid, the aero files are present
                                            // so an attempt was made to download something
                                            rowHasImages = true;

                                            // Update our overall stitched image lat and long maxima and minima
                                            // We want the highest NorthLatitude value of any image tile for this stitched image
                                            if (imageTileData.NorthLatitude > northLatitude)
                                            {
                                                northLatitude = imageTileData.NorthLatitude;
                                            }

                                            // We want the lowest SouthLatitude value of any image tile for this stitched image
                                            if (imageTileData.SouthLatitude < southLatitude)
                                            {
                                                southLatitude = imageTileData.SouthLatitude;
                                            }

                                            // We want the lowest WestLongitude value of any image tile for this stitched image
                                            if (imageTileData.WestLongitude < westLongitude)
                                            {
                                                westLongitude = imageTileData.WestLongitude;
                                            }

                                            // We want the highest EastLongitude value of any image tile for this stitched image
                                            if (imageTileData.EastLongitude > eastLongitude)
                                            {
                                                eastLongitude = imageTileData.EastLongitude;
                                            }

                                            var imageTileFilename = tileDownloadDirectory + imageTileData.FileName + "." + imageTileData.ImageExtension;

                                            Image tile = null;

                                            try
                                            {
                                                tile = Image.FromFile(imageTileFilename);

                                                if (tile != null)
                                                {
                                                    var imagePointX = (xIx * imageTileData.Width);
                                                    var imagePointY = (yIx * imageTileData.Width);

                                                    g.DrawImage(tile, new PointF(imagePointX, imagePointY));
                                                    tileStitcherProgress.CurrentTilesRenderedForCurrentStitchedImage++;
                                                    progress.Report(tileStitcherProgress);
                                                }

                                                tile.Dispose();
                                            }
                                            catch (Exception)
                                            {
                                                // The image file was probably invalid, but there's not a lot we can do
                                                // Leave it transparent
                                            }
                                            finally
                                            {
                                                // Even if the image was invalid, we still had an aero file for it
                                                // so it counts as a used column
                                                var colsUsedInThisRow = xIx + 1;

                                                if (columnsUsed < colsUsedInThisRow)
                                                {
                                                    columnsUsed = colsUsedInThisRow;
                                                }

                                                if (tile != null)
                                                {
                                                    tile.Dispose();
                                                }
                                            }
                                        }
                                    }

                                    if (rowHasImages)
                                    {
                                        rowsUsed++;
                                    }
                                }
                            }

                            var stitchFilename = String.Format("{0}_{1}_stitch_{2}_{3}.png", imageSource, zoomLevel, stitchedImagesXIx + 1, stitchedImagesYIx + 1);
                            var stitchedImage  = new StitchedImage();

                            stitchedImage.ImageExtension   = "png";
                            stitchedImage.NorthLatitude    = northLatitude;
                            stitchedImage.WestLongitude    = westLongitude;
                            stitchedImage.SouthLatitude    = southLatitude;
                            stitchedImage.EastLongitude    = eastLongitude;
                            stitchedImage.Width            = columnsUsed * tileWidth;
                            stitchedImage.Height           = rowsUsed * tileHeight;
                            stitchedImage.Source           = imageSource;
                            stitchedImage.ZoomLevel        = zoomLevel;
                            stitchedImage.StichedImageSetX = stitchedImagesXIx + 1;
                            stitchedImage.StichedImageSetY = stitchedImagesYIx + 1;

                            //Debug.WriteLine("Rows Used " + rowsUsed);
                            //Debug.WriteLine("Columns Used " + columnsUsed);

                            var settings = AeroSceneryManager.Instance.Settings;

                            if (settings.EnableImageProcessing.Value)
                            {
                                var imageProcessingSettings = new ImageProcessingSettings();
                                imageProcessingSettings.BrightnessAdjustment = settings.BrightnessAdjustment;
                                imageProcessingSettings.ContrastAdjustment   = settings.ContrastAdjustment;
                                imageProcessingSettings.SaturationAdjustment = settings.SaturationAdjustment;
                                imageProcessingSettings.SharpnessAdjustment  = settings.SharpnessAdjustment;
                                imageProcessingSettings.RedAdjustment        = settings.RedAdjustment;
                                imageProcessingSettings.GreenAdjustment      = settings.GreenAdjustment;
                                imageProcessingSettings.BlueAdjustment       = settings.BlueAdjustment;

                                this.imageProcessingFilters.ApplyFilters(imageProcessingSettings, bitmap);
                            }


                            // Have we drawn an image to the maximum number of rows and columns for this image?
                            if (columnsUsed == maxTilesPerStitchedImageX && rowsUsed == maxTilesPerStitchedImageY)
                            {
                                // Save the bitmap as it is
                                log.InfoFormat("Saving stitched image {0}", stitchFilename);
                                bitmap.Save(stitchedTilesDirectory + stitchFilename, ImageFormat.Png);
                                tileStitcherProgress.CurrentStitchedImage++;
                            }
                            else
                            {
                                // Resize the bitmap down to the used number of rows and columns
                                log.InfoFormat("Cropping stitched image {0}", stitchFilename);
                                CropBitmap(bitmap, new Rectangle(0, 0, columnsUsed *tileWidth, rowsUsed *tileHeight), stitchedTilesDirectory, stitchFilename);
                                tileStitcherProgress.CurrentStitchedImage++;
                            }

                            this.SaveStitchedImageAeroFile(this.stitchedImageXmlSerializer, stitchedImage, stitchedTilesDirectory);
                        }
                    }
                }

                if (deleteOriginals)
                {
                }
            });
        }