public async Task TestChunkyData(int width, int height, ushort horizontalSubsampling, ushort verticalSubsampling, byte[] subsampled, byte[] original) { var middleware = new TiffApplyChromaSubsamplingMiddleware <byte>(horizontalSubsampling, verticalSubsampling); byte[] buffer = new byte[original.Length]; original.AsSpan().CopyTo(buffer); var context = new TestEncoderContext <byte> { MemoryPool = MemoryPool <byte> .Shared, BitsPerSample = TiffValueCollection.UnsafeWrap(new ushort[] { 8, 8, 8 }), UncompressedData = buffer, ImageSize = new TiffSize(width, height) }; await middleware.InvokeAsync(context, new ValidationPipelineNode <byte>(subsampled)); }
/// <summary> /// Build the <see cref="TiffImageEncoder{TPixel}"/> instance with the specified pixel format of input image. /// </summary> /// <typeparam name="TPixel">The pixel type of the input image.</typeparam> /// <returns>The <see cref="TiffImageEncoder{TPixel}"/> instance.</returns> public TiffImageEncoder <TPixel> Build <TPixel>() where TPixel : unmanaged { var pipelineBuilder = new TiffImageEncoderPipelineBuilder <TPixel>(); bool useHorizontalDifferencingPredictor = Predictor == TiffPredictor.HorizontalDifferencing; switch (PhotometricInterpretation) { case TiffPhotometricInterpretation.WhiteIsZero: pipelineBuilder.Add(new WhiteIsZero8Encoder <TPixel>()); break; case TiffPhotometricInterpretation.BlackIsZero: pipelineBuilder.Add(new BlackIsZero8Encoder <TPixel>()); break; case TiffPhotometricInterpretation.RGB: if (EnableTransparencyForRgb) { pipelineBuilder.Add(new Rgba32Encoder <TPixel>()); } else { pipelineBuilder.Add(new Rgb24Encoder <TPixel>()); } break; case TiffPhotometricInterpretation.TransparencyMask: pipelineBuilder.Add(new TransparencyMaskEncoder <TPixel>(threshold: 127)); break; case TiffPhotometricInterpretation.Seperated: pipelineBuilder.Add(new Cmyk32Encoder <TPixel>()); break; case TiffPhotometricInterpretation.YCbCr: pipelineBuilder.Add(new YCbCr24Encoder <TPixel>()); break; default: throw new NotSupportedException("The selected photometric interpretation is not supported."); } if (useHorizontalDifferencingPredictor) { pipelineBuilder.Add(new TiffApplyPredictorMiddleware <TPixel>(TiffPredictor.HorizontalDifferencing)); } int horizontalSubsampling = HorizontalChromaSubSampling; int verticalSubsampling = VerticalChromaSubSampling; if (PhotometricInterpretation == TiffPhotometricInterpretation.YCbCr) { horizontalSubsampling = horizontalSubsampling == 0 ? 1 : horizontalSubsampling; verticalSubsampling = verticalSubsampling == 0 ? 1 : verticalSubsampling; if (horizontalSubsampling != 1 && horizontalSubsampling != 2 && horizontalSubsampling != 4) { throw new InvalidOperationException("HorizontalChromaSubSampling can only be 1, 2, or 4."); } if (verticalSubsampling != 1 && verticalSubsampling != 2 && verticalSubsampling != 4) { throw new InvalidOperationException("VerticalChromaSubSampling can only be 1, 2, or 4."); } var chromaSubsamplingMiddleware = new TiffApplyChromaSubsamplingMiddleware <TPixel>(horizontalSubsampling, verticalSubsampling); if (Compression != TiffCompression.Jpeg && (horizontalSubsampling > 1 || verticalSubsampling > 1)) { pipelineBuilder.Add(chromaSubsamplingMiddleware); } pipelineBuilder.Add(chromaSubsamplingMiddleware.GetFieldWriter()); } switch (Compression) { case 0: case TiffCompression.NoCompression: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(TiffCompression.NoCompression, NoneCompressionAlgorithm.Instance)); break; case TiffCompression.ModifiedHuffmanCompression: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, ModifiedHuffmanCompressionAlgorithm.GetSharedInstance(TiffFillOrder.HigherOrderBitsFirst))); break; case TiffCompression.T4Encoding: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, CcittGroup3OneDimensionalCompressionAlgorithm.GetSharedInstance(TiffFillOrder.HigherOrderBitsFirst))); break; case TiffCompression.T6Encoding: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, CcittGroup4Compression.GetSharedInstance(TiffFillOrder.HigherOrderBitsFirst))); break; case TiffCompression.Lzw: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, LzwCompressionAlgorithm.Instance)); break; case TiffCompression.Deflate: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, DeflateCompressionLevel == TiffDeflateCompressionLevel.Default ? DeflateCompressionAlgorithm.Instance : new DeflateCompressionAlgorithm(DeflateCompressionLevel))); break; case TiffCompression.Jpeg: TiffJpegEncodingOptions jpegOptions = JpegOptions ?? TiffJpegEncodingOptions.Default; if ((uint)jpegOptions.Quality > 100) { throw new InvalidOperationException("JpegQuality should be set between 0 and 100."); } var jpegCompressionAlgorithm = new JpegCompressionAlgorithm(PhotometricInterpretation, horizontalSubsampling, verticalSubsampling, jpegOptions); pipelineBuilder.Add(jpegCompressionAlgorithm.GetTableWriter <TPixel>()); pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, jpegCompressionAlgorithm)); break; case TiffCompression.PackBits: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, PackBitsCompressionAlgorithm.Instance)); break; case TiffCompression.ThunderScan: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, ThunderScanCompressionAlgorithm.Instance)); break; case TiffCompression.NeXT: pipelineBuilder.Add(new TiffImageCompressionMiddleware <TPixel>(Compression, NeXTCompressionAlgorithm.Instance)); break; case TiffCompression.OldDeflate: throw new NotSupportedException("Legacy Deflate compression is not supported. Use TiffCompression.Deflate instead."); case TiffCompression.OldJpeg: throw new NotSupportedException("Legacy JPEG compression is not supported. Use TiffCompression.Jpeg instead."); default: throw new NotSupportedException("The selected compression algorithm is not supported."); } ITiffImageEncoderPipelineNode <TPixel> imageEncoder = pipelineBuilder.Build(); if (IsTiled) { pipelineBuilder.InsertFirst(new TiffImageEncoderPaddingMiddleware <TPixel>(TileSize)); pipelineBuilder.InsertFirst(new TiffTiledImageEncoderEnumeratorMiddleware <TPixel>(TileSize)); } else { pipelineBuilder.InsertFirst(new TiffStrippedImageEncoderEnumeratorMiddleware <TPixel>(RowsPerStrip)); } if (MaxDegreeOfParallelism > 1) { pipelineBuilder.InsertFirst(new TiffParallelStarterMiddleware <TPixel>(MaxDegreeOfParallelism)); } ITiffImageEncoderPipelineNode <TPixel> ifdEncoder = pipelineBuilder.Build(); if (Orientation != 0) { imageEncoder = PrependOrientationMiddleware(imageEncoder); ifdEncoder = PrependOrientationMiddleware(ifdEncoder); } return(new TiffImageEncoderPipelineAdapter <TPixel>(MemoryPool, imageEncoder, ifdEncoder)); }