private unsafe List <Rectangle> ProcessChanges(IntPtr Scan0, Rectangle OutputRect, PixelFormat Format, int ImageWidth)
        {
            if (EncodeBuffer == null)
            {
                this.BlockWidth  = (int)Math.Floor((float)(OutputRect.Width / CheckBlock.Width));
                this.BlockHeight = (int)Math.Floor((double)(OutputRect.Height / CheckBlock.Height));
                int TotalBlocks = (int)Math.Floor((float)(BlockHeight * BlockWidth));
                this.EncodeBuffer = new ulong[TotalBlocks];
            }

            List <Rectangle> points = new List <Rectangle>();
            int StartScan           = Scan0.ToInt32();

            for (int y = OutputRect.Y; y < OutputRect.Height + OutputRect.Y; y += CheckBlock.Height)
            {
                if (y + CheckBlock.Height > OutputRect.Height)
                {
                    break;
                }

                for (int x = OutputRect.X; x < OutputRect.Width + OutputRect.X; x += CheckBlock.Width)
                {
                    if (x + CheckBlock.Width > OutputRect.Width)
                    {
                        break;
                    }

                    int    EncodeOffset = GetOffset(x, y);
                    long   offset       = FastBitmap.CalcImageOffset(x, y, Format, ImageWidth);
                    ulong *ScanPtr      = (ulong *)(StartScan + offset);

                    if (EncodeBuffer[EncodeOffset] != *ScanPtr)
                    {
                        EncodeBuffer[EncodeOffset] = *ScanPtr;

                        Rectangle cBlock = new Rectangle(x, y, CheckBlock.Width, CheckBlock.Height);
                        int       index  = points.Count - 1;
                        if (points.Count > 0 && (points[index].X + points[index].Width) == cBlock.X)
                        {
                            Rectangle rect     = points[index];
                            int       newWidth = cBlock.Width + rect.Width;
                            cBlock        = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
                            points[index] = cBlock;
                        }
                        else
                        {
                            points.Add(cBlock);
                        }
                    }
                }
            }
            return(points);
        }
Example #2
0
        public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
        {
            byte *pScan0 = (byte *)Scan0.ToInt32();

            if (!outStream.CanWrite)
            {
                throw new Exception("Must have access to Write in the Stream");
            }

            int Stride    = 0;
            int RawLength = 0;
            int PixelSize = 0;

            switch (Format)
            {
            case PixelFormat.Format24bppRgb:
                PixelSize = 3;
                break;

            case PixelFormat.Format32bppArgb:
            case PixelFormat.Format32bppPArgb:
                PixelSize = 4;
                break;

            default:
                throw new NotSupportedException(Format.ToString());
            }

            Stride    = ImageSize.Width * PixelSize;
            RawLength = Stride * ImageSize.Height;

            if (EncodedWidth == 0 && EncodedHeight == 0)
            {
                this.EncodedFormat = Format;
                this.EncodedWidth  = ImageSize.Width;
                this.EncodedHeight = ImageSize.Height;

                byte[] temp = null;
                using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
                {
                    temp = base.jpgCompression.Compress(TmpBmp);
                }
                outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
                outStream.Write(temp, 0, temp.Length);
                return;
            }

            Frame frame = new Frame(ImageSize.Width, ImageSize.Height);

            int Blocks      = (ScanArea.Width / CheckBlock.Width) * (ScanArea.Height / CheckBlock.Height);
            int RawSizeUsed = 0;

            long oldPos = outStream.Position;

            outStream.Write(new byte[4], 0, 4);
            int TotalDataLength            = 0;
            List <Rectangle> ChangedBlocks = new List <Rectangle>();

            for (int y = ScanArea.Y; y < ScanArea.Height;)
            {
                int height = y + CheckBlock.Height < ScanArea.Height ? CheckBlock.Height : ScanArea.Height - y;
                for (int x = ScanArea.X; x < ScanArea.Width;)
                {
                    int     width       = x + CheckBlock.Width < ScanArea.Width ? CheckBlock.Width : ScanArea.Width - x;
                    int     BlockStride = Format == PixelFormat.Format24bppRgb ? width * 3 : width * 4;
                    decimal FinalHash   = 0;

                    for (int h = 0; h < height; h++)
                    {
                        int Offset = FastBitmap.CalcImageOffset(x, y + h, Format, ImageSize.Width);
                        FinalHash += Hasher.Hash(pScan0 + Offset, BlockStride);
                    }

                    if (onCodeDebugScan != null)
                    {
                        onCodeDebugScan(new Rectangle(x, y, width, height));
                    }

                    bool    FoundBlock = false;
                    decimal FoundHash  = 0;
                    int     FrameIndex = 0;
                    for (int i = 0; i < Frames.Count; i++)
                    {
                        decimal hash = Frames[i].GetHashBlock(x, y);
                        if (hash == FinalHash)
                        {
                            FrameIndex = i;
                            FoundBlock = true;
                            FoundHash  = hash;
                            break;
                        }
                    }

                    frame.AddHashBlock(x, y, FinalHash);

                    if (!FoundBlock)
                    {
                        int       index  = ChangedBlocks.Count - 1;
                        Rectangle cBlock = new Rectangle(x, y, width, height);

                        if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].X + ChangedBlocks[index].Width) == cBlock.X)
                        {
                            Rectangle rect     = ChangedBlocks[index];
                            int       newWidth = cBlock.Width + rect.Width;
                            cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
                            ChangedBlocks[index] = cBlock;
                        }

                        /*else if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].Y + ChangedBlocks[index].Height) == cBlock.Y)
                         * {
                         *  Rectangle rect = ChangedBlocks[index];
                         *  int newHeight = cBlock.Height + rect.Height;
                         *  cBlock = new Rectangle(rect.X, rect.Y, rect.Width, newHeight);
                         *  ChangedBlocks[index] = cBlock;
                         * }*/
                        else
                        {
                            ChangedBlocks.Add(cBlock);
                        }
                        RawSizeUsed += BlockStride * height;
                    }
                    x += width;
                }
                y += height;
            }

            //write all the blocks
            for (int i = 0; i < ChangedBlocks.Count; i++)
            {
                Rectangle rect        = ChangedBlocks[i];
                int       blockStride = PixelSize * rect.Width;

                Bitmap     TmpBmp  = new Bitmap(rect.Width, rect.Height, Format);
                BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
                for (int j = 0, offset = 0; j < rect.Height; j++)
                {
                    int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
                    NativeMethods.memcpy((byte *)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
                    offset += blockStride;
                }
                TmpBmp.UnlockBits(TmpData);

                outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
                outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
                outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
                outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
                outStream.Write(new byte[4], 0, 4);

                long length = outStream.Position;
                long OldPos = outStream.Position;
                base.jpgCompression.Compress(TmpBmp, ref outStream);
                length = outStream.Position - length;

                outStream.Position = OldPos - 4;
                outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
                outStream.Position += length;

                TmpBmp.Dispose();
                TotalDataLength += (int)length + (4 * 5);
            }
            outStream.Position = oldPos;
            outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
            ChangedBlocks.Clear();

            Frames.Add(frame);
            if (Frames.Count > MAX_FRAMES)
            {
                Frames.RemoveAt(0);
            }
        }
Example #3
0
        public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
        {
            lock (this.ImageProcessLock)
            {
                byte *pScan0 = (byte *)Scan0.ToInt32();
                if (!outStream.CanWrite)
                {
                    throw new Exception("Must have access to Write in the Stream");
                }

                int Stride    = 0;
                int RawLength = 0;
                int PixelSize = 0;

                FastBitmap.CalcImageOffset(0, 0, Format, ScanArea.Width); //check for FastBitmap Support
                switch (Format)
                {
                case PixelFormat.Format24bppRgb:
                case PixelFormat.Format32bppRgb:
                    PixelSize = 3;
                    break;

                case PixelFormat.Format32bppArgb:
                case PixelFormat.Format32bppPArgb:
                    PixelSize = 4;
                    break;

                default:
                    throw new NotSupportedException(Format + " is not supported.");
                }

                Stride    = ImageSize.Width * PixelSize;
                RawLength = Stride * ImageSize.Height;

                //first frame
                if (EncodeBuffer == null)
                {
                    this.EncodedFormat = Format;
                    this.EncodedWidth  = ImageSize.Width;
                    this.EncodedHeight = ImageSize.Height;
                    this.EncodeBuffer  = new byte[RawLength];
                    fixed(byte *ptr = EncodeBuffer)
                    {
                        byte[] temp = null;
                        using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
                        {
                            temp = base.jpgCompression.Compress(TmpBmp);
                        }

                        outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
                        outStream.Write(temp, 0, temp.Length);
                        NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
                    }

                    return;
                }

                if (this.EncodedFormat != Format)
                {
                    throw new Exception("PixelFormat is not equal to previous Bitmap");
                }
                if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
                {
                    throw new Exception("Bitmap width/height are not equal to previous bitmap");
                }
                if (ScanArea.Width > ImageSize.Width || ImageSize.Height > this.EncodedHeight)
                {
                    throw new Exception("Scan Area Width/Height cannot be greater then the encoded image");
                }


                List <Rectangle> Blocks = new List <Rectangle>(); //all the changes
                fixed(byte *encBuffer = EncodeBuffer)
                {
                    //1. Check for the changes in height
                    for (int y = ScanArea.Y; y < ScanArea.Height; y++)
                    {
                        Rectangle cBlock = new Rectangle(0, y, ImageSize.Width, 1);

                        if (onCodeDebugScan != null)
                        {
                            onCodeDebugScan(cBlock);
                        }

                        int Offset = FastBitmap.CalcImageOffset(0, y, Format, ImageSize.Width);
                        if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
                        {
                            int index = Blocks.Count - 1;
                            if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
                            {
                                cBlock        = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
                                Blocks[index] = cBlock;
                            }
                            else
                            {
                                Blocks.Add(cBlock);
                            }
                        }
                    }

                    //2. Capture all the changes using the CheckBlock
                    List <Rectangle> finalUpdates = new List <Rectangle>();

                    for (int i = 0; i < Blocks.Count; i++)
                    {
                        Rectangle scanBlock = Blocks[i];

                        //go through the Blocks
                        for (int y = scanBlock.Y; y < scanBlock.Height; y += CheckBlock.Height)
                        {
                            for (int x = scanBlock.X; x < scanBlock.Width; x += CheckBlock.Width)
                            {
                                int       blockWidth  = x + CheckBlock.Width < scanBlock.Width ? CheckBlock.Width : scanBlock.Width - x;
                                int       blockHeight = y + CheckBlock.Height < scanBlock.Height ? CheckBlock.Height : scanBlock.Height - y;
                                Rectangle cBlock      = new Rectangle(x, y, blockWidth, blockHeight);

                                if (onCodeDebugScan != null)
                                {
                                    onCodeDebugScan(cBlock);
                                }

                                //scan the block from Top To Bottom and check for changes
                                bool FoundChanges = false;
                                for (int blockY = y; blockY < y + blockHeight; blockY++)
                                {
                                    int Offset = FastBitmap.CalcImageOffset(x, blockY, Format, blockWidth);
                                    if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
                                    {
                                        FoundChanges = true;
                                        break;
                                    }
                                }

                                if (FoundChanges)
                                {
                                    int index = finalUpdates.Count - 1;
                                    if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
                                    {
                                        Rectangle rect     = finalUpdates[index];
                                        int       newWidth = cBlock.Width + rect.Width;
                                        cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
                                        finalUpdates[index] = cBlock;
                                    }
                                    else
                                    {
                                        finalUpdates.Add(cBlock);
                                    }
                                }
                            }
                        }
                    }

                    //maybe a too hard algorithm but oh well
                    SortedList <int, SortedList <int, Rectangle> > Array = finalUpdates.ToArray().RectanglesTo2D().Rectangle2DToRows();
                    List <Rectangle> FinalTemp = new List <Rectangle>();

                    for (int i = 0; i < Array.Values.Count; i++)
                    {
                        FinalTemp.AddRange(Array.Values[i].Values);
                    }

                    //fixup the height
                    for (int i = 0; i < FinalTemp.Count;)
                    {
                        if (FinalTemp.Count == 1)
                        {
                            FinalTemp.Add(FinalTemp[i]);
                            break;
                        }

                        if (i + 1 < FinalTemp.Count)
                        {
                            Rectangle curRect  = FinalTemp[i];
                            Rectangle nextRect = FinalTemp[i + 1];
                            if ((curRect.Y + curRect.Height) == nextRect.Y && curRect.Width == nextRect.Width)
                            {
                                FinalTemp[i] = new Rectangle(curRect.X, curRect.Y, curRect.Width, curRect.Height + curRect.Height);
                                FinalTemp.RemoveAt(i + 1);
                            }
                            else
                            {
                                i++;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }

                    //copy changes to the EncodeBuffer and Process the Output
                    long oldPos = outStream.Position;

                    outStream.Write(new byte[4], 0, 4);
                    int TotalDataLength = 0;

                    for (int i = 0; i < FinalTemp.Count; i++)
                    {
                        Rectangle rect        = FinalTemp[i];
                        int       blockStride = PixelSize * rect.Width;

                        //copy changes to EncodeBuffer
                        for (int y = rect.Y; y < rect.Y + rect.Height; y++)
                        {
                            int Offset = FastBitmap.CalcImageOffset(rect.X, y, Format, rect.Width);
                            NativeMethods.memcpy(encBuffer + Offset, pScan0 + Offset, (uint)blockStride); //copy-changes
                        }

                        Bitmap     TmpBmp  = new Bitmap(rect.Width, rect.Height, Format);
                        BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
                        for (int j = 0, offset = 0; j < rect.Height; j++)
                        {
                            int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
                            NativeMethods.memcpy((byte *)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
                            offset += blockStride;
                        }
                        TmpBmp.UnlockBits(TmpData);

                        outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
                        outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
                        outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
                        outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
                        outStream.Write(new byte[4], 0, 4);

                        long length = outStream.Position;
                        long OldPos = outStream.Position;
                        base.jpgCompression.Compress(TmpBmp, ref outStream);
                        length = outStream.Position - length;

                        outStream.Position = OldPos - 4;
                        outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
                        outStream.Position += length;
                        TmpBmp.Dispose();
                        TotalDataLength += (int)length + (4 * 5);
                    }

                    outStream.Position = oldPos;
                    outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
                    Blocks.Clear();
                }
            }
        }