예제 #1
0
        /// <summary>
        /// Helper method to try to get an image in the specified format from the dataObject
        /// </summary>
        /// <param name="format">string with the format</param>
        /// <param name="dataObject">IDataObject</param>
        /// <returns>Image or null</returns>
        private static Image GetImageFormat(string format, IDataObject dataObject)
        {
            MemoryStream imageStream = GetFromDataObject(dataObject, format) as MemoryStream;

            if (isValidStream(imageStream))
            {
                try
                {
                    using (FileStream fs = new FileStream(@"C:\Localdata\test.png", FileMode.OpenOrCreate))
                    {
                        imageStream.WriteTo(fs);
                    }
                    imageStream.Seek(0, SeekOrigin.Begin);
                    using (Image tmpImage = Image.FromStream(imageStream, true, true))
                    {
                        if (tmpImage != null)
                        {
                            LOG.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
                            return(ImageHelper.Clone(tmpImage));
                        }
                    }
                }
                catch (Exception streamImageEx)
                {
                    LOG.Error(string.Format("Problem retrieving {0} from clipboard.", format), streamImageEx);
                }
            }
            return(null);
        }
예제 #2
0
 /// <summary>
 /// Download the uri to Bitmap
 /// </summary>
 /// <param name="url">Of an image</param>
 /// <returns>Bitmap</returns>
 public static Image DownloadImage(string url)
 {
     try {
         string content;
         using (MemoryStream memoryStream = GetAsMemoryStream(url)) {
             try {
                 using (Image image = Image.FromStream(memoryStream)) {
                     return(ImageHelper.Clone(image, PixelFormat.Format32bppArgb));
                 }
             } catch (Exception) {
                 // If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead.
                 using (StreamReader streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) {
                     content = streamReader.ReadLine();
                 }
                 Regex imageUrlRegex = new Regex(@"(http|https)://.*(\.png|\.gif|\.jpg|\.tiff|\.jpeg|\.bmp)");
                 Match match         = imageUrlRegex.Match(content);
                 if (match.Success)
                 {
                     using (MemoryStream memoryStream2 = GetAsMemoryStream(match.Value)) {
                         using (Image image = Image.FromStream(memoryStream2)) {
                             return(ImageHelper.Clone(image, PixelFormat.Format32bppArgb));
                         }
                     }
                 }
                 throw;
             }
         }
     } catch (Exception e) {
         LOG.Error("Problem downloading the image from: " + url, e);
     }
     return(null);
 }
예제 #3
0
        /// <summary>
        /// Load a Greenshot surface
        /// </summary>
        /// <param name="fullPath"></param>
        /// <returns></returns>
        public static ISurface LoadGreenshotSurface(string fullPath, ISurface returnSurface)
        {
            if (string.IsNullOrEmpty(fullPath))
            {
                return(null);
            }
            Image fileImage = null;

            LOG.InfoFormat("Loading image from file {0}", fullPath);
            // Fixed lock problem Bug #3431881
            using (Stream surfaceFileStream = File.OpenRead(fullPath))
            {
                // And fixed problem that the bitmap stream is disposed... by Cloning the image
                // This also ensures the bitmap is correctly created

                // We create a copy of the bitmap, so everything else can be disposed
                surfaceFileStream.Position = 0;
                using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true))
                {
                    LOG.DebugFormat("Loaded {0} with Size {1}x{2} and PixelFormat {3}", fullPath, tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
                    fileImage = ImageHelper.Clone(tmpImage);
                }
                // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor)
                const int markerSize = 14;
                surfaceFileStream.Seek(-markerSize, SeekOrigin.End);
                string greenshotMarker;
                using (StreamReader streamReader = new StreamReader(surfaceFileStream))
                {
                    greenshotMarker = streamReader.ReadToEnd();
                    if (greenshotMarker == null || !greenshotMarker.StartsWith("Greenshot"))
                    {
                        throw new ArgumentException(string.Format("{0} is not a Greenshot file!", fullPath));
                    }
                    LOG.InfoFormat("Greenshot file format: {0}", greenshotMarker);
                    const int filesizeLocation = 8 + markerSize;
                    surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End);
                    long bytesWritten = 0;
                    using (BinaryReader reader = new BinaryReader(surfaceFileStream))
                    {
                        bytesWritten = reader.ReadInt64();
                        surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End);
                        returnSurface.LoadElementsFromStream(surfaceFileStream);
                    }
                }
            }
            if (fileImage != null)
            {
                returnSurface.Image = fileImage;
                LOG.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, fileImage.Width, fileImage.Height, fileImage.PixelFormat, fileImage.HorizontalResolution, fileImage.VerticalResolution);
            }
            return(returnSurface);
        }
예제 #4
0
        /// <summary>
        /// the DIB readed should solve the issue reported here: https://sourceforge.net/projects/greenshot/forums/forum/676083/topic/6354353/index/page/1
        /// </summary>
        /// <returns>Image</returns>
        private static Image GetDIBImage(IDataObject dataObejct)
        {
            try {
                // If the EnableSpecialDIBClipboardReader flag in the config is set, use the code from:
                // http://www.thomaslevesque.com/2009/02/05/wpf-paste-an-image-from-the-clipboard/
                // to read the DeviceIndependentBitmap from the clipboard, this might fix bug 3576125
                if (config.EnableSpecialDIBClipboardReader)
                {
                    MemoryStream dibStream = GetFromDataObject(dataObejct, DataFormats.Dib) as MemoryStream;
                    if (isValidStream(dibStream))
                    {
                        LOG.Info("Found valid DIB stream, trying to process it.");
                        byte[] dibBuffer = new byte[dibStream.Length];
                        dibStream.Read(dibBuffer, 0, dibBuffer.Length);
                        BitmapInfoHeader infoHeader = BinaryStructHelper.FromByteArray <BitmapInfoHeader>(dibBuffer);
                        LOG.InfoFormat("Using special DIB format reader for biCompression {0}", infoHeader.biCompression);
                        int  fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader));
                        uint infoHeaderSize = infoHeader.biSize;
                        int  fileSize       = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);

                        BitmapFileHeader fileHeader = new BitmapFileHeader();
                        fileHeader.bfType      = BitmapFileHeader.BM;
                        fileHeader.bfSize      = fileSize;
                        fileHeader.bfReserved1 = 0;
                        fileHeader.bfReserved2 = 0;
                        fileHeader.bfOffBits   = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4);

                        byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray <BitmapFileHeader>(fileHeader);

                        using (MemoryStream bitmapStream = new MemoryStream()) {
                            bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
                            bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
                            bitmapStream.Seek(0, SeekOrigin.Begin);
                            using (Image tmpImage = Image.FromStream(bitmapStream)) {
                                if (tmpImage != null)
                                {
                                    return(ImageHelper.Clone(tmpImage));
                                }
                            }
                        }
                    }
                }
                else
                {
                    LOG.Info("Skipping special DIB format reader as it's disabled in the configuration.");
                }
            } catch (Exception dibEx) {
                LOG.Error("Problem retrieving DIB from clipboard.", dibEx);
            }
            return(null);
        }
예제 #5
0
 /// <summary>
 /// Download the url to Bitmap
 /// </summary>
 /// <param name="baseUri"></param>
 /// <returns>Bitmap</returns>
 public static Image DownloadImage(string url)
 {
     try {
         HttpWebRequest  request  = (HttpWebRequest)NetworkHelper.CreateWebRequest(url);
         HttpWebResponse response = (HttpWebResponse)request.GetResponse();
         if (request.HaveResponse)
         {
             using (Image image = Image.FromStream(response.GetResponseStream())) {
                 return(ImageHelper.Clone(image));
             }
         }
     } catch (Exception e) {
         LOG.Error("Problem downloading the image from: " + url, e);
     }
     return(null);
 }
예제 #6
0
 /// <summary>
 /// Download the uri to Bitmap
 /// </summary>
 /// <param name="url">Of an image</param>
 /// <returns>Bitmap</returns>
 public static Image DownloadImage(string url)
 {
     try {
         HttpWebRequest  request  = CreateWebRequest(url);
         HttpWebResponse response = (HttpWebResponse)request.GetResponse();
         if (request.HaveResponse)
         {
             using (Stream responseStream = response.GetResponseStream()) {
                 if (responseStream != null)
                 {
                     using (Image image = Image.FromStream(responseStream)) {
                         return(ImageHelper.Clone(image, PixelFormat.Format32bppArgb));
                     }
                 }
             }
         }
     } catch (Exception e) {
         LOG.Error("Problem downloading the image from: " + url, e);
     }
     return(null);
 }
예제 #7
0
        /// <summary>
        /// Helper method to try to get an image in the specified format from the dataObject
        /// the DIB readed should solve the issue reported here: https://sourceforge.net/projects/greenshot/forums/forum/676083/topic/6354353/index/page/1
        /// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591
        /// </summary>
        /// <param name="format">string with the format</param>
        /// <param name="dataObject">IDataObject</param>
        /// <returns>Image or null</returns>
        private static Image GetImageForFormat(string format, IDataObject dataObject)
        {
            object       clipboardObject = GetFromDataObject(dataObject, format);
            MemoryStream imageStream     = clipboardObject as MemoryStream;

            if (!isValidStream(imageStream))
            {
                // TODO: add "HTML Format" support here...
                return(clipboardObject as Image);
            }
            else
            {
                if (config.EnableSpecialDIBClipboardReader)
                {
                    if (format == FORMAT_17 || format == DataFormats.Dib)
                    {
                        LOG.Info("Found DIB stream, trying to process it.");
                        try
                        {
                            byte[] dibBuffer = new byte[imageStream.Length];
                            imageStream.Read(dibBuffer, 0, dibBuffer.Length);
                            BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray <BITMAPINFOHEADER>(dibBuffer);
                            if (!infoHeader.IsDibV5)
                            {
                                LOG.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
                                int  fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
                                uint infoHeaderSize = infoHeader.biSize;
                                int  fileSize       = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);

                                BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER();
                                fileHeader.bfType      = BITMAPFILEHEADER.BM;
                                fileHeader.bfSize      = fileSize;
                                fileHeader.bfReserved1 = 0;
                                fileHeader.bfReserved2 = 0;
                                fileHeader.bfOffBits   = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4);

                                byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray <BITMAPFILEHEADER>(fileHeader);

                                using (MemoryStream bitmapStream = new MemoryStream())
                                {
                                    bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
                                    bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
                                    bitmapStream.Seek(0, SeekOrigin.Begin);
                                    using (Image tmpImage = Image.FromStream(bitmapStream))
                                    {
                                        if (tmpImage != null)
                                        {
                                            return(ImageHelper.Clone(tmpImage));
                                        }
                                    }
                                }
                            }
                            else
                            {
                                LOG.Info("Using special DIBV5 / Format17 format reader");
                                // CF_DIBV5
                                IntPtr gcHandle = IntPtr.Zero;
                                try
                                {
                                    GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
                                    gcHandle = GCHandle.ToIntPtr(handle);
                                    return(new Bitmap(infoHeader.biWidth, infoHeader.biHeight, -(int)(infoHeader.biSizeImage / infoHeader.biHeight),
                                                      infoHeader.biBitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb,
                                                      new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight))));
                                }
                                catch (Exception ex)
                                {
                                    LOG.Error("Problem retrieving Format17 from clipboard.", ex);
                                }
                                finally
                                {
                                    if (gcHandle == IntPtr.Zero)
                                    {
                                        GCHandle.FromIntPtr(gcHandle).Free();
                                    }
                                }
                            }
                        }
                        catch (Exception dibEx)
                        {
                            LOG.Error("Problem retrieving DIB from clipboard.", dibEx);
                        }
                    }
                }
                else
                {
                    LOG.Info("Skipping special DIB format reader as it's disabled in the configuration.");
                }
                try
                {
                    imageStream.Seek(0, SeekOrigin.Begin);
                    using (Image tmpImage = Image.FromStream(imageStream, true, true))
                    {
                        if (tmpImage != null)
                        {
                            LOG.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
                            return(ImageHelper.Clone(tmpImage));
                        }
                    }
                }
                catch (Exception streamImageEx)
                {
                    LOG.Error(string.Format("Problem retrieving {0} from clipboard.", format), streamImageEx);
                }
            }
            return(null);
        }
예제 #8
0
        /// <summary>
        /// Saves image to stream with specified quality
        /// To prevent problems with GDI version of before Windows 7:
        /// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used.
        /// </summary>
        /// <param name="imageToSave">image to save</param>
        /// <param name="surface">surface for the elements, needed if the greenshot format is used</param>
        /// <param name="stream">Stream to save to</param>
        /// <param name="outputSettings">SurfaceOutputSettings</param>
        public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings)
        {
            ImageFormat  imageFormat     = null;
            bool         useMemoryStream = false;
            MemoryStream memoryStream    = null;

            if (outputSettings.Format == OutputFormat.greenshot && surface == null)
            {
                throw new ArgumentException("Surface needs to be se when using OutputFormat.Greenshot");
            }

            try
            {
                switch (outputSettings.Format)
                {
                case OutputFormat.bmp:
                    imageFormat = ImageFormat.Bmp;
                    break;

                case OutputFormat.gif:
                    imageFormat = ImageFormat.Gif;
                    break;

                case OutputFormat.jpg:
                    imageFormat = ImageFormat.Jpeg;
                    break;

                case OutputFormat.tiff:
                    imageFormat = ImageFormat.Tiff;
                    break;

                case OutputFormat.greenshot:
                case OutputFormat.png:
                default:
                    // Problem with non-seekable streams most likely doesn't happen with Windows 7 (OS Version 6.1 and later)
                    // http://stackoverflow.com/questions/8349260/generic-gdi-error-on-one-machine-but-not-the-other
                    if (!stream.CanSeek)
                    {
                        int majorVersion = Environment.OSVersion.Version.Major;
                        int minorVersion = Environment.OSVersion.Version.Minor;
                        if (majorVersion < 6 || (majorVersion == 6 && minorVersion == 0))
                        {
                            useMemoryStream = true;
                            LOG.Warn("Using memorystream prevent an issue with saving to a non seekable stream.");
                        }
                    }
                    imageFormat = ImageFormat.Png;
                    break;
                }
                LOG.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat);

                // Check if we want to use a memory stream, to prevent a issue which happens with Windows before "7".
                // The save is made to the targetStream, this is directed to either the MemoryStream or the original
                Stream targetStream = stream;
                if (useMemoryStream)
                {
                    memoryStream = new MemoryStream();
                    targetStream = memoryStream;
                }

                if (imageFormat == ImageFormat.Jpeg)
                {
                    bool foundEncoder = false;
                    foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders())
                    {
                        if (imageCodec.FormatID == imageFormat.Guid)
                        {
                            EncoderParameters parameters = new EncoderParameters(1);
                            parameters.Param[0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality);
                            // Removing transparency if it's not supported in the output
                            if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat))
                            {
                                Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
                                AddTag(nonAlphaImage);
                                nonAlphaImage.Save(targetStream, imageCodec, parameters);
                                nonAlphaImage.Dispose();
                                nonAlphaImage = null;
                            }
                            else
                            {
                                AddTag(imageToSave);
                                imageToSave.Save(targetStream, imageCodec, parameters);
                            }
                            foundEncoder = true;
                            break;
                        }
                    }
                    if (!foundEncoder)
                    {
                        throw new ApplicationException("No JPG encoder found, this should not happen.");
                    }
                }
                else
                {
                    // Removing transparency if it's not supported in the output
                    if (imageFormat != ImageFormat.Png && Image.IsAlphaPixelFormat(imageToSave.PixelFormat))
                    {
                        Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
                        AddTag(nonAlphaImage);
                        nonAlphaImage.Save(targetStream, imageFormat);
                        nonAlphaImage.Dispose();
                        nonAlphaImage = null;
                    }
                    else
                    {
                        AddTag(imageToSave);
                        imageToSave.Save(targetStream, imageFormat);
                    }
                }

                // If we used a memory stream, we need to stream the memory stream to the original stream.
                if (useMemoryStream)
                {
                    memoryStream.WriteTo(stream);
                }

                // Output the surface elements, size and marker to the stream
                if (outputSettings.Format == OutputFormat.greenshot)
                {
                    using (MemoryStream tmpStream = new MemoryStream())
                    {
                        long bytesWritten = surface.SaveElementsToStream(tmpStream);
                        using (BinaryWriter writer = new BinaryWriter(tmpStream))
                        {
                            writer.Write(bytesWritten);
                            Version v      = Assembly.GetExecutingAssembly().GetName().Version;
                            byte[]  marker = Encoding.ASCII.GetBytes(String.Format("Greenshot{0:00}.{1:00}", v.Major, v.Minor));
                            writer.Write(marker);
                            tmpStream.WriteTo(stream);
                        }
                    }
                }
            }
            finally
            {
                if (memoryStream != null)
                {
                    memoryStream.Dispose();
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Write the images to the stream as icon
        /// Every image is resized to 256x256 (but the content maintains the aspect ratio)
        /// </summary>
        /// <param name="stream">Stream to write to</param>
        /// <param name="images">List of images</param>
        public static void WriteIcon(Stream stream, IList <Image> images)
        {
            var binaryWriter = new BinaryWriter(stream);

            //
            // ICONDIR structure
            //
            binaryWriter.Write((short)0);             // reserved
            binaryWriter.Write((short)1);             // image type (icon)
            binaryWriter.Write((short)images.Count);  // number of images

            IList <Size>         imageSizes    = new List <Size>();
            IList <MemoryStream> encodedImages = new List <MemoryStream>();

            foreach (var image in images)
            {
                // Pick the best fit
                var sizes = new[] { 16, 32, 48 };
                int size  = 256;
                foreach (var possibleSize in sizes)
                {
                    if (image.Width <= possibleSize && image.Height <= possibleSize)
                    {
                        size = possibleSize;
                        break;
                    }
                }
                var imageStream = new MemoryStream();
                if (image.Width == size && image.Height == size)
                {
                    using (var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb))
                    {
                        clonedImage.Save(imageStream, ImageFormat.Png);
                        imageSizes.Add(new Size(size, size));
                    }
                }
                else
                {
                    // Resize to the specified size, first make sure the image is 32bpp
                    using (var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb))
                    {
                        using (var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null))
                        {
                            resizedImage.Save(imageStream, ImageFormat.Png);
                            imageSizes.Add(resizedImage.Size);
                        }
                    }
                }

                imageStream.Seek(0, SeekOrigin.Begin);
                encodedImages.Add(imageStream);
            }

            //
            // ICONDIRENTRY structure
            //
            const int iconDirSize      = 6;
            const int iconDirEntrySize = 16;

            var offset = iconDirSize + (images.Count * iconDirEntrySize);

            for (int i = 0; i < images.Count; i++)
            {
                var imageSize = imageSizes[i];
                // Write the width / height, 0 means 256
                binaryWriter.Write(imageSize.Width == 256 ? (byte)0 : (byte)imageSize.Width);
                binaryWriter.Write(imageSize.Height == 256 ? (byte)0 : (byte)imageSize.Height);
                binaryWriter.Write((byte)0);                      // no pallete
                binaryWriter.Write((byte)0);                      // reserved
                binaryWriter.Write((short)0);                     // no color planes
                binaryWriter.Write((short)32);                    // 32 bpp
                binaryWriter.Write((int)encodedImages[i].Length); // image data length
                binaryWriter.Write(offset);
                offset += (int)encodedImages[i].Length;
            }

            binaryWriter.Flush();
            //
            // Write image data
            //
            foreach (var encodedImage in encodedImages)
            {
                encodedImage.WriteTo(stream);
                encodedImage.Dispose();
            }
        }
예제 #10
0
        /// <summary>
        /// Saves image to stream with specified quality
        /// To prevent problems with GDI version of before Windows 7:
        /// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used.
        /// </summary>
        /// <param name="imageToSave">image to save</param>
        /// <param name="surface">surface for the elements, needed if the greenshot format is used</param>
        /// <param name="stream">Stream to save to</param>
        /// <param name="outputSettings">SurfaceOutputSettings</param>
        public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings)
        {
            bool         useMemoryStream = false;
            MemoryStream memoryStream    = null;

            if (outputSettings.Format == OutputFormat.greenshot && surface == null)
            {
                throw new ArgumentException("Surface needs to be set when using OutputFormat.Greenshot");
            }

            try {
                ImageFormat imageFormat;
                switch (outputSettings.Format)
                {
                case OutputFormat.bmp:
                    imageFormat = ImageFormat.Bmp;
                    break;

                case OutputFormat.gif:
                    imageFormat = ImageFormat.Gif;
                    break;

                case OutputFormat.jpg:
                    imageFormat = ImageFormat.Jpeg;
                    break;

                case OutputFormat.tiff:
                    imageFormat = ImageFormat.Tiff;
                    break;

                case OutputFormat.ico:
                    imageFormat = ImageFormat.Icon;
                    break;

                default:
                    imageFormat = ImageFormat.Png;
                    break;
                }
                Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat);

                // Check if we want to use a memory stream, to prevent issues with non seakable streams
                // The save is made to the targetStream, this is directed to either the MemoryStream or the original
                Stream targetStream = stream;
                if (!stream.CanSeek)
                {
                    useMemoryStream = true;
                    Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream.");
                    memoryStream = new MemoryStream();
                    targetStream = memoryStream;
                }

                if (Equals(imageFormat, ImageFormat.Jpeg))
                {
                    bool foundEncoder = false;
                    foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders())
                    {
                        if (imageCodec.FormatID == imageFormat.Guid)
                        {
                            EncoderParameters parameters = new EncoderParameters(1)
                            {
                                Param = { [0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality) }
                            };
                            // Removing transparency if it's not supported in the output
                            if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat))
                            {
                                Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
                                AddTag(nonAlphaImage);
                                nonAlphaImage.Save(targetStream, imageCodec, parameters);
                                nonAlphaImage.Dispose();
                            }
                            else
                            {
                                AddTag(imageToSave);
                                imageToSave.Save(targetStream, imageCodec, parameters);
                            }
                            foundEncoder = true;
                            break;
                        }
                    }
                    if (!foundEncoder)
                    {
                        throw new ApplicationException("No JPG encoder found, this should not happen.");
                    }
                }
                else if (Equals(imageFormat, ImageFormat.Icon))
                {
                    // FEATURE-916: Added Icon support
                    IList <Image> images = new List <Image>();
                    images.Add(imageToSave);
                    WriteIcon(stream, images);
                }
                else
                {
                    bool needsDispose = false;
                    // Removing transparency if it's not supported in the output
                    if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat))
                    {
                        imageToSave  = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
                        needsDispose = true;
                    }
                    AddTag(imageToSave);
                    // Added for OptiPNG
                    bool processed = false;
                    if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand))
                    {
                        processed = ProcessPngImageExternally(imageToSave, targetStream);
                    }
                    if (!processed)
                    {
                        imageToSave.Save(targetStream, imageFormat);
                    }
                    if (needsDispose)
                    {
                        imageToSave.Dispose();
                    }
                }

                // If we used a memory stream, we need to stream the memory stream to the original stream.
                if (useMemoryStream)
                {
                    memoryStream.WriteTo(stream);
                }

                // Output the surface elements, size and marker to the stream
                if (outputSettings.Format != OutputFormat.greenshot)
                {
                    return;
                }
                using (MemoryStream tmpStream = new MemoryStream()) {
                    long bytesWritten = surface.SaveElementsToStream(tmpStream);
                    using (BinaryWriter writer = new BinaryWriter(tmpStream)) {
                        writer.Write(bytesWritten);
                        Version v      = Assembly.GetExecutingAssembly().GetName().Version;
                        byte[]  marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}");
                        writer.Write(marker);
                        tmpStream.WriteTo(stream);
                    }
                }
            }
            finally
            {
                memoryStream?.Dispose();
            }
        }