private void StartInput_ValueChanged(object sender, EventArgs e)
        {
            if (!mIgnoreChangeEvent)
            {
                ClipInfo info = mAllFrameInfo[mSelectedIndex];

                info.Offset = new Point((int)StartXOffset.Value, (int)StartYOffset.Value);
                info.Zoom   = (double)StartZoom.Value;

                UpdateClipInfo();
            }
        }
        private void VideoSize_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!mIgnoreChangeEvent)
            {
                ClipInfo info = mAllFrameInfo[mSelectedIndex];
                info.FrameSize = mVideoSizes[VideoSize.SelectedIndex];

                if (info.FrameSize.Label.Equals("Custom") && info.FrameSize.Width == 0 && info.FrameSize.Height == 0)
                {
                    Image firstImage = Image.FromFile(mFiles[0]);
                    widthInput.Value  = firstImage.Width;
                    heightInput.Value = firstImage.Height;
                }
            }

            UpdateClipInfo();
            UpdateOutputStatus();
        }
        private void keyButton_Click(object sender, EventArgs e)
        {
            ClipInfo clipInfo = mAllFrameInfo[mSelectedIndex];

            if (clipInfo.IsKeyFrame)
            {
                clipInfo.IsKeyFrame = false;
                for (int i = 0; i < mKeyFrameInfo.Count; i++)
                {
                    ClipInfo searchClip = mKeyFrameInfo[i];
                    if (searchClip.Index == mSelectedIndex)
                    {
                        mKeyFrameInfo.RemoveAt(i);
                        UpdateClipInfo();
                        return;
                    }
                }
            }
            else
            {
                clipInfo.IsKeyFrame = true;
                clipInfo.Offset     = new Point((int)StartXOffset.Value, (int)StartYOffset.Value);
                clipInfo.Zoom       = (double)StartZoom.Value;
                for (int i = 0; i < mKeyFrameInfo.Count; i++)
                {
                    if (mKeyFrameInfo[i].Index > clipInfo.Index)
                    {
                        mKeyFrameInfo.Insert(i, clipInfo);
                        UpdateClipInfo();
                        return;
                    }
                }

                mKeyFrameInfo.Add(clipInfo);
                UpdateClipInfo();
                return;
            }
        }
        private void DoCropping()
        {
            string directory = string.Format("{0}\\Cropped {1}x", mDirectory, mRealtimeMultiplier);
            int    appender  = 0;

            while (Directory.Exists(directory))
            {
                appender++;
                directory = string.Format("{0}\\Cropped {1}x_{2}", mDirectory, mRealtimeMultiplier, appender);
            }
            Directory.CreateDirectory(directory);

            int numInputs  = mFiles.Length;
            int numOutputs = numInputs / mSkipRate;

            //Parallel.For(0, numOutputs, (i) => {
            for (int i = 0; i < numOutputs; i++)
            {
                ClipInfo clipInfo = null;
                if (mClipInfos != null)
                {
                    clipInfo = mClipInfos[i * mSkipRate];
                }

                if (Event != null)
                {
                    Event(this, new CropperEventArgs(i, numOutputs, null));
                }

                int    xOffset = clipInfo != null ? clipInfo.Offset.X : (int)(mStartX + ((mEndX - mStartX) * i / (numOutputs - 1)));
                int    yOffset = clipInfo != null ? clipInfo.Offset.Y : (int)(mStartY + ((mEndY - mStartY) * i / (numOutputs - 1)));
                double zoom    = clipInfo != null ? clipInfo.Zoom : (double)(mStartZoom + ((mEndZoom - mStartZoom) * i / (numOutputs - 1)));
                if (clipInfo != null)
                {
                    mVideoSize = clipInfo.FrameSize;
                }

                //Get the output filename
                string outName = string.Format("{0}\\{1}_{2}x_{3:00000}.png", directory, mLabel, mRealtimeMultiplier, i);

                Console.WriteLine(string.Format("Processing frame {0}, ({1}, {2}), output {3}", i, xOffset, yOffset, outName));

                //Crop the image
                using (Bitmap bmpImage = new Bitmap(mFiles[i * mSkipRate]))
                {
                    using (Bitmap bmpCrop = bmpImage.Clone(new Rectangle(xOffset, yOffset, (int)(mVideoSize.Width * zoom), (int)(mVideoSize.Height * zoom)), bmpImage.PixelFormat))
                    {
                        using (Bitmap bm = new Bitmap(bmpCrop, mVideoSize.Width, mVideoSize.Height))
                        {
                            Graphics grap = Graphics.FromImage(bm);
                            grap.InterpolationMode = InterpolationMode.HighQualityBicubic;

                            //Save the image
                            bm.Save(outName);
                            grap.Dispose();

                            if (Event != null)
                            {
                                Event(this, new CropperEventArgs(i, numOutputs, bm));
                            }
                        }
                    }
                }
            }
            //});

            if (Event != null)
            {
                Event(this, new CropperEventArgs(numOutputs, numOutputs, null));
            }
        }
        public void DrawImage(int imageIndex)
        {
            mSelectedIndex    = imageIndex;
            frameIndex.Value  = imageIndex;
            frameSlider.Value = imageIndex;

            ClipInfo clipInfo = mAllFrameInfo[imageIndex];

            mIgnoreChangeEvent = true;
            StartXOffset.Value = clipInfo.Offset.X;
            StartYOffset.Value = clipInfo.Offset.Y;
            StartZoom.Value    = (decimal)clipInfo.Zoom;
            mIgnoreChangeEvent = false;

            if (clipInfo.IsKeyFrame)
            {
                keyButton.Text = "Clear Key";

                StartXOffset.Enabled = true;
                StartYOffset.Enabled = true;
                StartZoom.Enabled    = true;
            }
            else
            {
                keyButton.Text = "Make Key";

                StartXOffset.Enabled = false;
                StartYOffset.Enabled = false;
                StartZoom.Enabled    = false;
            }

            string filename = mFiles[imageIndex];

            //if (clipInfo.SavedImage == null)
            //{
            //    clipInfo.SavedImage = Image.FromFile(filename);
            //}
            Image  image        = Image.FromFile(filename);
            double inputRatio   = (double)image.Width / image.Height;
            int    outputHeight = (int)(imageDisplay.Size.Width / inputRatio);
            double imageZoom    = (double)image.Width / imageDisplay.Size.Width;

            Bitmap   bitmap = new Bitmap(image, imageDisplay.Size.Width, outputHeight);
            Graphics grap   = Graphics.FromImage(bitmap);

            grap.InterpolationMode = InterpolationMode.HighQualityBicubic;

            Rectangle rect = new Rectangle(
                (int)(clipInfo.Offset.X / imageZoom),
                (int)(clipInfo.Offset.Y / imageZoom),
                (int)(clipInfo.FrameSize.Width * clipInfo.Zoom / imageZoom),
                (int)(clipInfo.FrameSize.Height * clipInfo.Zoom / imageZoom));

            Pen pen = clipInfo.IsKeyFrame ? Pens.Cyan : Pens.DarkGreen;

            grap.DrawRectangle(pen, rect);
            grap.Dispose();

            image.Dispose();

            imageDisplay.Image = bitmap;
        }
        public void UpdateClipInfo()
        {
            mAllFrameInfo = new List <ClipInfo>();

            for (int i = 0; i < mFiles.Length; i++)
            {
                ClipInfo info = null;

                foreach (ClipInfo searchClip in mKeyFrameInfo)
                {
                    if (i == searchClip.Index)
                    {
                        info = searchClip;
                    }
                }

                if (info == null)
                {
                    info            = new ClipInfo();
                    info.Index      = i;
                    info.IsKeyFrame = false;
                    info.Zoom       = 1;
                    info.FrameSize  = mVideoSizes[VideoSize.SelectedIndex];

                    bool custom = info.FrameSize.Label == "Custom";
                    widthInput.Visible  = custom;
                    widthLabel.Visible  = custom;
                    heightInput.Visible = custom;
                    heightLabel.Visible = custom;
                    if (custom)
                    {
                        info.FrameSize.Height = (int)heightInput.Value;
                        info.FrameSize.Width  = (int)widthInput.Value;
                    }

                    //Interpolate to find the clip info for this frame
                    ClipInfo beforeInfo = null;
                    ClipInfo afterInfo  = null;
                    foreach (ClipInfo searchInfo in mKeyFrameInfo)
                    {
                        if (searchInfo.Index < info.Index)
                        {
                            beforeInfo = searchInfo;
                        }

                        if (searchInfo.Index > info.Index && afterInfo == null)
                        {
                            afterInfo = searchInfo;
                        }
                    }

                    if (beforeInfo == null)
                    {
                        if (afterInfo == null)
                        {
                            //No before, no after
                        }
                        else
                        {
                            //No before, after
                            info.Offset = new Point(afterInfo.Offset.X, afterInfo.Offset.Y);
                            info.Zoom   = afterInfo.Zoom;
                        }
                    }
                    else
                    {
                        if (afterInfo == null)
                        {
                            //Before, no after
                            info.Offset = new Point(beforeInfo.Offset.X, beforeInfo.Offset.Y);
                            info.Zoom   = beforeInfo.Zoom;
                        }
                        else
                        {
                            //Before, after
                            double ratio = (double)(info.Index - beforeInfo.Index) / (afterInfo.Index - beforeInfo.Index);
                            info.Offset = new Point((int)(ratio * (afterInfo.Offset.X - beforeInfo.Offset.X) + beforeInfo.Offset.X),
                                                    (int)(ratio * (afterInfo.Offset.Y - beforeInfo.Offset.Y) + beforeInfo.Offset.Y));
                            info.Zoom = ratio * (afterInfo.Zoom - beforeInfo.Zoom) + beforeInfo.Zoom;
                        }
                    }
                }

                mAllFrameInfo.Add(info);
            }

            //Update the listbox
            keyFramesListBox.Items.Clear();
            foreach (ClipInfo clipInfo in mKeyFrameInfo)
            {
                keyFramesListBox.Items.Add(string.Format("{0}: ({1},{2})  {3}", clipInfo.Index, clipInfo.Offset.X, clipInfo.Offset.Y, clipInfo.Zoom));
            }

            DrawImage(mSelectedIndex);
        }