/// <summary>
        /// Reads and returns an application extension from the supplied input
        /// stream.
        /// </summary>
        /// <param name="inputStream">
        /// The input stream to read.
        /// </param>
        /// <param name="xmlDebugging">Whether or not to create debug XML</param>
        public ApplicationExtension(Stream inputStream, bool xmlDebugging)
            : base(xmlDebugging)
        {
            DataBlock identificationBlock = new DataBlock(inputStream,
                                                          XmlDebugging);
            Collection <DataBlock> applicationData = new Collection <DataBlock>();

            if (!identificationBlock.TestState(ErrorState.EndOfInputStream))
            {
                // Read application specific data
                DataBlock thisBlock;
                do
                {
                    thisBlock = new DataBlock(inputStream, XmlDebugging);
                    applicationData.Add(thisBlock);
                }
                // A zero-length block indicates the end of the data blocks
                while(thisBlock.DeclaredBlockSize != 0 &&
                      !thisBlock.TestState(ErrorState.EndOfInputStream)
                      );
            }

            SaveData(identificationBlock, applicationData);
        }
Esempio n. 2
0
		/// <summary>
		/// Constructor.
		/// </summary>
		/// <param name="inputStream">
		/// The stream from which the image data is to be read, starting with
		/// the LZW minimum code size, and ending with a block terminator.
		/// </param>
		/// <param name="pixelCount">
		/// Number of pixels in the image.
		/// </param>
		/// <param name="xmlDebugging">Whether or not to create debug XML</param>
		/// <remarks>
		/// The input stream is read, first into the LZW minimum code size, then
		/// into data blocks. Bytes are extracted from the data blocks into a
		/// datum until the datum contains enough bits to form a code; this code
		/// is then extracted from the datum and decoded into a pixel index.
		/// Once all data has been read, or a block terminator, 
		/// end-of-information code or error condition is encountered, any
		/// remaining pixel indices not already populated default to zero.
		/// </remarks>
		public TableBasedImageData( Stream inputStream, 
		                            int pixelCount, 
		                            bool xmlDebugging )
			: base( xmlDebugging )
		{
			#region guard against silly image sizes
			if( pixelCount < 1 )
			{
				string message
					= "The pixel count must be greater than zero. "
					+ "Supplied value was " + pixelCount;
				throw new ArgumentOutOfRangeException( "pixelCount", message );
			}
			#endregion
			
			#region declare / initialise local variables
			_pixels = new IndexedPixels( pixelCount );
			_dataBlocks = new Collection<DataBlock>();
			int nextAvailableCode; // the next code to be added to the dictionary
			int	currentCodeSize;
			int	in_code;
			int	previousCode;
			int	code;
			int	datum = 0; // temporary storage for codes read from the input stream
			int	meaningfulBitsInDatum = 0; // number of bits of useful information held in the datum variable
			int	firstCode = 0; // first code read from the stream since last clear code
			int	indexInDataBlock = 0;
			int	pixelIndex = 0;
			
			// number of bytes still to be extracted from the current data block
			int bytesToExtract = 0; 

			short[] prefix = new short[_maxStackSize];
			byte[] suffix = new byte[_maxStackSize];
			Stack<byte> pixelStack = new Stack<byte>();
			#endregion

			//  Initialize GIF data stream decoder.
			_lzwMinimumCodeSize = Read( inputStream ); // number of bits initially used for LZW codes in image data
			WriteDebugXmlElement( "LzwMinimumCodeSize", _lzwMinimumCodeSize );
			nextAvailableCode = ClearCode + 2;
			previousCode = _nullCode;
			currentCodeSize = InitialCodeSize;
			
			#region guard against LZW code size being too large
			if( ClearCode >= _maxStackSize )
			{
				string message
					= "LZW minimum code size: " + _lzwMinimumCodeSize
					+ ". Clear code: " + ClearCode
					+ ". Max stack size: " + _maxStackSize;
				SetStatus( ErrorState.LzwMinimumCodeSizeTooLarge, message );
				WriteDebugXmlFinish();
				return;
			}
			#endregion
			
			// TODO: what are prefix and suffix and why are we initialising them like this?
			for( code = 0; code < ClearCode; code++ )
			{
				prefix[code] = 0;
				suffix[code] = (byte) code;
			}
			
			WriteDebugXmlStartElement( "DataBlocks" );

			#region decode LZW image data

			// Initialise block to an empty data block. This will be overwritten
			// first time through the loop with a data block read from the input
			// stream.
			DataBlock block = new DataBlock( 0, new byte[0] );
			
			for( pixelIndex = 0; pixelIndex < pixelCount; ) 
			{
				if( pixelStack.Count == 0 )
				{
					// There are no pixels in the stack at the moment, so...
					#region get some pixels and put them on the stack
					if( meaningfulBitsInDatum < currentCodeSize )
					{
						// Then we don't have enough bits in the datum to make
						// a code; we need to get some more from the current
						// data block, or we may need to read another data
						// block from the input stream
						#region get another byte from the current data block
						if( bytesToExtract == 0 )
						{
							// Then we've extracted all the bytes from the 
							// current data block, so...
							
							#region	read the next data block from the stream
							block = ReadDataBlock( inputStream );
							bytesToExtract = block.ActualBlockSize;
							
							// Point to the first byte in the new data block
							indexInDataBlock = 0;

							if( block.TestState( ErrorState.DataBlockTooShort ) )
							{
								// then we've reached the end of the stream
								// prematurely
								break;
							}
							
							if( bytesToExtract == 0 )
							{
								// then it's a block terminator, end of the
								// image data (this is a data block other than
								// the first one)
								break;
							}
							#endregion
						}
						// Append the contents of the current byte in the data 
						// block to the beginning of the datum
						int newDatum = block[indexInDataBlock] << meaningfulBitsInDatum;
						datum += newDatum;

						// so we've now got 8 more bits of information in the
						// datum.
						meaningfulBitsInDatum += 8;
						
						// Point to the next byte in the data block
						indexInDataBlock++;
						
						// We've one less byte still to read from the data block
						// now.
						bytesToExtract--;
						
						// and carry on reading through the data block
						continue;
						#endregion
					}

					#region get the next code from the datum
					// Get the least significant bits from the read datum, up
					// to the maximum allowed by the current code size.
					code = datum & GetMaximumPossibleCode( currentCodeSize );
					
					// Drop the bits we've just extracted from the datum.
					datum >>= currentCodeSize;
					
					// Reduce the count of meaningful bits held in the datum
					meaningfulBitsInDatum -= currentCodeSize;
					#endregion

					#region interpret the code

					#region end of information?
					if( code == EndOfInformation )
					{
						// We've reached an explicit marker for the end of the
						// image data.
						break;
					}
					#endregion

					#region code not in dictionary?
					if( code > nextAvailableCode )
					{
						// We expect the code to be either one which is already
						// in the dictionary, or the next available one to be
						// added. If it's neither of these then abandon 
						// processing of the image data.
						string message
							= "Next available code: " + nextAvailableCode
							+ ". Last code read from input stream: " + code;
						SetStatus( ErrorState.CodeNotInDictionary, message );
						break;
					}
					#endregion

					#region clear code?
					if( code == ClearCode )
					{
						// We can get a clear code at any point in the image
						// data, this is an instruction to reset the decoder
						// and empty the dictionary of codes.
						currentCodeSize = InitialCodeSize;
						nextAvailableCode = ClearCode + 2;
						previousCode = _nullCode;

						// Carry on reading from the input stream.
						continue;
					}
					#endregion
					
					#region first code since last clear code?
					if( previousCode == _nullCode )
					{
						// This is the first code read since the start of the
						// image data or the most recent clear code.
						// There's no previously read code in memory yet, so
						// get the pixel index for the current code and add it
						// to the stack.
						pixelStack.Push( suffix[code] );
						previousCode = code;
						firstCode = code;
						
						// and carry on to the next pixel
						continue;
					}
					#endregion

					in_code = code;
					if( code == nextAvailableCode )
					{
						pixelStack.Push( (byte) firstCode );
						code = previousCode;
					}
					
					while( code > ClearCode )
					{
						pixelStack.Push( suffix[code] );
						code = prefix[code];
					}

					#endregion

					firstCode = ((int) suffix[code]) & 0xff;

					#region add a new string to the string table
					if( nextAvailableCode >= _maxStackSize )
					{
						// TESTME: constructor - next available code >- _maxStackSize
						break;
					}
					pixelStack.Push( (byte) firstCode );
					prefix[nextAvailableCode] = (short) previousCode;
					suffix[nextAvailableCode] = (byte) firstCode;
					nextAvailableCode++;
					#endregion
					
					#region do we need to increase the code size?
					if( ( nextAvailableCode & GetMaximumPossibleCode( currentCodeSize ) ) == 0 )
					{
						// We've reached the largest code possible for this size
						if( nextAvailableCode < _maxStackSize )
						{
							// so increase the code size by 1
							currentCodeSize++;
						}
					}
					#endregion

					previousCode = in_code;
					#endregion
				}

				// Pop all the pixels currently on the stack off, and add them
				// to the return value.
				_pixels[pixelIndex] = pixelStack.Pop();
				pixelIndex++;
			}

			#endregion

			#region check input stream contains enough data to fill the image
			if( pixelIndex < pixelCount )
			{
				string message
					= "Expected pixel count: " + pixelCount
					+ ". Actual pixel count: " + pixelIndex;
				SetStatus( ErrorState.TooFewPixelsInImageData, message );
			}
			#endregion
			
			if( XmlDebugging )
			{
				WriteDebugXmlEndElement();
				byte[] bytes = new byte[_pixels.Count];
				_pixels.CopyTo( bytes, 0 );
				WriteDebugXmlByteValues( "IndexedPixels", bytes );
				WriteDebugXmlFinish();
			}
		}
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="inputStream">
        /// The stream from which the image data is to be read, starting with
        /// the LZW minimum code size, and ending with a block terminator.
        /// </param>
        /// <param name="pixelCount">
        /// Number of pixels in the image.
        /// </param>
        /// <param name="xmlDebugging">Whether or not to create debug XML</param>
        /// <remarks>
        /// The input stream is read, first into the LZW minimum code size, then
        /// into data blocks. Bytes are extracted from the data blocks into a
        /// datum until the datum contains enough bits to form a code; this code
        /// is then extracted from the datum and decoded into a pixel index.
        /// Once all data has been read, or a block terminator,
        /// end-of-information code or error condition is encountered, any
        /// remaining pixel indices not already populated default to zero.
        /// </remarks>
        public TableBasedImageData(Stream inputStream,
                                   int pixelCount,
                                   bool xmlDebugging)
            : base(xmlDebugging)
        {
            #region guard against silly image sizes
            if (pixelCount < 1)
            {
                string message
                    = "The pixel count must be greater than zero. "
                      + "Supplied value was " + pixelCount;
                throw new ArgumentOutOfRangeException("pixelCount", message);
            }
            #endregion

            #region declare / initialise local variables
            _pixels     = new IndexedPixels(pixelCount);
            _dataBlocks = new Collection <DataBlock>();
            int nextAvailableCode;             // the next code to be added to the dictionary
            int currentCodeSize;
            int in_code;
            int previousCode;
            int code;
            int datum = 0;                 // temporary storage for codes read from the input stream
            int meaningfulBitsInDatum = 0; // number of bits of useful information held in the datum variable
            int firstCode             = 0; // first code read from the stream since last clear code
            int indexInDataBlock      = 0;
            int pixelIndex            = 0;

            // number of bytes still to be extracted from the current data block
            int bytesToExtract = 0;

            short[]      prefix     = new short[_maxStackSize];
            byte[]       suffix     = new byte[_maxStackSize];
            Stack <byte> pixelStack = new Stack <byte>();
            #endregion

            //  Initialize GIF data stream decoder.
            _lzwMinimumCodeSize = Read(inputStream);               // number of bits initially used for LZW codes in image data
            WriteDebugXmlElement("LzwMinimumCodeSize", _lzwMinimumCodeSize);
            nextAvailableCode = ClearCode + 2;
            previousCode      = _nullCode;
            currentCodeSize   = InitialCodeSize;

            #region guard against LZW code size being too large
            if (ClearCode >= _maxStackSize)
            {
                string message
                    = "LZW minimum code size: " + _lzwMinimumCodeSize
                      + ". Clear code: " + ClearCode
                      + ". Max stack size: " + _maxStackSize;
                SetStatus(ErrorState.LzwMinimumCodeSizeTooLarge, message);
                WriteDebugXmlFinish();
                return;
            }
            #endregion

            // TODO: what are prefix and suffix and why are we initialising them like this?
            for (code = 0; code < ClearCode; code++)
            {
                prefix[code] = 0;
                suffix[code] = (byte)code;
            }

            WriteDebugXmlStartElement("DataBlocks");

            #region decode LZW image data

            // Initialise block to an empty data block. This will be overwritten
            // first time through the loop with a data block read from the input
            // stream.
            DataBlock block = new DataBlock(0, new byte[0]);

            for (pixelIndex = 0; pixelIndex < pixelCount;)
            {
                if (pixelStack.Count == 0)
                {
                    // There are no pixels in the stack at the moment, so...
                    #region get some pixels and put them on the stack
                    if (meaningfulBitsInDatum < currentCodeSize)
                    {
                        // Then we don't have enough bits in the datum to make
                        // a code; we need to get some more from the current
                        // data block, or we may need to read another data
                        // block from the input stream
                        #region get another byte from the current data block
                        if (bytesToExtract == 0)
                        {
                            // Then we've extracted all the bytes from the
                            // current data block, so...

                            #region read the next data block from the stream
                            block          = ReadDataBlock(inputStream);
                            bytesToExtract = block.ActualBlockSize;

                            // Point to the first byte in the new data block
                            indexInDataBlock = 0;

                            if (block.TestState(ErrorState.DataBlockTooShort))
                            {
                                // then we've reached the end of the stream
                                // prematurely
                                break;
                            }

                            if (bytesToExtract == 0)
                            {
                                // then it's a block terminator, end of the
                                // image data (this is a data block other than
                                // the first one)
                                break;
                            }
                            #endregion
                        }
                        // Append the contents of the current byte in the data
                        // block to the beginning of the datum
                        int newDatum = block[indexInDataBlock] << meaningfulBitsInDatum;
                        datum += newDatum;

                        // so we've now got 8 more bits of information in the
                        // datum.
                        meaningfulBitsInDatum += 8;

                        // Point to the next byte in the data block
                        indexInDataBlock++;

                        // We've one less byte still to read from the data block
                        // now.
                        bytesToExtract--;

                        // and carry on reading through the data block
                        continue;
                        #endregion
                    }

                    #region get the next code from the datum
                    // Get the least significant bits from the read datum, up
                    // to the maximum allowed by the current code size.
                    code = datum & GetMaximumPossibleCode(currentCodeSize);

                    // Drop the bits we've just extracted from the datum.
                    datum >>= currentCodeSize;

                    // Reduce the count of meaningful bits held in the datum
                    meaningfulBitsInDatum -= currentCodeSize;
                    #endregion

                    #region interpret the code

                    #region end of information?
                    if (code == EndOfInformation)
                    {
                        // We've reached an explicit marker for the end of the
                        // image data.
                        break;
                    }
                    #endregion

                    #region code not in dictionary?
                    if (code > nextAvailableCode)
                    {
                        // We expect the code to be either one which is already
                        // in the dictionary, or the next available one to be
                        // added. If it's neither of these then abandon
                        // processing of the image data.
                        string message
                            = "Next available code: " + nextAvailableCode
                              + ". Last code read from input stream: " + code;
                        SetStatus(ErrorState.CodeNotInDictionary, message);
                        break;
                    }
                    #endregion

                    #region clear code?
                    if (code == ClearCode)
                    {
                        // We can get a clear code at any point in the image
                        // data, this is an instruction to reset the decoder
                        // and empty the dictionary of codes.
                        currentCodeSize   = InitialCodeSize;
                        nextAvailableCode = ClearCode + 2;
                        previousCode      = _nullCode;

                        // Carry on reading from the input stream.
                        continue;
                    }
                    #endregion

                    #region first code since last clear code?
                    if (previousCode == _nullCode)
                    {
                        // This is the first code read since the start of the
                        // image data or the most recent clear code.
                        // There's no previously read code in memory yet, so
                        // get the pixel index for the current code and add it
                        // to the stack.
                        pixelStack.Push(suffix[code]);
                        previousCode = code;
                        firstCode    = code;

                        // and carry on to the next pixel
                        continue;
                    }
                    #endregion

                    in_code = code;
                    if (code == nextAvailableCode)
                    {
                        pixelStack.Push((byte)firstCode);
                        code = previousCode;
                    }

                    while (code > ClearCode)
                    {
                        pixelStack.Push(suffix[code]);
                        code = prefix[code];
                    }

                    #endregion

                    firstCode = ((int)suffix[code]) & 0xff;

                    #region add a new string to the string table
                    if (nextAvailableCode >= _maxStackSize)
                    {
                        // TESTME: constructor - next available code >- _maxStackSize
                        break;
                    }
                    pixelStack.Push((byte)firstCode);
                    prefix[nextAvailableCode] = (short)previousCode;
                    suffix[nextAvailableCode] = (byte)firstCode;
                    nextAvailableCode++;
                    #endregion

                    #region do we need to increase the code size?
                    if ((nextAvailableCode & GetMaximumPossibleCode(currentCodeSize)) == 0)
                    {
                        // We've reached the largest code possible for this size
                        if (nextAvailableCode < _maxStackSize)
                        {
                            // so increase the code size by 1
                            currentCodeSize++;
                        }
                    }
                    #endregion

                    previousCode = in_code;
                    #endregion
                }

                // Pop all the pixels currently on the stack off, and add them
                // to the return value.
                _pixels[pixelIndex] = pixelStack.Pop();
                pixelIndex++;
            }

            #endregion

            #region check input stream contains enough data to fill the image
            if (pixelIndex < pixelCount)
            {
                string message
                    = "Expected pixel count: " + pixelCount
                      + ". Actual pixel count: " + pixelIndex;
                SetStatus(ErrorState.TooFewPixelsInImageData, message);
            }
            #endregion

            if (XmlDebugging)
            {
                WriteDebugXmlEndElement();
                byte[] bytes = new byte[_pixels.Count];
                _pixels.CopyTo(bytes, 0);
                WriteDebugXmlByteValues("IndexedPixels", bytes);
                WriteDebugXmlFinish();
            }
        }
Esempio n. 4
0
		/// <summary>
		/// Reads and returns an application extension from the supplied input 
		/// stream.
		/// </summary>
		/// <param name="inputStream">
		/// The input stream to read.
		/// </param>
		/// <param name="xmlDebugging">Whether or not to create debug XML</param>
		public ApplicationExtension( Stream inputStream, bool xmlDebugging )
			: base( xmlDebugging )
		{
			DataBlock identificationBlock = new DataBlock( inputStream, 
			                                               XmlDebugging );
			Collection<DataBlock> applicationData = new Collection<DataBlock>();
			if( !identificationBlock.TestState( ErrorState.EndOfInputStream ) )
			{
				// Read application specific data
				DataBlock thisBlock;
				do
				{
					thisBlock = new DataBlock( inputStream, XmlDebugging );
					applicationData.Add( thisBlock );
				}
				// A zero-length block indicates the end of the data blocks
				while( thisBlock.DeclaredBlockSize != 0 
				       && !thisBlock.TestState( ErrorState.EndOfInputStream ) 
				     );
			}
			
			SaveData( identificationBlock, applicationData );
		}