Пример #1
0
 public void ReadPixelData(MifHeader header, byte[] buffer, bool isFirstFrame)
 {
     if (header.Flags.HasFlag(MifFlags.Compressed))
     {
         // Read mode.
         MifCompressionMode mode = (MifCompressionMode)ReadByte();
         switch (mode)
         {
             case MifCompressionMode.None: // 0: not compressed
                 ReadRawPixelData(buffer);
                 break;
             case MifCompressionMode.Delta: // 1: delta encoded
                 if (isFirstFrame)
                     throw new InvalidDataException("The first frame must not be delta encoded.");
                 ReadDeltaEncodedPixelData(buffer);
                 break;
             default:
                 throw new NotSupportedException(string.Format(
                     "Compression mode {0} is not supported.", mode));
         }
     }
     else
     {
         ReadRawPixelData(buffer);
     }
 }
Пример #2
0
        /// <summary>
        /// Read a frame.
        /// </summary>
        public MifFrame ReadFrame(MifHeader header, MifFrame prevFrame)
        {
            MifFrame frame = new MifFrame();

            // Read Delay field if present.
            if (header.Flags.HasFlag(MifFlags.HasDelay))
            {
                frame.delay = ReadInt32();
            }

            // Read primary channels.
            frame.colorData = new byte[2 * header.ImageWidth * header.ImageHeight];
            if (prevFrame != null && prevFrame.colorData != null)
            {
                prevFrame.colorData.CopyTo(frame.colorData, 0);
                ReadPixelData(header, frame.colorData, false);
            }
            else
            {
                ReadPixelData(header, frame.colorData, true);
            }

            // Read alpha channel if present.
            if (header.Flags.HasFlag(MifFlags.HasAlpha))
            {
                frame.alphaData = new byte[header.ImageWidth * header.ImageHeight];
                if (prevFrame != null && prevFrame.alphaData != null)
                {
                    prevFrame.alphaData.CopyTo(frame.alphaData, 0);
                    ReadPixelData(header, frame.alphaData, false);
                }
                else
                {
                    ReadPixelData(header, frame.alphaData, true);
                }
            }

            return frame;
        }
Пример #3
0
 /// <summary>
 /// Reads MIF file header. This method does not validate the fields
 /// of the header.
 /// </summary>
 public MifHeader ReadHeader()
 {
     MifHeader header = new MifHeader();
     header.Version = ReadInt32();
     header.ImageWidth = ReadInt32();
     header.ImageHeight = ReadInt32();
     header.Flags = (MifFlags)ReadInt32();
     header.FrameCount = ReadInt32();
     return header;
 }
Пример #4
0
        /// <summary>
        /// Creates a MIF image from the specified stream.
        /// </summary>
        /// <param name="stream">The stream to read the image from. This 
        /// stream is automatically disposed by the constructor, whether the
        /// constructor succeeds or throws an exception. If this is not what
        /// you want, create an extra layer on top of the stream to ignore
        /// Dispose().
        /// </param>
        /// <exception cref="InvalidDataException">The stream does not
        /// contain a valid MIF image format.</exception>
        public MifImage(Stream stream)
        {
            // Create a MIF reader on the stream.
            using (stream)
            using (MifReader reader = new MifReader(stream))
            {
                // Reads and validates the MIF file header.
                this.header = reader.ReadHeader();
                if (!header.Flags.HasFlag(MifFlags.HasImage))
                {
                    throw new InvalidDataException("The stream does not contain an image.");
                }
                if (header.ImageWidth <= 0)
                {
                    throw new InvalidDataException("ImageWidth field must be positive.");
                }
                if (header.ImageHeight <= 0)
                {
                    throw new InvalidDataException("ImageHeight field must be positive.");
                }
                if (header.FrameCount <= 0)
                {
                    throw new InvalidDataException("FrameCount field must be positive.");
                }

                // TODO: avoid DoS attach if FrameCount, Width, or Height
                // are very large.

                // Read all frames at once so that we can close the stream
                // and navigate through the frames easily later.
                frameDiff = new MifFrameDiff[header.FrameCount];
                delays = new int[header.FrameCount];
                MifFrame firstFrame = null, prevFrame = null;
                bool alphaPresent = false;
                for (int i = 0; i < header.FrameCount; i++)
                {
                    // Read the next frame in uncompressed format.
                    MifFrame thisFrame = reader.ReadFrame(header, prevFrame);
                    delays[i] = thisFrame.delay;
                    if (i == 0)
                        firstFrame = thisFrame;

            #if TEST_ZIP_COMPRESSION
                    using (MemoryStream input=new MemoryStream(thisFrame.colorData))
                    using (MemoryStream output=new MemoryStream())
                    using (DeflateStream zip = new DeflateStream(output, CompressionMode.Compress))
                    {
                        input.CopyTo(zip);
                    }
                    using (MemoryStream input = new MemoryStream(thisFrame.alphaData))
                    using (MemoryStream output = new MemoryStream())
                    using (DeflateStream zip = new DeflateStream(output, CompressionMode.Compress))
                    {
                        input.CopyTo(zip);
                    }
            #endif

                    // Check whether this frame contains non-opaque alpha.
                    if (!alphaPresent && thisFrame.alphaData != null)
                    {
                        alphaPresent = thisFrame.alphaData.Any(a => (a < 0x20));
                    }

                    // Store the difference of thisFrame from prevFrame using
                    // delta encoding.
                    if (i > 0)
                    {
                        frameDiff[i] = new MifFrameDiff(prevFrame, thisFrame);
                    }
                    prevFrame = thisFrame;
                }

                // Delta-encode the first frame from the last frame.
                if (header.FrameCount > 1)
                {
                    frameDiff[0] = new MifFrameDiff(prevFrame, firstFrame);
                }

                // If no frame contains a non-opaque alpha, then we don't need
                // to store the alpha channel at all. In this case, the bitmap
                // is 16 bpp. Otherwise, we create a 32-bpp bitmap.
            #if true
                if (!alphaPresent)
                {
                    int stride = (header.ImageWidth * 2 + 3) / 4 * 4;
                    bmpBuffer = new int[stride / 4 * header.ImageHeight];
                    bmpBufferHandle = GCHandle.Alloc(bmpBuffer, GCHandleType.Pinned);
                    bitmap = new Bitmap(
                        header.ImageWidth,
                        header.ImageHeight,
                        stride,
                        PixelFormat.Format16bppRgb565,
                        bmpBufferHandle.AddrOfPinnedObject());
                    colorBuffer = new ArrayPixelBuffer<int>(
                        bmpBuffer,
                        PixelFormat.Format16bppRgb565,
                        stride,
                        header.ImageWidth * 2);
                    alphaBuffer = null;
                }
                else // 32-bpp with alpha channel
            #endif
                {
                    bmpBuffer = new int[header.ImageWidth * header.ImageHeight];
                    bmpBufferHandle = GCHandle.Alloc(bmpBuffer, GCHandleType.Pinned);
                    bitmap = new Bitmap(
                        header.ImageWidth,
                        header.ImageHeight,
                        header.ImageWidth * 4,
                        PixelFormat.Format32bppArgb,
                        bmpBufferHandle.AddrOfPinnedObject());
                    colorBuffer = new MifColorBuffer32(bmpBuffer);
                    alphaBuffer = new MifAlphaBuffer32(bmpBuffer);
                }

                // Render the first frame in the bitmap buffer.
                this.activeIndex = 0;
                firstFrame.UpdateBitmap(colorBuffer, alphaBuffer);

                // If there's only one frame, we don't need frames[] array.
                if (frameDiff.Length == 1)
                {
                    frameDiff = null;
                }

                // If there's no alpha, we don't need to store alpha diff,
                // although this won't really save much memory as we're
                // run-length encoded.
                if (!alphaPresent && frameDiff != null)
                {
                    foreach (MifFrameDiff f in frameDiff)
                        f.RemoveAlpha();
                }
            }
        }