Пример #1
0
        /// <summary>
        /// Decodes the image data from a specified IFD.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="tags">The IFD tags.</param>
        /// <param name="cancellationToken">The token to monitor cancellation.</param>
        /// <returns> The tiff frame. </returns>
        private ImageFrame <TPixel> DecodeFrame <TPixel>(ExifProfile tags, CancellationToken cancellationToken)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            ImageFrameMetadata imageFrameMetaData = this.ignoreMetadata ?
                                                    new ImageFrameMetadata() :
                                                    new ImageFrameMetadata {
                ExifProfile = tags, XmpProfile = tags.GetValue(ExifTag.XMP)?.Value
            };

            TiffFrameMetadata tiffFrameMetaData = imageFrameMetaData.GetTiffMetadata();

            TiffFrameMetadata.Parse(tiffFrameMetaData, tags);

            this.VerifyAndParse(tags, tiffFrameMetaData);

            int width  = GetImageWidth(tags);
            int height = GetImageHeight(tags);
            var frame  = new ImageFrame <TPixel>(this.Configuration, width, height, imageFrameMetaData);

            int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity;

            Number[] stripOffsets    = tags.GetValue(ExifTag.StripOffsets)?.Value;
            Number[] stripByteCounts = tags.GetValue(ExifTag.StripByteCounts)?.Value;

            if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar)
            {
                this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken);
            }
            else
            {
                this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken);
            }

            return(frame);
        }
Пример #2
0
        /// <summary>
        /// Returns a new <see cref="TiffFrameMetadata"/> instance parsed from the given Exif profile.
        /// </summary>
        /// <param name="profile">The Exif profile containing tiff frame directory tags to parse.
        /// If null, a new instance is created and parsed instead.</param>
        /// <returns>The <see cref="TiffFrameMetadata"/>.</returns>
        internal static TiffFrameMetadata Parse(ExifProfile profile)
        {
            var meta = new TiffFrameMetadata();

            Parse(meta, profile);
            return(meta);
        }
Пример #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class.
 /// </summary>
 /// <param name="other">The other tiff frame metadata.</param>
 private TiffFrameMetadata(TiffFrameMetadata other)
 {
     this.BitsPerPixel = other.BitsPerPixel;
     this.Compression  = other.Compression;
     this.PhotometricInterpretation = other.PhotometricInterpretation;
     this.Predictor = other.Predictor;
 }
Пример #4
0
        /// <summary>
        /// Decodes the image data from a specified IFD.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="tags">The IFD tags.</param>
        /// <param name="cancellationToken">The token to monitor cancellation.</param>
        /// <returns> The tiff frame. </returns>
        private ImageFrame <TPixel> DecodeFrame <TPixel>(ExifProfile tags, CancellationToken cancellationToken)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            var imageFrameMetaData = new ImageFrameMetadata();

            if (!this.ignoreMetadata)
            {
                imageFrameMetaData.ExifProfile = tags;
            }

            TiffFrameMetadata tiffFrameMetaData = imageFrameMetaData.GetTiffMetadata();

            TiffFrameMetadata.Parse(tiffFrameMetaData, tags);

            this.VerifyAndParse(tags, tiffFrameMetaData);

            int width  = GetImageWidth(tags);
            int height = GetImageHeight(tags);
            var frame  = new ImageFrame <TPixel>(this.Configuration, width, height, imageFrameMetaData);

            int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity;

            var stripOffsetsArray    = (Array)tags.GetValueInternal(ExifTag.StripOffsets).GetValue();
            var stripByteCountsArray = (Array)tags.GetValueInternal(ExifTag.StripByteCounts).GetValue();

            IMemoryOwner <ulong> stripOffsetsMemory    = this.ConvertNumbers(stripOffsetsArray, out Span <ulong> stripOffsets);
            IMemoryOwner <ulong> stripByteCountsMemory = this.ConvertNumbers(stripByteCountsArray, out Span <ulong> stripByteCounts);

            if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar)
            {
                this.DecodeStripsPlanar(
                    frame,
                    rowsPerStrip,
                    stripOffsets,
                    stripByteCounts,
                    cancellationToken);
            }
            else
            {
                this.DecodeStripsChunky(
                    frame,
                    rowsPerStrip,
                    stripOffsets,
                    stripByteCounts,
                    cancellationToken);
            }

            stripOffsetsMemory?.Dispose();
            stripByteCountsMemory?.Dispose();
            return(frame);
        }
Пример #5
0
        /// <inheritdoc/>
        public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
        {
            this.inputStream = stream;
            var reader = new DirectoryReader(stream, this.Configuration.MemoryAllocator);
            IEnumerable <ExifProfile> directories = reader.Read();

            ExifProfile rootFrameExifProfile = directories.First();
            var         rootMetadata         = TiffFrameMetadata.Parse(rootFrameExifProfile);

            ImageMetadata metadata = TiffDecoderMetadataCreator.Create(reader.ByteOrder, reader.IsBigTiff, rootFrameExifProfile);
            int           width    = GetImageWidth(rootFrameExifProfile);
            int           height   = GetImageHeight(rootFrameExifProfile);

            return(new ImageInfo(new PixelTypeInfo((int)rootMetadata.BitsPerPixel), width, height, metadata));
        }
        private static void VerifyRequiredFieldsArePresent(ExifProfile exifProfile, TiffFrameMetadata frameMetadata)
        {
            if (exifProfile.GetValueInternal(ExifTag.StripOffsets) is null)
            {
                TiffThrowHelper.ThrowImageFormatException("StripOffsets are missing and are required for decoding the TIFF image!");
            }

            if (exifProfile.GetValueInternal(ExifTag.StripByteCounts) is null)
            {
                TiffThrowHelper.ThrowImageFormatException("StripByteCounts are missing and are required for decoding the TIFF image!");
            }

            if (frameMetadata.BitsPerPixel == null)
            {
                TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image!");
            }
        }
Пример #7
0
        /// <summary>
        /// Parses the given Exif profile to populate the properties of the tiff frame meta data.
        /// </summary>
        /// <param name="meta">The tiff frame meta data.</param>
        /// <param name="profile">The Exif profile containing tiff frame directory tags.</param>
        internal static void Parse(TiffFrameMetadata meta, ExifProfile profile)
        {
            if (profile != null)
            {
                if (TiffBitsPerSample.TryParse(profile.GetValue(ExifTag.BitsPerSample)?.Value, out TiffBitsPerSample bitsPerSample))
                {
                    meta.BitsPerSample = bitsPerSample;
                }

                meta.BitsPerPixel = meta.BitsPerSample?.BitsPerPixel();
                meta.Compression  = (TiffCompression?)profile.GetValue(ExifTag.Compression)?.Value;
                meta.PhotometricInterpretation = (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value;
                meta.Predictor = (TiffPredictor?)profile.GetValue(ExifTag.Predictor)?.Value;

                profile.RemoveValue(ExifTag.BitsPerSample);
                profile.RemoveValue(ExifTag.Compression);
                profile.RemoveValue(ExifTag.PhotometricInterpretation);
                profile.RemoveValue(ExifTag.Predictor);
            }
        }
        /// <summary>
        /// Determines the TIFF compression and color types, and reads any associated parameters.
        /// </summary>
        /// <param name="options">The options.</param>
        /// <param name="exifProfile">The exif profile of the frame to decode.</param>
        /// <param name="frameMetadata">The IFD entries container to read the image format information for current frame.</param>
        public static void VerifyAndParse(this TiffDecoderCore options, ExifProfile exifProfile, TiffFrameMetadata frameMetadata)
        {
            if (exifProfile.GetValueInternal(ExifTag.TileOffsets) is not null || exifProfile.GetValueInternal(ExifTag.TileByteCounts) is not null)
            {
                TiffThrowHelper.ThrowNotSupported("Tiled images are not supported.");
            }

            if (exifProfile.GetValueInternal(ExifTag.ExtraSamples) is not null)
            {
                TiffThrowHelper.ThrowNotSupported("ExtraSamples is not supported.");
            }

            TiffFillOrder fillOrder = (TiffFillOrder?)exifProfile.GetValue(ExifTag.FillOrder)?.Value ?? TiffFillOrder.MostSignificantBitFirst;

            if (fillOrder == TiffFillOrder.LeastSignificantBitFirst && frameMetadata.BitsPerPixel != TiffBitsPerPixel.Bit1)
            {
                TiffThrowHelper.ThrowNotSupported("The lower-order bits of the byte FillOrder is only supported in combination with 1bit per pixel bicolor tiff's.");
            }

            if (frameMetadata.Predictor == TiffPredictor.FloatingPoint)
            {
                TiffThrowHelper.ThrowNotSupported("TIFF images with FloatingPoint horizontal predictor are not supported.");
            }

            TiffSampleFormat[] sampleFormats = exifProfile.GetValue(ExifTag.SampleFormat)?.Value?.Select(a => (TiffSampleFormat)a).ToArray();
            TiffSampleFormat?  sampleFormat  = null;

            if (sampleFormats != null)
            {
                sampleFormat = sampleFormats[0];
                foreach (TiffSampleFormat format in sampleFormats)
                {
                    if (format != TiffSampleFormat.UnsignedInteger && format != TiffSampleFormat.Float)
                    {
                        TiffThrowHelper.ThrowNotSupported("ImageSharp only supports the UnsignedInteger and Float SampleFormat.");
                    }
                }
            }

            ushort[] ycbcrSubSampling = exifProfile.GetValue(ExifTag.YCbCrSubsampling)?.Value;
            if (ycbcrSubSampling != null && ycbcrSubSampling.Length != 2)
            {
                TiffThrowHelper.ThrowImageFormatException("Invalid YCbCrSubsampling, expected 2 values.");
            }

            if (ycbcrSubSampling != null && ycbcrSubSampling[1] > ycbcrSubSampling[0])
            {
                TiffThrowHelper.ThrowImageFormatException("ChromaSubsampleVert shall always be less than or equal to ChromaSubsampleHoriz.");
            }

            if (exifProfile.GetValue(ExifTag.StripRowCounts)?.Value != null)
            {
                TiffThrowHelper.ThrowNotSupported("Variable-sized strips are not supported.");
            }

            VerifyRequiredFieldsArePresent(exifProfile, frameMetadata);

            options.PlanarConfiguration       = (TiffPlanarConfiguration?)exifProfile.GetValue(ExifTag.PlanarConfiguration)?.Value ?? DefaultPlanarConfiguration;
            options.Predictor                 = frameMetadata.Predictor ?? TiffPredictor.None;
            options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffPhotometricInterpretation.Rgb;
            options.SampleFormat              = sampleFormat ?? TiffSampleFormat.UnsignedInteger;
            options.BitsPerPixel              = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffBitsPerPixel.Bit24;
            options.BitsPerSample             = frameMetadata.BitsPerSample ?? new TiffBitsPerSample(0, 0, 0);
            options.ReferenceBlackAndWhite    = exifProfile.GetValue(ExifTag.ReferenceBlackWhite)?.Value;
            options.YcbcrCoefficients         = exifProfile.GetValue(ExifTag.YCbCrCoefficients)?.Value;
            options.YcbcrSubSampling          = exifProfile.GetValue(ExifTag.YCbCrSubsampling)?.Value;
            options.FillOrder                 = fillOrder;
            options.JpegTables                = exifProfile.GetValue(ExifTag.JPEGTables)?.Value;

            options.ParseColorType(exifProfile);
            options.ParseCompression(frameMetadata.Compression, exifProfile);
        }