protected static void TestTiffEncoderCore <TPixel>(
            TestImageProvider <TPixel> provider,
            TiffBitsPerPixel?bitsPerPixel,
            TiffPhotometricInterpretation photometricInterpretation,
            TiffCompression compression = TiffCompression.None,
            TiffPredictor predictor     = TiffPredictor.None,
            bool useExactComparer       = true,
            float compareTolerance      = 0.001f,
            IImageDecoder imageDecoder  = null)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            using Image <TPixel> image = provider.GetImage();
            var encoder = new TiffEncoder
            {
                PhotometricInterpretation = photometricInterpretation,
                BitsPerPixel        = bitsPerPixel,
                Compression         = compression,
                HorizontalPredictor = predictor
            };

            // Does DebugSave & load reference CompareToReferenceInput():
            image.VerifyEncoder(
                provider,
                "tiff",
                bitsPerPixel,
                encoder,
                useExactComparer ? ImageComparer.Exact : ImageComparer.Tolerant(compareTolerance),
                referenceDecoder: imageDecoder ?? ReferenceDecoder);
        }
        public static TiffBaseDecompressor Create(
            Configuration configuration,
            TiffDecoderCompressionType method,
            MemoryAllocator allocator,
            TiffPhotometricInterpretation photometricInterpretation,
            int width,
            int bitsPerPixel,
            TiffColorType colorType,
            TiffPredictor predictor,
            FaxCompressionOptions faxOptions,
            byte[] jpegTables,
            TiffFillOrder fillOrder,
            ByteOrder byteOrder)
        {
            switch (method)
            {
            case TiffDecoderCompressionType.None:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
                return(new NoneTiffCompression(allocator, width, bitsPerPixel));

            case TiffDecoderCompressionType.PackBits:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
                return(new PackBitsTiffCompression(allocator, width, bitsPerPixel));

            case TiffDecoderCompressionType.Deflate:
                DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
                return(new DeflateTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian));

            case TiffDecoderCompressionType.Lzw:
                DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
                return(new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian));

            case TiffDecoderCompressionType.T4:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new T4TiffCompression(allocator, fillOrder, width, bitsPerPixel, faxOptions, photometricInterpretation));

            case TiffDecoderCompressionType.T6:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new T6TiffCompression(allocator, fillOrder, width, bitsPerPixel, photometricInterpretation));

            case TiffDecoderCompressionType.HuffmanRle:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new ModifiedHuffmanTiffCompression(allocator, fillOrder, width, bitsPerPixel, photometricInterpretation));

            case TiffDecoderCompressionType.Jpeg:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new JpegTiffCompression(configuration, allocator, width, bitsPerPixel, jpegTables, photometricInterpretation));

            default:
                throw TiffThrowHelper.NotSupportedDecompressor(nameof(method));
            }
        }
Example #3
0
        public void TiffCore()
        {
            TiffPhotometricInterpretation photometricInterpretation = TiffPhotometricInterpretation.Rgb;

            var encoder = new TiffEncoder()
            {
                Compression = this.Compression, PhotometricInterpretation = photometricInterpretation
            };

            using var memoryStream = new MemoryStream();
            this.core.SaveAsTiff(memoryStream, encoder);
        }
        /// <summary>
        /// Initialize the middleware.
        /// </summary>
        /// <param name="photometricInterpretation">The photometric interpretation of the image.</param>
        /// <param name="bitsPerSample">Bits per sample.</param>
        /// <param name="bytesPerScanlines">Byte count per scanline.</param>
        /// <param name="decompressionAlgorithm">The decompression algorithm.</param>
        public TiffImageDecompressionMiddleware(TiffPhotometricInterpretation photometricInterpretation, TiffValueCollection <ushort> bitsPerSample, TiffValueCollection <int> bytesPerScanlines, ITiffDecompressionAlgorithm decompressionAlgorithm)
        {
            if (bytesPerScanlines.IsEmpty)
            {
                throw new ArgumentException("BytesPerScanlines not specified.");
            }

            _photometricInterpretation = photometricInterpretation;
            _bitsPerSample             = bitsPerSample;
            _bytesPerScanlines         = bytesPerScanlines;
            _decompressionAlgorithm    = decompressionAlgorithm;
        }
Example #5
0
        /// <summary>
        /// Computes the image file directory of a geometry.
        /// </summary>
        /// <param name="geometry">The geometry.</param>
        /// <param name="compression">The compression.</param>
        /// <param name="format">The sample format.</param>
        /// <param name="startPosition">The starting position of the raster content within the stream.</param>
        /// <param name="endPosition">The ending position of the raster content within the stream.</param>
        /// <returns>The computed image file directory.</returns>
        protected virtual TiffImageFileDirectory ComputeImageFileDirectory(ISpectralGeometry geometry, TiffCompression compression, TiffSampleFormat format)
        {
            TiffImageFileDirectory imageFileDirectory = new TiffImageFileDirectory();

            // compute photometric interpretation
            TiffPhotometricInterpretation photometricInterpretation = ComputePhotometricInterpretation(geometry);

            // add raster properties
            AddImageTag(imageFileDirectory, TiffTag.PhotometricInterpretation, (UInt16)photometricInterpretation);
            AddImageTag(imageFileDirectory, TiffTag.Compression, (UInt16)compression);
            AddImageTag(imageFileDirectory, TiffTag.ImageLength, (UInt32)geometry.Raster.NumberOfRows);
            AddImageTag(imageFileDirectory, TiffTag.ImageWidth, (UInt32)geometry.Raster.NumberOfColumns);
            AddImageTag(imageFileDirectory, TiffTag.ResolutionUnit, (UInt16)2);
            AddImageTag(imageFileDirectory, TiffTag.XResolution, (geometry.Raster.Mapper != null) ? (Rational)geometry.Raster.Mapper.ColumnSize : (Rational)1);
            AddImageTag(imageFileDirectory, TiffTag.YResolution, (geometry.Raster.Mapper != null) ? (Rational)geometry.Raster.Mapper.RowSize : (Rational)1);
            AddImageTag(imageFileDirectory, TiffTag.RowsPerStrip, (UInt32)geometry.Raster.NumberOfRows);
            AddImageTag(imageFileDirectory, TiffTag.StripOffsets, (UInt32)0);
            AddImageTag(imageFileDirectory, TiffTag.StripByteCounts, (UInt32)0);
            AddImageTag(imageFileDirectory, TiffTag.BitsPerSample, Enumerable.Repeat((UInt16)geometry.Raster.RadiometricResolution, geometry.Raster.NumberOfBands).Cast <Object>().ToArray());
            AddImageTag(imageFileDirectory, TiffTag.SamplesPerPixel, (UInt32)geometry.Raster.NumberOfBands);
            AddImageTag(imageFileDirectory, TiffTag.SampleFormat, (UInt16)format);

            // add color palette
            if (photometricInterpretation == TiffPhotometricInterpretation.PaletteColor)
            {
                imageFileDirectory.Add(TiffTag.ColorMap, ComputeColorMap(geometry));
            }

            // add metadata
            AddImageTag(imageFileDirectory, TiffTag.DocumentName, geometry.Metadata, "GeoTIFF::DocumentName");
            AddImageTag(imageFileDirectory, TiffTag.ImageDescription, geometry.Metadata, "GeoTIFF::ImageDescription");
            AddImageTag(imageFileDirectory, TiffTag.DocumentName, geometry.Metadata, "GeoTIFF::Make");
            AddImageTag(imageFileDirectory, TiffTag.Make, geometry.Metadata, "GeoTIFF::DocumentName");
            AddImageTag(imageFileDirectory, TiffTag.Model, geometry.Metadata, "GeoTIFF::Model");
            AddImageTag(imageFileDirectory, TiffTag.PageName, geometry.Metadata, "GeoTIFF::PageName");
            AddImageTag(imageFileDirectory, TiffTag.Artist, geometry.Metadata, "GeoTIFF::Artist");
            AddImageTag(imageFileDirectory, TiffTag.HostComputer, geometry.Metadata, "GeoTIFF::HostComputer");
            AddImageTag(imageFileDirectory, TiffTag.Copyright, geometry.Metadata, "GeoTIFF::Copyright");
            AddImageTag(imageFileDirectory, TiffTag.Software, "AEGIS Geospatial Framework");
            AddImageTag(imageFileDirectory, TiffTag.DateTime, DateTime.Now.ToString(CultureInfo.InvariantCulture.DateTimeFormat));

            Dictionary <String, Object> attributes = geometry.Metadata.Where(attribute => !attribute.Key.Contains("GeoTIFF")).ToDictionary(attribute => attribute.Key, attribute => attribute.Value);

            if (geometry.Metadata.Count(attribute => !attribute.Key.Contains("GeoTIFF")) > 0)
            {
                imageFileDirectory.Add(TiffTag.AegisAttributes, new Object[] { JsonConvert.SerializeObject(attributes, Formatting.None, new JsonSerializerSettings {
                        TypeNameHandling = TypeNameHandling.All
                    }) });
            }

            return(imageFileDirectory);
        }
        public static bool SupportsPhotometricInterpretation(TiffPhotometricInterpretation photometricInterpretation)
        {
            switch (photometricInterpretation)
            {
            case TiffPhotometricInterpretation.WhiteIsZero:
            case TiffPhotometricInterpretation.BlackIsZero:
            case TiffPhotometricInterpretation.Rgb:
                return(true);

            default:
                return(false);
            }
        }
Example #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="JpegTiffCompression"/> class.
 /// </summary>
 /// <param name="configuration">The configuration.</param>
 /// <param name="memoryAllocator">The memoryAllocator to use for buffer allocations.</param>
 /// <param name="width">The image width.</param>
 /// <param name="bitsPerPixel">The bits per pixel.</param>
 /// <param name="jpegTables">The JPEG tables containing the quantization and/or Huffman tables.</param>
 /// <param name="photometricInterpretation">The photometric interpretation.</param>
 public JpegTiffCompression(
     Configuration configuration,
     MemoryAllocator memoryAllocator,
     int width,
     int bitsPerPixel,
     byte[] jpegTables,
     TiffPhotometricInterpretation photometricInterpretation)
     : base(memoryAllocator, width, bitsPerPixel)
 {
     this.configuration             = configuration;
     this.jpegTables                = jpegTables;
     this.photometricInterpretation = photometricInterpretation;
 }
Example #8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="T6TiffCompression" /> class.
 /// </summary>
 /// <param name="allocator">The memory allocator.</param>
 /// <param name="fillOrder">The logical order of bits within a byte.</param>
 /// <param name="width">The image width.</param>
 /// <param name="bitsPerPixel">The number of bits per pixel.</param>
 /// <param name="photometricInterpretation">The photometric interpretation.</param>
 public T6TiffCompression(
     MemoryAllocator allocator,
     TiffFillOrder fillOrder,
     int width,
     int bitsPerPixel,
     TiffPhotometricInterpretation photometricInterpretation)
     : base(allocator, width, bitsPerPixel)
 {
     this.FillOrder   = fillOrder;
     this.width       = width;
     this.isWhiteZero = photometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero;
     this.whiteValue  = (byte)(this.isWhiteZero ? 0 : 1);
     this.blackValue  = (byte)(this.isWhiteZero ? 1 : 0);
 }
 /// <summary>
 /// Initialize the object.
 /// </summary>
 /// <param name="photometricInterpretation">The expected photometric interpretation.</param>
 /// <param name="quality">The quality factor to use when generating quantization table.</param>
 public JpegCompressionAlgorithm(TiffPhotometricInterpretation photometricInterpretation, int quality)
 {
     if ((uint)quality > 100)
     {
         throw new ArgumentOutOfRangeException(nameof(quality));
     }
     _photometricInterpretation   = photometricInterpretation;
     _horizontalSubsampling       = 1;
     _verticalSubsampling         = 1;
     _useSharedHuffmanTables      = false;
     _useSharedQuantizationTables = false;
     _optimizeCoding = false;
     Initialize(quality, false);
 }
 /// <summary>
 /// Initialize the object.
 /// </summary>
 /// <param name="photometricInterpretation">The expected photometric interpretation.</param>
 /// <param name="horizontalSubsampling">The horizontal subsampling factor for YCbCr image.</param>
 /// <param name="verticalSubsampling">The vertical subsampling factor for YCbCr image.</param>
 /// <param name="options">Options to use when encoding with JPEG compression.</param>
 public JpegCompressionAlgorithm(TiffPhotometricInterpretation photometricInterpretation, int horizontalSubsampling, int verticalSubsampling, TiffJpegEncodingOptions?options)
 {
     options = options ?? TiffJpegEncodingOptions.Default;
     if ((uint)options.Quality > 100)
     {
         throw new ArgumentException("Quality should be between 0 and 100.");
     }
     _photometricInterpretation   = photometricInterpretation;
     _horizontalSubsampling       = horizontalSubsampling;
     _verticalSubsampling         = verticalSubsampling;
     _useSharedHuffmanTables      = options.UseSharedHuffmanTables && !options.OptimizeCoding;
     _useSharedQuantizationTables = options.UseSharedQuantizationTables;
     _optimizeCoding = options.OptimizeCoding;
     Initialize(options.Quality, options.OptimizeCoding);
 }
Example #11
0
        public void TiffCore()
        {
            TiffPhotometricInterpretation photometricInterpretation = TiffPhotometricInterpretation.Rgb;

            // Workaround for 1-bit bug
            if (this.Compression == TiffCompression.CcittGroup3Fax || this.Compression == TiffCompression.Ccitt1D)
            {
                photometricInterpretation = TiffPhotometricInterpretation.WhiteIsZero;
            }

            var encoder = new TiffEncoder()
            {
                Compression = this.Compression, PhotometricInterpretation = photometricInterpretation
            };

            using var memoryStream = new MemoryStream();
            this.core.SaveAsTiff(memoryStream, encoder);
        }
        public void SupportsPhotometricInterpretation_ReturnsCorrectValue(TiffPhotometricInterpretation photometricInterpretation, bool expectedResult)
        {
            var supported = TiffImageReader.SupportsPhotometricInterpretation(photometricInterpretation);

            Assert.Equal(expectedResult, supported);
        }
        protected static void TestStripLength <TPixel>(
            TestImageProvider <TPixel> provider,
            TiffPhotometricInterpretation photometricInterpretation,
            TiffCompression compression,
            bool useExactComparer  = true,
            float compareTolerance = 0.01f)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            // arrange
            var tiffEncoder = new TiffEncoder()
            {
                PhotometricInterpretation = photometricInterpretation, Compression = compression
            };

            using Image <TPixel> input = provider.GetImage();
            using var memStream = new MemoryStream();
            TiffFrameMetadata inputMeta        = input.Frames.RootFrame.Metadata.GetTiffMetadata();
            TiffCompression   inputCompression = inputMeta.Compression ?? TiffCompression.None;

            // act
            input.Save(memStream, tiffEncoder);

            // assert
            memStream.Position = 0;
            using var output   = Image.Load <Rgba32>(memStream);
            ExifProfile         exifProfileOutput = output.Frames.RootFrame.Metadata.ExifProfile;
            TiffFrameMetadata   outputMeta        = output.Frames.RootFrame.Metadata.GetTiffMetadata();
            ImageFrame <Rgba32> rootFrame         = output.Frames.RootFrame;

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

            Assert.True(output.Height > (int)rowsPerStrip);
            Assert.True(exifProfileOutput.GetValue(ExifTag.StripOffsets)?.Value.Length > 1);
            Number[] stripByteCounts = exifProfileOutput.GetValue(ExifTag.StripByteCounts)?.Value;
            Assert.NotNull(stripByteCounts);
            Assert.True(stripByteCounts.Length > 1);
            Assert.NotNull(outputMeta.BitsPerPixel);

            foreach (Number sz in stripByteCounts)
            {
                Assert.True((uint)sz <= TiffConstants.DefaultStripSize);
            }

            // For uncompressed more accurate test.
            if (compression == TiffCompression.None)
            {
                for (int i = 0; i < stripByteCounts.Length - 1; i++)
                {
                    // The difference must be less than one row.
                    int stripBytes = (int)stripByteCounts[i];
                    int widthBytes = ((int)outputMeta.BitsPerPixel + 7) / 8 * rootFrame.Width;

                    Assert.True((TiffConstants.DefaultStripSize - stripBytes) < widthBytes);
                }
            }

            // Compare with reference.
            TestTiffEncoderCore(
                provider,
                inputMeta.BitsPerPixel,
                photometricInterpretation,
                inputCompression,
                useExactComparer: useExactComparer,
                compareTolerance: compareTolerance);
        }
Example #14
0
        public static async Task <int> Wrap(FileInfo source, FileInfo output, CancellationToken cancellationToken)
        {
            if (source is null || !source.Exists)
            {
                Console.WriteLine(source is null ? "Input JPEG image is not specified." : "File not found: " + source.FullName);
                return(1);
            }
            if (output is null)
            {
                Console.WriteLine("Output TIFF file is not specified.");
                return(1);
            }

            byte[] jpegFile = await File.ReadAllBytesAsync(source.FullName, cancellationToken);

            var decoder = new JpegDecoder();

            decoder.SetInput(jpegFile);
            decoder.Identify(loadQuantizationTables: false);

            ushort[] bitsPerSample = new ushort[decoder.NumberOfComponents];
            ushort   bits          = (ushort)decoder.Precision;

            for (int i = 0; i < bitsPerSample.Length; i++)
            {
                bitsPerSample[i] = bits;
            }
            TiffPhotometricInterpretation photometricInterpretation =
                bitsPerSample.Length == 1 ? TiffPhotometricInterpretation.BlackIsZero :
                bitsPerSample.Length == 3 ? TiffPhotometricInterpretation.YCbCr :
                throw new InvalidDataException("Photometric interpretation not supported.");

            using (TiffFileWriter writer = await TiffFileWriter.OpenAsync(output.FullName, useBigTiff: false))
            {
                TiffStreamOffset imageOffset = await writer.WriteAlignedBytesAsync(jpegFile);

                TiffStreamOffset ifdOffset;
                using (TiffImageFileDirectoryWriter ifdWriter = writer.CreateImageFileDirectory())
                {
                    await ifdWriter.WriteTagAsync(TiffTag.ImageWidth, TiffValueCollection.Single((ushort)decoder.Width));

                    await ifdWriter.WriteTagAsync(TiffTag.ImageLength, TiffValueCollection.Single((ushort)decoder.Height));

                    await ifdWriter.WriteTagAsync(TiffTag.BitsPerSample, TiffValueCollection.UnsafeWrap(bitsPerSample));

                    await ifdWriter.WriteTagAsync(TiffTag.Compression, TiffValueCollection.Single((ushort)TiffCompression.Jpeg));

                    await ifdWriter.WriteTagAsync(TiffTag.PhotometricInterpretation, TiffValueCollection.Single((ushort)photometricInterpretation));

                    await ifdWriter.WriteTagAsync(TiffTag.SamplesPerPixel, TiffValueCollection.Single((ushort)bitsPerSample.Length));

                    await ifdWriter.WriteTagAsync(TiffTag.PlanarConfiguration, TiffValueCollection.Single((ushort)TiffPlanarConfiguration.Chunky));

                    await ifdWriter.WriteTagAsync(TiffTag.RowsPerStrip, TiffValueCollection.Single((ushort)decoder.Height));

                    await ifdWriter.WriteTagAsync(TiffTag.StripOffsets, TiffValueCollection.Single((uint)imageOffset.Offset));

                    await ifdWriter.WriteTagAsync(TiffTag.StripByteCounts, TiffValueCollection.Single((uint)jpegFile.Length));

                    if (photometricInterpretation == TiffPhotometricInterpretation.YCbCr)
                    {
                        int maxHorizontalSampling   = decoder.GetMaximumHorizontalSampling();
                        int maxVerticalSampling     = decoder.GetMaximumVerticalSampling();
                        int yHorizontalSubSampling  = maxHorizontalSampling / decoder.GetHorizontalSampling(0);
                        int yVerticalSubSampling    = maxVerticalSampling / decoder.GetVerticalSampling(0);
                        int cbHorizontalSubSampling = maxHorizontalSampling / decoder.GetHorizontalSampling(1) / yHorizontalSubSampling;
                        int cbVerticalSubSampling   = maxVerticalSampling / decoder.GetVerticalSampling(1) / yVerticalSubSampling;
                        int crHorizontalSubSampling = maxHorizontalSampling / decoder.GetHorizontalSampling(2) / yHorizontalSubSampling;
                        int crVerticalSubSampling   = maxVerticalSampling / decoder.GetVerticalSampling(2) / yVerticalSubSampling;

                        if (cbHorizontalSubSampling != crHorizontalSubSampling || cbVerticalSubSampling != crVerticalSubSampling)
                        {
                            throw new InvalidDataException("Unsupported JPEG image.");
                        }

                        await ifdWriter.WriteTagAsync(TiffTag.YCbCrSubSampling, TiffValueCollection.UnsafeWrap(new ushort[] { (ushort)cbHorizontalSubSampling, (ushort)cbVerticalSubSampling }));
                    }

                    // Write other properties here (eg, XResolution, YResolution)
                    await ifdWriter.WriteTagAsync(TiffTag.XResolution, TiffValueCollection.Single(new TiffRational(96, 1)));

                    await ifdWriter.WriteTagAsync(TiffTag.YResolution, TiffValueCollection.Single(new TiffRational(96, 1)));

                    await ifdWriter.WriteTagAsync(TiffTag.ResolutionUnit, TiffValueCollection.Single((ushort)TiffResolutionUnit.Inch));

                    ifdOffset = await ifdWriter.FlushAsync();
                }

                writer.SetFirstImageFileDirectoryOffset(ifdOffset);
                await writer.FlushAsync();
            }

            return(0);
        }
        public void TiffEncode_WorksWithDiscontiguousBuffers <TPixel>(TestImageProvider <TPixel> provider, TiffPhotometricInterpretation photometricInterpretation)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            provider.LimitAllocatorBufferCapacity().InPixelsSqrt(200);
            using Image <TPixel> image = provider.GetImage();

            var encoder = new TiffEncoder {
                PhotometricInterpretation = photometricInterpretation
            };

            image.DebugSave(provider, encoder);
        }
 public void TiffEncoder_StripLength_OutOfBounds <TPixel>(TestImageProvider <TPixel> provider, TiffPhotometricInterpretation photometricInterpretation, TiffCompression compression)
     where TPixel : unmanaged, IPixel <TPixel> =>
 //// CcittGroup3Fax compressed data length can be larger than the original length.
 Assert.Throws <Xunit.Sdk.TrueException>(() => TestStripLength(provider, photometricInterpretation, compression));
 public void TiffEncoder_StripLength_WithPalette <TPixel>(TestImageProvider <TPixel> provider, TiffPhotometricInterpretation photometricInterpretation, TiffCompression compression)
     where TPixel : unmanaged, IPixel <TPixel> =>
 TestStripLength(provider, photometricInterpretation, compression, false, 0.01f);