예제 #1
0
        internal void AddFrame(int index, string path, int delay = 66)
        {
            var reader = new PixelUtil(path.SourceFrom());

            reader.LockBits();

            var channelData = new ImageChannelData(reader.Depth, reader.Pixels, reader.Height, reader.Width, Compress); //TODO: Support for layers with multiple sizes.
            var layerData   = new LayerRecord
            {
                Top    = 0,
                Left   = 0,
                Bottom = (uint)Height, // + top,
                Right  = (uint)Width,  // + left,
                Name   = index.ToString()
            };

            reader.UnlockBitsWithoutCommit();

            //Add the lengths of the channels.
            for (var i = 0; i < channelData.ChannelList.Count; i++)
            {
                layerData.Channels.Add((short)(i - 1), (int)channelData.ChannelList[i].Length + 2); //+ 2 bytes for the compression type.
            }
            LayerAndMask.LayerInfo.ImageChannelDataList.Add(channelData);
            LayerAndMask.LayerInfo.LayerList.Add(layerData);

            //TODO: Add ImageResource info (timeline)
            //ImageResources.ImageResourceList.Add(new ImageResourceBlock(2, "shmd", null));
        }
예제 #2
0
        private void EyeDropperButton_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            var str = new Native.PointW();

            Native.GetCursorPos(ref str);

            var image = Native.CaptureBitmapSource((int)_captureSize.Width, (int)_captureSize.Height, str.X - (int)(_captureSize.Width / 2d), str.Y - (int)(_captureSize.Height / 2d));

            if (image.Format != PixelFormats.Bgra32)
            {
                image = new FormatConvertedBitmap(image, PixelFormats.Bgra32, null, 0);
            }

            EyeDropperImage.Source = image;

            var pix = new PixelUtil(image);

            pix.LockBits();
            UpdateMarkerPosition(pix.GetPixel((int)(_captureSize.Width / 2d), (int)(_captureSize.Height / 2d)));

            #region Update the values

            _isUpdating = true;

            AlphaIntegerUpDown.Value = SelectedColor.A;
            RedIntegerUpDown.Value   = SelectedColor.R;
            GreenIntegerUpDown.Value = SelectedColor.G;
            BlueIntegerUpDown.Value  = SelectedColor.B;

            _isUpdating = false;

            #endregion

            pix.UnlockBits();
        }
예제 #3
0
        internal GifskiError AddFrame(IntPtr handle, uint index, string path, int delay)
        {
            if (Version.Major == 0 && Version.Minor < 9)
            {
                return(_addPngFrame(handle, index, path, (ushort)(delay / 10)));
            }

            var util = new PixelUtil(new FormatConvertedBitmap(path.SourceFrom(), PixelFormats.Rgb24, null, 0));

            util.LockBits();

            var result = AddFramePixels(handle, index, (uint)util.Width, (uint)((util.Width * 24 + 31) / 32) * 4, (uint)util.Height, util.BackBuffer, (ushort)delay);

            util.UnlockBitsWithoutCommit();

            return(result);
        }
예제 #4
0
        /// <summary>
        /// Applies the pixelate effect in given frame.
        /// </summary>
        /// <param name="image">The image to pixelate.</param>
        /// <param name="rectangle">The area to pixelate.</param>
        /// <param name="pixelateSize">The size of the pixel.</param>
        /// <param name="useMedian">Calculate the median color of the pixel block.</param>
        /// <returns>A pixelated Bitmap.</returns>
        public static BitmapSource Pixelate(BitmapSource image, Int32Rect rectangle, int pixelateSize, bool useMedian)
        {
            var croppedImage = new CroppedBitmap(image, rectangle);
            var pixelUtil    = new PixelUtil(croppedImage);

            pixelUtil.LockBits();

            //Loop through all the blocks that should be pixelated.
            for (var xx = 0; xx < croppedImage.PixelWidth; xx += pixelateSize)
            {
                for (var yy = 0; yy < croppedImage.PixelHeight; yy += pixelateSize)
                {
                    var offsetX = pixelateSize / 2;
                    var offsetY = pixelateSize / 2;

                    if (xx + offsetX >= croppedImage.PixelWidth)
                    {
                        offsetX = croppedImage.PixelWidth;
                    }

                    if (yy + offsetY >= croppedImage.PixelHeight)
                    {
                        offsetY = croppedImage.PixelHeight;
                    }

                    //Get the pixel color in the center of the soon to be pixelated area.
                    var pixel = useMedian ? pixelUtil.GetMedianColor(xx, yy, offsetX, offsetY) : pixelUtil.GetPixel(xx + offsetX, yy + offsetY);

                    //For each pixel in the pixelate size, set it to the center color.
                    for (var x = xx; x < xx + pixelateSize && x < croppedImage.PixelWidth; x++)
                    {
                        for (var y = yy; y < yy + pixelateSize && y < croppedImage.PixelHeight; y++)
                        {
                            pixelUtil.SetPixel(x, y, pixel);
                        }
                    }
                }
            }

            return(pixelUtil.UnlockBits());
        }
예제 #5
0
        private void EyeDropperButton_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            var str = new Native.PointW();

            Native.GetCursorPos(ref str);

            var image = Native.CaptureBitmapSource((int)_captureSize.Width, (int)_captureSize.Height, str.X - (int)(_captureSize.Width / 2d), str.Y - (int)(_captureSize.Height / 2d));

            if (image.Format != PixelFormats.Bgra32)
            {
                image = new FormatConvertedBitmap(image, PixelFormats.Bgra32, null, 0);
            }

            EyeDropperImage.Source = image;

            var pix = new PixelUtil(image);

            pix.LockBits();
            UpdateMarkerPosition(pix.GetPixel((int)(_captureSize.Width / 2d), (int)(_captureSize.Height / 2d)));
            pix.UnlockBits();
        }
예제 #6
0
        /// <summary>
        /// Copy all necessary files to a new encode folder.
        /// </summary>
        /// <param name="usePadding">True if the file names should have a left pad, to preserve the file ordering.</param>
        /// <param name="copyJson">True if the Project.json file should be copied too.</param>
        /// <param name="useBytes">True if the images should be converted to byte array.</param>
        /// <returns>A list of frames with the new path.</returns>
        internal ExportProject CopyToExport(bool usePadding = false, bool copyJson = false, bool useBytes = false)
        {
            #region Output folder

            var folder = Path.Combine(FullPath, "Encode " + DateTime.Now.ToString("yyyy-MM-dd hh-mm-ss-ff"));

            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }

            #endregion

            var export = new ExportProject();

            if (useBytes)
            {
                export.Frames       = new List <ExportFrame>();
                export.ChunkPath    = Path.Combine(folder, "Chunk");
                export.NewChunkPath = Path.Combine(folder, "NewChunk");

                try
                {
                    //Create chunk file.
                    using (var fileStream = new FileStream(export.ChunkPath, FileMode.Create, FileAccess.Write, FileShare.None))
                    {
                        var pos = 0L;

                        foreach (var info in Frames)
                        {
                            var image = new PixelUtil(info.Path.SourceFrom());
                            image.LockBits();

                            fileStream.WriteBytes(image.Pixels);

                            export.Frames.Add(new ExportFrame
                            {
                                DataPosition = pos,
                                DataLength   = image.Pixels.LongLength,
                                Delay        = info.Delay,
                                Rect         = new Int32Rect(0, 0, image.Width, image.Height),
                                ImageDepth   = image.Depth
                            });

                            //Advances in the position.
                            pos += image.Pixels.LongLength;

                            image.UnlockBitsWithoutCommit();
                        }
                    }
                }
                catch (Exception e)
                {
                    LogWriter.Log(e, "It was impossible to get the image bytes to encode.");
                    throw;
                }

                return(export);
            }

            export.UsesFiles   = true;
            export.FramesFiles = new List <FrameInfo>();

            try
            {
                #region If it's being exported as project, maintain file naming

                if (copyJson)
                {
                    foreach (var info in Frames)
                    {
                        var filename = Path.Combine(folder, Path.GetFileName(info.Path));

                        //Copy the image to the folder.
                        File.Copy(info.Path, filename, true);

                        //Create the new object and add to the list.
                        export.FramesFiles.Add(new FrameInfo(filename, info.Delay));
                    }

                    File.Copy(ProjectPath, Path.Combine(folder, "Project.json"), true);

                    return(export);
                }

                #endregion

                //Detect pad size.
                var pad = usePadding ? (Frames.Count - 1).ToString().Length : 0;

                foreach (var info in Frames)
                {
                    //Changes the path of the image. Writes as an ordered list of files, replacing the old filenames.
                    var filename = Path.Combine(folder, export.FramesFiles.Count.ToString().PadLeft(pad, '0') + ".png");

                    //Copy the image to the folder.
                    File.Copy(info.Path, filename, true);

                    //Create the new object and add to the list.
                    export.FramesFiles.Add(new FrameInfo(filename, info.Delay));
                }
            }
            catch (Exception ex)
            {
                LogWriter.Log(ex, "It was impossible to copy the files to encode.");
                throw;
            }

            return(export);
        }
예제 #7
0
        private void GeneratePalette(string path)
        {
            var colorList = new List <Color>();

            NonIndexedPixels = new List <Color>();

            #region Get the Pixels

            var image     = path.SourceFrom();
            var pixelUtil = new PixelUtil(image);
            pixelUtil.LockBits();

            for (int x = 0; x < image.PixelWidth; x++)
            {
                for (int y = 0; y < image.PixelHeight; y++)
                {
                    colorList.Add(pixelUtil.GetPixel(x, y));
                }
            }

            pixelUtil.UnlockBits();

            #endregion

            //Save all the pixels in a property.
            NonIndexedPixels.AddRange(colorList);

            //TODO: more ways to decide which color to get
            //Like removing similar colors (with less than 5% similarity) if there is more than 256 colors, etc.
            //I probably can do that, using the groupby method.

            //if (NonIndexedPixels.Count == 100)
            //{
            //    ColorTable = new List<Color>
            //    {
            //        Color.FromRgb(255, 255, 255),
            //        Color.FromRgb(255, 0, 0),
            //        Color.FromRgb(0, 0, 255)
            //    };

            //    return;
            //}

            ColorTable = colorList.GroupBy(x => x)          //Grouping based on its value
                         .OrderByDescending(g => g.Count()) //Order by most frequent values
                         .Select(g => g.FirstOrDefault())   //take the first among the group
                         .Take(256).ToList();

            //Make sure that the transparent color is added to list.
            if (!IsFirstFrame && TransparentColor.HasValue && ColorTable.Count == 256)
            {
                //Only adds if there is 256 colors, so I need to make sure that the color won't be ignored.
                //If there is less than 256 selected colors, it means that the transparent color is already selected.

                //If the color isn't on the list, add or replace.
                if (ColorTable.All(x => x != TransparentColor.Value))
                {
                    //Adds to the last spot, keeping it sorted. (Since all the colors are ordered by descending)
                    ColorTable.Insert(255, TransparentColor.Value);

                    //Remove the exceding value at the last position.
                    ColorTable.RemoveAt(256);
                }
            }

            //I need to signal the other method that I won't need transparency.
            WillUseTransparency = TransparentColor.HasValue && ColorTable.Contains(TransparentColor.Value);
        }
예제 #8
0
        /// <summary>
        /// Analizes all frames (from the end to the start) and paints all unchanged pixels with a given color,
        /// after, it cuts the image to reduce filesize.
        /// </summary>
        /// <param name="listToEncode">The list of frames to analize.</param>
        /// <param name="transparent">The color to paint the unchanged pixels.</param>
        /// <param name="id">The Id of the current Task.</param>
        /// <param name="tokenSource">The cancelation token source.</param>
        /// <returns>A List contaning all frames and its cut points</returns>
        public static List <FrameInfo> PaintTransparentAndCut(List <FrameInfo> listToEncode, Color transparent, int id, CancellationTokenSource tokenSource)
        {
            //End to start FOR
            for (int index = listToEncode.Count - 1; index > 0; index--)
            {
                #region Cancellation

                if (tokenSource.Token.IsCancellationRequested)
                {
                    Encoder.SetStatus(Status.Cancelled, id);

                    break;
                }

                #endregion

                #region For each Frame, from the end to the start

                Encoder.Update(id, index - 1);

                //First frame is ignored.
                if (index <= 0)
                {
                    continue;
                }

                #region Get Image Info

                var imageAux1 = listToEncode[index - 1].ImageLocation.From();
                var imageAux2 = listToEncode[index].ImageLocation.From();

                var startY = new bool[imageAux1.Height];
                var startX = new bool[imageAux1.Width];

                var image1 = new PixelUtil(imageAux1); //Previous image
                var image2 = new PixelUtil(imageAux2); //Actual image

                image1.LockBits();
                image2.LockBits();

                int height = imageAux1.Height;
                int width  = imageAux1.Width;

                #endregion

                //Only use Parallel if the image is big enough.
                if ((width * height) > 150000)
                {
                    #region Parallel Loop

                    //x - width - sides
                    Parallel.For(0, width, x =>
                    {
                        //y - height - up/down
                        for (int y = 0; y < height; y++)
                        {
                            if (image1.GetPixel(x, y) == image2.GetPixel(x, y))
                            {
                                image2.SetPixel(x, y, transparent);
                            }
                            else
                            {
                                #region Get the Changed Pixels

                                startX[x] = true;
                                startY[y] = true;

                                #endregion
                            }
                        }
                    }); //SPEEEEEED, alot!

                    #endregion
                }
                else
                {
                    #region Sequential Loop

                    //x - width - sides
                    for (int x = 0; x < width; x++)
                    {
                        //y - height - up/down
                        for (int y = 0; y < height; y++)
                        {
                            #region For each Pixel

                            if (image1.GetPixel(x, y) == image2.GetPixel(x, y))
                            {
                                image2.SetPixel(x, y, transparent);
                            }
                            else
                            {
                                #region Get the Changed Pixels

                                startX[x] = true;
                                startY[y] = true;

                                #endregion
                            }

                            #endregion
                        }
                    }

                    #endregion
                }

                image1.UnlockBits();
                image2.UnlockBits();

                #region Verify positions

                int firstX = startX.ToList().FindIndex(x => x);
                int lastX  = startX.ToList().FindLastIndex(x => x);

                if (firstX == -1)
                {
                    firstX = 0;
                }
                if (lastX == -1)
                {
                    lastX = imageAux1.Width;
                }

                int firstY = startY.ToList().FindIndex(x => x);
                int lastY  = startY.ToList().FindLastIndex(x => x);

                if (lastY == -1)
                {
                    lastY = imageAux1.Height;
                }
                if (firstY == -1)
                {
                    firstY = 0;
                }

                if (lastX < firstX)
                {
                    int aux = lastX;
                    lastX  = firstX;
                    firstX = aux;
                }

                if (lastY < firstY)
                {
                    int aux = lastY;
                    lastY  = firstY;
                    firstY = aux;
                }

                #endregion

                #region Get the Width and Height

                int heigthCut = Math.Abs(lastY - firstY);
                int widthCut  = Math.Abs(lastX - firstX);

                if (heigthCut != height)
                {
                    heigthCut++;
                }
                else
                {
                    //It means that no pixel got changed.
                    heigthCut = 1;
                    //So i cut to 1 pixel to save the most, 0 can't be.
                }

                if (widthCut != width)
                {
                    widthCut++;
                }
                else
                {
                    widthCut = 1;
                }

                #endregion

                //Cut the images and get the new values.
                var imageSave2 = new Bitmap(imageAux2.Clone(new Rectangle(firstX, firstY, widthCut, heigthCut), imageAux2.PixelFormat));

                imageAux2.Dispose();
                imageAux1.Dispose();

                #region Update Image Info and Save

                imageSave2.Save(listToEncode[index].ImageLocation);

                listToEncode[index].PositionTopLeft = new Point(firstX, firstY);

                #endregion

                GC.Collect(1);

                #endregion
            }

            return(listToEncode);
        }
예제 #9
0
        /// <summary>
        /// Analizes all frames (from the end to the start) and paints all unchanged pixels with a given color,
        /// after, it cuts the image to reduce filesize.
        /// </summary>
        /// <param name="listToEncode">The list of frames to analize.</param>
        /// <param name="id">The Id of the Task.</param>
        /// <param name="tokenSource">The cancelation token source.</param>
        public static List <FrameInfo> CutUnchanged(List <FrameInfo> listToEncode, int id, CancellationTokenSource tokenSource)
        {
            //First frame rect.
            var size = listToEncode[0].ImageLocation.ScaledSize();

            listToEncode[0].Rect = new Int32Rect(0, 0, (int)size.Width, (int)size.Height);

            //End to start FOR
            for (int index = listToEncode.Count - 1; index > 0; index--)
            {
                #region Cancellation

                if (tokenSource.Token.IsCancellationRequested)
                {
                    Windows.Encoder.SetStatus(Status.Canceled, id);

                    break;
                }

                #endregion

                #region For each Frame, from the end to the start

                Windows.Encoder.Update(id, index - 1);

                //First frame is ignored.
                if (index <= 0)
                {
                    continue;
                }

                #region Get Image Info

                var imageAux1 = listToEncode[index - 1].ImageLocation.From();
                var imageAux2 = listToEncode[index].ImageLocation.From();

                var startY = new bool[imageAux1.Height];
                var startX = new bool[imageAux1.Width];

                var image1 = new PixelUtil(imageAux1); //Previous image
                var image2 = new PixelUtil(imageAux2); //Actual image

                image1.LockBits();
                image2.LockBits();

                int height = imageAux1.Height;
                int width  = imageAux1.Width;

                #endregion

                //Only use Parallel if the image is big enough.
                if ((width * height) > 150000)
                {
                    #region Parallel Loop

                    //x - width - sides
                    Parallel.For(0, width, x =>
                    {
                        //y - height - up/down
                        for (int y = 0; y < height; y++)
                        {
                            if (image1.GetPixel(x, y) != image2.GetPixel(x, y))
                            {
                                #region Get the Changed Pixels

                                startX[x] = true;
                                startY[y] = true;

                                #endregion
                            }
                        }
                    }); //SPEEEEEED, alot!

                    #endregion
                }
                else
                {
                    #region Sequential Loop

                    //x - width - sides
                    for (int x = 0; x < width; x++)
                    {
                        //y - height - up/down
                        for (int y = 0; y < height; y++)
                        {
                            #region For each Pixel

                            if (image1.GetPixel(x, y) != image2.GetPixel(x, y))
                            {
                                #region Get the Changed Pixels

                                startX[x] = true;
                                startY[y] = true;

                                #endregion
                            }

                            #endregion
                        }
                    }

                    #endregion
                }

                image1.UnlockBits();
                image2.UnlockBits();

                #region Verify positions

                int firstX = startX.ToList().FindIndex(x => x);
                int lastX  = startX.ToList().FindLastIndex(x => x);

                if (firstX == -1)
                {
                    firstX = 0;
                }
                if (lastX == -1)
                {
                    lastX = imageAux1.Width;
                }

                int firstY = startY.ToList().FindIndex(x => x);
                int lastY  = startY.ToList().FindLastIndex(x => x);

                if (lastY == -1)
                {
                    lastY = imageAux1.Height;
                }
                if (firstY == -1)
                {
                    firstY = 0;
                }

                if (lastX < firstX)
                {
                    int aux = lastX;
                    lastX  = firstX;
                    firstX = aux;
                }

                if (lastY < firstY)
                {
                    int aux = lastY;
                    lastY  = firstY;
                    firstY = aux;
                }

                #endregion

                #region Get the Width and Height

                int heightCut = Math.Abs(lastY - firstY);
                int widthCut  = Math.Abs(lastX - firstX);

                //If nothing changed, shift the delay.
                if ((heightCut + widthCut) == (height + width))
                {
                    listToEncode[index - 1].Delay += listToEncode[index].Delay;
                    listToEncode[index].Rect       = new Int32Rect(0, 0, 0, 0);

                    GC.Collect(1);
                    continue;
                }
                else
                {
                    if (heightCut != height)
                    {
                        heightCut++;
                    }

                    if (widthCut != width)
                    {
                        widthCut++;
                    }
                }

                listToEncode[index].Rect = new Int32Rect(firstX, firstY, widthCut, heightCut);

                #endregion

                #region Update Image Info and Save

                //Cut the images and get the new values.
                var imageSave2 = new Bitmap(imageAux2.Clone(
                                                new Rectangle(firstX, firstY, widthCut, heightCut),
                                                imageAux2.PixelFormat));

                imageAux2.Dispose();
                imageAux1.Dispose();

                imageSave2.Save(listToEncode[index].ImageLocation);

                #endregion

                GC.Collect(1);

                #endregion
            }

            return(listToEncode);
        }