public void Test(string reference, string test) { using var refImage = Image.Load <Rgb24>(reference); using var tiff = TiffFileReader.Open(test); TiffStreamOffset ifdOffset = tiff.FirstImageFileDirectoryOffset; while (!ifdOffset.IsZero) { TiffImageFileDirectory ifd = tiff.ReadImageFileDirectory(ifdOffset); TiffImageDecoder decoder = tiff.CreateImageDecoder(ifd, new TiffImageDecoderOptions { UndoColorPreMultiplying = true }); Assert.Equal(refImage.Width, decoder.Width); Assert.Equal(refImage.Height, decoder.Height); TiffRgb24[] pixels = new TiffRgb24[decoder.Width * decoder.Height]; decoder.Decode(TiffPixelBuffer.Wrap(pixels, decoder.Width, decoder.Height)); AssertEqual(refImage, pixels); using (var image = new Image <Rgb24>(decoder.Width, decoder.Height)) { decoder.Decode(image); AssertEqual(refImage, image); } ifdOffset = ifd.NextOffset; } }
public async Task TestAsync(string reference, string test) { using var refImage = Image.Load <L8>(reference); await using TiffFileReader tiff = await TiffFileReader.OpenAsync(test); TiffStreamOffset ifdOffset = tiff.FirstImageFileDirectoryOffset; while (!ifdOffset.IsZero) { TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(ifdOffset); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(ifd, new TiffImageDecoderOptions { UndoColorPreMultiplying = true }); Assert.Equal(refImage.Width, decoder.Width); Assert.Equal(refImage.Height, decoder.Height); TiffGray8[] pixels = new TiffGray8[decoder.Width * decoder.Height]; await decoder.DecodeAsync(TiffPixelBuffer.Wrap(pixels, decoder.Width, decoder.Height)); AssertEqual(refImage, pixels); using (var image = new Image <L8>(decoder.Width, decoder.Height)) { decoder.Decode(image); AssertEqual(refImage, image); } ifdOffset = ifd.NextOffset; } }
/// <summary> /// Adds the specified tag to the Image File Directory. /// </summary> /// <param name="directory">The Image File Directory.</param> /// <param name="tag">The tag.</param> /// <param name="metadata">The geometry metadata.</param> /// <param name="tagName">The name of the tag.</param> protected void AddImageTag(TiffImageFileDirectory directory, UInt16 tag, IDictionary <String, Object> metadata, String tagName) { if (metadata.ContainsKey(tagName)) { directory[tag] = new Object[] { metadata[tagName] }; metadata.Remove(tagName); } }
public async Task TestDoubleCompatibility(int length, bool bigTiff) { double[] refData = new double[length]; var rand = new Random(); for (int i = 0; i < refData.Length; i++) { refData[i] = rand.NextDouble(); } using Stream stream = await GenerateTiffAsync(bigTiff, async ifd => { await ifd.WriteTagAsync((TiffTag) 0x1234, TiffValueCollection.UnsafeWrap(refData)); }); await using (TiffFileReader reader = await TiffFileReader.OpenAsync(stream, leaveOpen: true)) { TiffImageFileDirectory ifd = await reader.ReadImageFileDirectoryAsync(); TiffFieldReader fieldReader = await reader.CreateFieldReaderAsync(); TiffImageFileDirectoryEntry entry = ifd.FindEntry((TiffTag)0x1234); Assert.Equal((TiffTag)0x1234, entry.Tag); // Byte await TestInvalidConversionAsync <byte>(fieldReader, entry, nameof(fieldReader.ReadByteFieldAsync), refData.Length); // SSbyte await TestInvalidConversionAsync <sbyte>(fieldReader, entry, nameof(fieldReader.ReadSByteFieldAsync), refData.Length); // Short await TestInvalidConversionAsync <ushort>(fieldReader, entry, nameof(fieldReader.ReadShortFieldAsync), refData.Length); // SShort await TestInvalidConversionAsync <short>(fieldReader, entry, nameof(fieldReader.ReadSShortFieldAsync), refData.Length); // Long await TestInvalidConversionAsync <uint>(fieldReader, entry, nameof(fieldReader.ReadLongFieldAsync), refData.Length); // SLong await TestInvalidConversionAsync <int>(fieldReader, entry, nameof(fieldReader.ReadSLongFieldAsync), refData.Length); // Float await TestInvalidConversionAsync <float>(fieldReader, entry, nameof(fieldReader.ReadFloatFieldAsync), refData.Length); // Double await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadDoubleFieldAsync), refData); // Rational await TestInvalidConversionAsync <TiffRational>(fieldReader, entry, nameof(fieldReader.ReadRationalFieldAsync), refData.Length); // SRational await TestInvalidConversionAsync <TiffSRational>(fieldReader, entry, nameof(fieldReader.ReadSRationalFieldAsync), refData.Length); } }
/// <summary> /// Writes the geo-key directory into the Image File Directory. /// </summary> /// <param name="imageFileDirectory">The Image File Directory.</param> /// <param name="geoKeyDirectory">The geo-key directory.</param> private void WriteGeoKeyDirectory(TiffImageFileDirectory imageFileDirectory, GeoKeyDirectory geoKeyDirectory) { if (geoKeyDirectory.Count == 0) { return; } Object[] geoKeyDirectoryTag = new Object[(geoKeyDirectory.Count + 1) * 4]; List <Object> geoDoubleParamsTag = new List <Object>(); List <Object> geoAsciiParamsTag = new List <Object>(); // header data (version, revision, count) geoKeyDirectoryTag[0] = (Int16)1; geoKeyDirectoryTag[1] = (Int16)0; geoKeyDirectoryTag[2] = (Int16)0; geoKeyDirectoryTag[3] = (Int16)geoKeyDirectory.Count; // content Int32 byteIndex = 4; foreach (KeyValuePair <Int16, Object> geoData in geoKeyDirectory) { geoKeyDirectoryTag[byteIndex] = geoData.Key; geoKeyDirectoryTag[byteIndex + 1] = (UInt16)0; geoKeyDirectoryTag[byteIndex + 2] = (UInt16)1; if (geoData.Value is Int16) { geoKeyDirectoryTag[byteIndex + 3] = geoData.Value; } if (geoData.Value is Double) { geoDoubleParamsTag.Add(geoData.Value); } if (geoData.Value is String) { geoAsciiParamsTag.Add(geoData.Value); } byteIndex += 4; } imageFileDirectory.Add(TiffTag.GeoKeyDirectoryTag, geoKeyDirectoryTag); if (geoDoubleParamsTag.Count > 0) { imageFileDirectory.Add(TiffTag.GeoDoubleParamsTag, geoDoubleParamsTag.ToArray()); } if (geoAsciiParamsTag.Count > 0) { imageFileDirectory.Add(TiffTag.GeoAsciiParamsTag, geoAsciiParamsTag.ToArray()); } }
/// <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 async Task <int> Merge(FileInfo[] source, FileInfo output, CancellationToken cancellationToken) { if (source is null || source.Length == 0) { Console.WriteLine("Input TIFF file are not specified."); return(1); } if (output is null) { Console.WriteLine("Output TIFF file is not specified"); return(1); } await using TiffFileWriter writer = await TiffFileWriter.OpenAsync(output.FullName); TiffStreamOffset fistIfdOffset = default; TiffStreamOffset previousIfdOffset = default; foreach (FileInfo sourceFile in source) { await using TiffFileReader reader = await TiffFileReader.OpenAsync(sourceFile.FullName); await using TiffFileContentReader contentReader = await reader.CreateContentReaderAsync(); await using TiffFieldReader fieldReader = await reader.CreateFieldReaderAsync(cancellationToken); TiffStreamOffset inputIfdOffset = reader.FirstImageFileDirectoryOffset; while (!inputIfdOffset.IsZero) { TiffImageFileDirectory ifd = await reader.ReadImageFileDirectoryAsync(inputIfdOffset, cancellationToken); using (TiffImageFileDirectoryWriter ifdWriter = writer.CreateImageFileDirectory()) { await CopyIfdAsync(contentReader, fieldReader, ifd, ifdWriter, cancellationToken); previousIfdOffset = await ifdWriter.FlushAsync(previousIfdOffset); if (fistIfdOffset.IsZero) { fistIfdOffset = previousIfdOffset; } } inputIfdOffset = ifd.NextOffset; } } writer.SetFirstImageFileDirectoryOffset(fistIfdOffset); await writer.FlushAsync(); return(0); }
/// <summary> /// Apply the write operation for the specified geometry. /// </summary> /// <param name="geometry">The geometry.</param> /// <exception cref="System.ArgumentException">The number of images in the stream has reached the maximum.</exception> protected override void ApplyWriteGeometry(IGeometry geometry) { if (_imageCount == _maxImageCount) { throw new InvalidOperationException("The number of images in the stream has reached the maximum."); } IRaster raster = (geometry as ISpectralGeometry).Raster; if (raster == null) { return; } // TODO: compute the format more exactly Int64 contentSize = (Int64)raster.RadiometricResolution / 8 * raster.NumberOfBands * raster.NumberOfColumns * raster.NumberOfRows; InitializeStream(contentSize > BigTiffThreshold ? TiffStructure.BigTiff : TiffStructure.RegularTiff); TiffCompression compression = TiffCompression.None; // TODO: support other compressions TiffSampleFormat sampleFormat = (geometry as ISpectralGeometry).Raster.Format == RasterFormat.Floating ? TiffSampleFormat.Floating : TiffSampleFormat.UnsignedInteger; TiffImageFileDirectory imageFileDirectory = ComputeImageFileDirectory(geometry as ISpectralGeometry, compression, sampleFormat); // compute and update raster content position Int64 imageFileDirectorySize = ComputeImageFileDirectorySize(imageFileDirectory); Int64 rasterContentStartPosition = _baseStream.Position + imageFileDirectorySize; Int64 rasterContentSize = ComputeRasterContentSize(raster); // strip offset and length switch (_structure) { case TiffStructure.RegularTiff: imageFileDirectory[TiffTag.StripOffsets][0] = (UInt32)rasterContentStartPosition; imageFileDirectory[TiffTag.StripByteCounts][0] = (UInt32)rasterContentSize; WriteImageFileDirectory(imageFileDirectory); break; case TiffStructure.BigTiff: imageFileDirectory[TiffTag.StripOffsets][0] = (UInt64)rasterContentStartPosition; imageFileDirectory[TiffTag.StripByteCounts][0] = (UInt64)rasterContentSize; WriteBigImageFileDirectory(imageFileDirectory); break; } // perform writing based on representation WriteRasterContentToStrip((geometry as ISpectralGeometry).Raster, compression, sampleFormat); _imageCount++; }
private async Task <IImageInfo> IdentifyCoreAsync(TiffFileContentSource contentSource, CancellationToken cancellationToken) { using TiffFileReader tiff = await TiffFileReader.OpenAsync(contentSource, cancellationToken : cancellationToken).ConfigureAwait(false); TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(cancellationToken).ConfigureAwait(false); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(ifd, _options, cancellationToken).ConfigureAwait(false); return(new ImageInfo() { Width = decoder.Width, Height = decoder.Height }); }
public async Task TestSLongCompatibility(int length, bool bigTiff) { int[] refData = new int[length]; new Random(42).NextBytes(MemoryMarshal.AsBytes(refData.AsSpan())); using Stream stream = await GenerateTiffAsync(bigTiff, async ifd => { await ifd.WriteTagAsync((TiffTag) 0x1234, TiffValueCollection.UnsafeWrap(refData)); }); await using (TiffFileReader reader = await TiffFileReader.OpenAsync(stream, leaveOpen: true)) { TiffImageFileDirectory ifd = await reader.ReadImageFileDirectoryAsync(); TiffFieldReader fieldReader = await reader.CreateFieldReaderAsync(); TiffImageFileDirectoryEntry entry = ifd.FindEntry((TiffTag)0x1234); Assert.Equal((TiffTag)0x1234, entry.Tag); // Byte await TestInvalidConversionAsync <byte>(fieldReader, entry, nameof(fieldReader.ReadByteFieldAsync), refData.Length); // SSbyte await TestInvalidConversionAsync <sbyte>(fieldReader, entry, nameof(fieldReader.ReadSByteFieldAsync), refData.Length); // Short await TestInvalidConversionAsync <ushort>(fieldReader, entry, nameof(fieldReader.ReadShortFieldAsync), refData.Length); // SShort await TestInvalidConversionAsync <short>(fieldReader, entry, nameof(fieldReader.ReadSShortFieldAsync), refData.Length); // Long await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadLongFieldAsync), Array.ConvertAll(refData, v => (uint)v)); // SLong await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadSLongFieldAsync), refData); // Float await TestInvalidConversionAsync <float>(fieldReader, entry, nameof(fieldReader.ReadFloatFieldAsync), refData.Length); // Double await TestInvalidConversionAsync <double>(fieldReader, entry, nameof(fieldReader.ReadDoubleFieldAsync), refData.Length); // Rational await TestInvalidConversionAsync <TiffRational>(fieldReader, entry, nameof(fieldReader.ReadRationalFieldAsync), refData.Length); // SRational await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadSRationalFieldAsync), Array.ConvertAll(refData, v => new TiffSRational(v, 1))); } }
public static async Task <int> Dump(FileInfo file, long?offset, CancellationToken cancellationToken) { await using TiffFileReader tiff = await TiffFileReader.OpenAsync(file.FullName); await using TiffFieldReader fieldReader = await tiff.CreateFieldReaderAsync(cancellationToken); Console.WriteLine("Input File: " + file.FullName); Console.WriteLine($"StandardTIFF: {tiff.IsStandardTiff}, BigTIFF: {tiff.IsBigTiff}, IsLittleEndian: {tiff.IsLittleEndian}"); Console.WriteLine("First IFD: " + tiff.FirstImageFileDirectoryOffset); Console.WriteLine(); int ifdIndex = 0; TiffStreamOffset ifdOffset = offset.HasValue ? new TiffStreamOffset(offset.GetValueOrDefault()) : tiff.FirstImageFileDirectoryOffset; while (!ifdOffset.IsZero) { TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(ifdOffset, cancellationToken); Console.WriteLine($"IFD #{ifdIndex++} (Offset = {ifdOffset})"); Console.WriteLine(" Well-known Tags:"); await DumpWellKnownTagsAsync(fieldReader, ifd, cancellationToken); Console.WriteLine(); Console.WriteLine(" Tags:"); for (int i = 0; i < ifd.Count; i++) { TiffImageFileDirectoryEntry entry = ifd[i]; await DumpIfdEntryAsync(i, fieldReader, entry, cancellationToken); } if (ifd.Count == 0) { Console.WriteLine(" No tags found."); } Console.WriteLine(); Console.WriteLine(); ifdOffset = ifd.NextOffset; } return(0); }
private async Task <Image <TPixel> > DecodeCoreAsync <TPixel>(TiffFileContentSource contentSource, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel <TPixel> { using TiffFileReader tiff = await TiffFileReader.OpenAsync(contentSource, cancellationToken : cancellationToken).ConfigureAwait(false); TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(cancellationToken).ConfigureAwait(false); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(ifd, _options, cancellationToken).ConfigureAwait(false); Image <TPixel>?image = new Image <TPixel>(_configuration, decoder.Width, decoder.Height); try { await decoder.DecodeAsync(image, cancellationToken).ConfigureAwait(false); return(Interlocked.Exchange <Image <TPixel>?>(ref image, null) !); } finally { image?.Dispose(); } }
/// <summary> /// Computes the size of the image file directory. /// </summary> /// <param name="imageFileDirectory">The image file directory.</param> /// <returns>The size of the image file directory (in bytes).</returns> private Int64 ComputeImageFileDirectorySize(TiffImageFileDirectory imageFileDirectory) { Int64 size = (_structure == TiffStructure.BigTiff ? 8 : 2) // number of entries + _imageFileDirectoryEntrySize * imageFileDirectory.Count // entries + _imageFileDirectoryFieldSize; // position of next directory TiffTagType entryType; UInt16 dataSize; Int32 dataCount; foreach (UInt16 entryTag in imageFileDirectory.Keys) { entryType = TiffTag.GetType(imageFileDirectory[entryTag][0]); dataSize = TiffTag.GetSize(entryType); if (entryType == TiffTagType.ASCII) { dataCount = 0; for (Int32 i = 0; i < imageFileDirectory[entryTag].Length; i++) { dataCount += (imageFileDirectory[entryTag][i] as String).Length; } } else { dataCount = imageFileDirectory[entryTag].Length; } if (dataCount * dataSize > _imageFileDirectoryFieldSize) { size += dataCount * dataSize + (dataCount * dataSize) % 2; } } return(size); }
internal async Task <TiffStreamOffset> GenerateReducedResolutionLayerAsync(int layer, TiffStreamOffset ifdOffset, IRipperReducedResolutionGenerationReporter reporter, CancellationToken cancellationToken) { int outputTileSize = _options.OutputTileSize; int outputTileSize2 = 2 * outputTileSize; TiffImageFileDirectory ifd = await _fileReader.ReadImageFileDirectoryAsync(ifdOffset).ConfigureAwait(false); TiffImageDecoder image = await _fileReader.CreateImageDecoderAsync(ifd); int width = image.Width; int height = image.Height; int tiffRowCount = (width / 2 + outputTileSize - 1) / outputTileSize; int tiffColCount = (height / 2 + outputTileSize - 1) / outputTileSize; int index = 0; ulong[] offsets = new ulong[tiffRowCount * tiffColCount]; ulong[] byteCounts = new ulong[tiffRowCount * tiffColCount]; ulong totalByteCount = 0; reporter?.ReportStartReducedResolutionLayerGeneration(layer, offsets.Length, width / 2, height / 2); using (Image <Rgb24> canvas2 = new Image <Rgb24>(_configuration, outputTileSize2, outputTileSize2)) { for (int y = 0; y < height; y += outputTileSize2) { for (int x = 0; x < width; x += outputTileSize2) { cancellationToken.ThrowIfCancellationRequested(); MemoryMarshal.AsBytes(canvas2.GetPixelSpan()).Clear(); await image.DecodeAsync(new TiffPoint(x, y), canvas2).ConfigureAwait(false); using (Image <Rgb24> tile24 = canvas2.Clone(ctx => { ctx.Resize(outputTileSize, outputTileSize); })) { cancellationToken.ThrowIfCancellationRequested(); TiffStreamRegion region = await _encoder.EncodeAsync(_fileWriter, tile24).ConfigureAwait(false); offsets[index] = (ulong)region.Offset.Offset; byteCounts[index] = (uint)region.Length; totalByteCount += (uint)region.Length; index++; reporter?.ReportReducedResolutionLayerGenerationProgress(layer, index, offsets.Length); } } } } cancellationToken.ThrowIfCancellationRequested(); using (TiffImageFileDirectoryWriter ifdWriter = _fileWriter.CreateImageFileDirectory()) { await ifdWriter.WriteTagAsync(TiffTag.NewSubfileType, new TiffValueCollection <ushort>((ushort)TiffNewSubfileType.ReducedResolution)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.PhotometricInterpretation, new TiffValueCollection <ushort>((ushort)TiffPhotometricInterpretation.YCbCr)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.Compression, new TiffValueCollection <ushort>((ushort)TiffCompression.Jpeg)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.SamplesPerPixel, new TiffValueCollection <ushort>((ushort)3)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.TileWidth, new TiffValueCollection <ushort>((ushort)outputTileSize)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.TileLength, new TiffValueCollection <ushort>((ushort)outputTileSize)).ConfigureAwait(false); //ifdWriter.AddTag(TiffTag.ResolutionUnit, (ushort)TiffResolutionUnit.Inch); //await ifdWriter.WriteTagAsync(TiffTag.XResolution, new TiffValueCollection<TiffRational>(new TiffRational(72, 1))); //await ifdWriter.WriteTagAsync(TiffTag.YResolution, new TiffValueCollection<TiffRational>(new TiffRational(72, 1))); await ifdWriter.WriteTagAsync(TiffTag.SampleFormat, new TiffValueCollection <ushort>(new ushort[] { 1, 1, 1 })).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.BitsPerSample, new TiffValueCollection <ushort>(new ushort[] { 8, 8, 8 })).ConfigureAwait(false); if (UseBigTiff) { await ifdWriter.WriteTagAsync(TiffTag.ImageWidth, new TiffValueCollection <ulong>((ulong)(width / 2))).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.ImageLength, new TiffValueCollection <ulong>((ulong)(height / 2))).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.TileOffsets, new TiffValueCollection <ulong>(offsets)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.TileByteCounts, new TiffValueCollection <ulong>(byteCounts)).ConfigureAwait(false); } else { await ifdWriter.WriteTagAsync(TiffTag.ImageWidth, new TiffValueCollection <uint>((uint)(width / 2))).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.ImageLength, new TiffValueCollection <uint>((uint)(height / 2))).ConfigureAwait(false); uint[] tempArr = new uint[offsets.Length]; for (int i = 0; i < tempArr.Length; i++) { tempArr[i] = (uint)offsets[i]; } await ifdWriter.WriteTagAsync(TiffTag.TileOffsets, new TiffValueCollection <uint>(tempArr)).ConfigureAwait(false); for (int i = 0; i < tempArr.Length; i++) { tempArr[i] = (uint)byteCounts[i]; } await ifdWriter.WriteTagAsync(TiffTag.TileByteCounts, new TiffValueCollection <uint>(tempArr)).ConfigureAwait(false); } string software = Software; if (!string.IsNullOrEmpty(software)) { await ifdWriter.WriteTagAsync(TiffTag.Software, new TiffValueCollection <string>(software)); } ifdOffset = await ifdWriter.FlushAsync(ifdOffset).ConfigureAwait(false); } reporter?.ReportCompleteReducedResolutionLayerGeneration(layer, offsets.Length, (long)totalByteCount); return(ifdOffset); }
private static async Task CopyIfdAsync(TiffFileContentReader contentReader, TiffFieldReader fieldReader, TiffImageFileDirectory ifd, TiffImageFileDirectoryWriter dest, CancellationToken cancellationToken) { var tagReader = new TiffTagReader(fieldReader, ifd); foreach (TiffImageFileDirectoryEntry entry in ifd) { // Stripped image data if (entry.Tag == TiffTag.StripOffsets) { await CopyStrippedImageAsync(contentReader, tagReader, dest, cancellationToken); } else if (entry.Tag == TiffTag.StripByteCounts) { // Ignore this } // Tiled image data else if (entry.Tag == TiffTag.TileOffsets) { await CopyTiledImageAsync(contentReader, tagReader, dest, cancellationToken); } else if (entry.Tag == TiffTag.TileByteCounts) { // Ignore this } // Other fields else { await CopyFieldValueAsync(fieldReader, entry, dest, cancellationToken); } } }
/// <summary> /// Adds the specified tag to the Image File Directory. /// </summary> /// <param name="directory">The Image File Directory.</param> /// <param name="tag">The tag.</param> /// <param name="value">The array of values.</param> protected void AddImageTag(TiffImageFileDirectory directory, UInt16 tag, Object[] value) { directory[tag] = value; }
/// <summary> /// Adds the specified tag to the Image File Directory. /// </summary> /// <param name="directory">The Image File Directory.</param> /// <param name="tag">The tag.</param> /// <param name="value">The value.</param> protected void AddImageTag(TiffImageFileDirectory directory, UInt16 tag, Object value) { directory[tag] = new Object[] { value }; }
/// <summary> /// Writes an image file directory to the stream. /// </summary> /// <param name="imageFileDirectory">The image file directory.</param> private void WriteImageFileDirectory(TiffImageFileDirectory imageFileDirectory) { _currentImageFileDirectoryStartPosition = _baseStream.Position; // write starting position _baseStream.Seek(_currentImageFileDirectoryEndPosition, SeekOrigin.Begin); _baseStream.Write(EndianBitConverter.GetBytes((UInt32)_currentImageFileDirectoryStartPosition), 0, _imageFileDirectoryFieldSize); // compute size of directory (without additional fields) Int64 imageFileDirectorySize = 2 + _imageFileDirectoryEntrySize * imageFileDirectory.Count; _currentImageFileDirectoryEndPosition = _currentImageFileDirectoryStartPosition + imageFileDirectorySize; // position after the IFD to write exceeding values _baseStream.Seek(_currentImageFileDirectoryEndPosition + _imageFileDirectoryFieldSize, SeekOrigin.Begin); // the IFD should be written in one operation Byte[] bytes; if (_imageCount == _maxImageCount - 1) { bytes = new Byte[imageFileDirectorySize + _imageFileDirectoryFieldSize]; } else { bytes = new Byte[imageFileDirectorySize]; } EndianBitConverter.CopyBytes((UInt16)imageFileDirectory.Count, bytes, 0); // number of entries Int32 byteIndex = 2; TiffTagType entryType; UInt16 dataSize; Int64 dataCount; foreach (UInt16 entryTag in imageFileDirectory.Keys) { entryType = TiffTag.GetType(imageFileDirectory[entryTag][0]); dataSize = TiffTag.GetSize(entryType); if (entryType == TiffTagType.ASCII) { dataCount = 0; for (Int32 i = 0; i < imageFileDirectory[entryTag].Length; i++) { dataCount += (imageFileDirectory[entryTag][i] as String).Length; } } else { dataCount = imageFileDirectory[entryTag].Length; } EndianBitConverter.CopyBytes(entryTag, bytes, byteIndex); EndianBitConverter.CopyBytes((UInt16)entryType, bytes, byteIndex + 2); EndianBitConverter.CopyBytes((UInt32)dataCount, bytes, byteIndex + 4); // values exceeding he field size (4) must be written to another position Byte[] dataBytes; Int32 dataStartIndex; if (dataCount * dataSize <= 4) { dataBytes = bytes; dataStartIndex = byteIndex + 8; } else { dataBytes = new Byte[dataCount * dataSize + (dataCount * dataSize) % 2]; dataStartIndex = 0; } for (Int32 valueIndex = 0; valueIndex < imageFileDirectory[entryTag].Length; valueIndex++) { dataStartIndex = TiffTag.SetValue(entryType, imageFileDirectory[entryTag][valueIndex], dataBytes, dataStartIndex); } if (dataCount * dataSize > 4) { Int64 valuePosition = _baseStream.Position; _baseStream.Write(dataBytes, 0, dataBytes.Length); EndianBitConverter.CopyBytes((UInt32)valuePosition, bytes, byteIndex + 8); } byteIndex += _imageFileDirectoryEntrySize; } _currentImageStartPosition = _baseStream.Position; // write the IFD _baseStream.Seek(_currentImageFileDirectoryStartPosition, SeekOrigin.Begin); _baseStream.Write(bytes, 0, bytes.Length); }
private static async Task DumpWellKnownTagsAsync(TiffFieldReader fieldReader, TiffImageFileDirectory ifd, CancellationToken cancellationToken) { int count = 0; var tagReader = new TiffTagReader(fieldReader, ifd); if (ifd.Contains(TiffTag.PhotometricInterpretation)) { Console.WriteLine(" PhotometricInterpretation = " + (await tagReader.ReadPhotometricInterpretationAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.SamplesPerPixel)) { Console.WriteLine(" SamplesPerPixel = " + (await tagReader.ReadSamplesPerPixelAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.BitsPerSample)) { Console.Write(" BitsPerSample = "); DumpValueCollecionSimple(await tagReader.ReadBitsPerSampleAsync(cancellationToken)); Console.WriteLine(); count++; } if (ifd.Contains(TiffTag.ImageWidth)) { Console.WriteLine(" ImageWidth = " + (await tagReader.ReadImageWidthAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.ImageLength)) { Console.WriteLine(" ImageLength = " + (await tagReader.ReadImageLengthAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.Compression)) { Console.WriteLine(" Compression = " + (await tagReader.ReadCompressionAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.FillOrder)) { Console.WriteLine(" FillOrder = " + (await tagReader.ReadFillOrderAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.Predictor)) { Console.WriteLine(" Predictor = " + (await tagReader.ReadPredictorAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.Orientation)) { Console.WriteLine(" Orientation = " + (await tagReader.ReadOrientationAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.RowsPerStrip)) { Console.WriteLine(" RowsPerStrip = " + (await tagReader.ReadRowsPerStripAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.TileWidth)) { Console.WriteLine(" TileWidth = " + (await tagReader.ReadTileWidthAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.TileLength)) { Console.WriteLine(" TileLength = " + (await tagReader.ReadTileLengthAsync(cancellationToken))); count++; } if (count == 0) { Console.WriteLine(" No well-known tags found."); } }
/// <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 override TiffImageFileDirectory ComputeImageFileDirectory(ISpectralGeometry geometry, TiffCompression compression, TiffSampleFormat format) { TiffImageFileDirectory imageFileDirectory = base.ComputeImageFileDirectory(geometry, compression, format); CoordinateReferenceSystem referenceSystem = geometry.ReferenceSystem as CoordinateReferenceSystem; GeoKeyDirectory geoKeyDirectory = new GeoKeyDirectory(); AddGeoKey(geoKeyDirectory, GeoKey.Citation, geometry.Metadata, "GeoTIFF::GeoCitation"); AddGeoKey(geoKeyDirectory, GeoKey.GeodeticCoordinateReferenceSystemCitation, geometry.Metadata, "GeoTIFF::GeodeticCoordinateReferenceSystemCitation"); AddGeoKey(geoKeyDirectory, GeoKey.ProjectedCoordinateReferenceSystemCitation, geometry.Metadata, "GeoTIFF::ProjectedCoordinateReferenceSystemCitation"); if (geometry.Raster.Mapper != null) // if mapper is available { geoKeyDirectory.Add(GeoKey.RasterType, (Int16)((geometry.Raster.Mapper.Mode == RasterMapMode.ValueIsArea) ? 1 : 2)); imageFileDirectory.Add(TiffTag.ModelTiepointTag, new Object[] { 0.0, 0.0, 0.0, geometry.Raster.Mapper.Translation.X, geometry.Raster.Mapper.Translation.Y, 0.0 }); imageFileDirectory.Add(TiffTag.ModelPixelScaleTag, new Object[] { geometry.Raster.Mapper.ColumnSize, geometry.Raster.Mapper.RowSize, 1.0 }); } if (referenceSystem != null) // if reference system is available (and supported) { switch (referenceSystem.Type) { case ReferenceSystemType.Projected: ComputeProjectedCoordinateReferenceSystem(geoKeyDirectory, referenceSystem as ProjectedCoordinateReferenceSystem); break; case ReferenceSystemType.Geographic2D: case ReferenceSystemType.Geographic3D: ComputeGeodeticCoordinateReferenceSystem(geoKeyDirectory, referenceSystem as GeographicCoordinateReferenceSystem); break; default: // other reference systems are not supported return(imageFileDirectory); } } WriteGeoKeyDirectory(imageFileDirectory, geoKeyDirectory); if (geometry.Imaging != null) // add imaging data { imageFileDirectory.Add(57410, new Object[] { geometry.Imaging.Device.Name }); imageFileDirectory.Add(57411, new Object[] { geometry.Imaging.Time.ToString(CultureInfo.InvariantCulture.DateTimeFormat) }); imageFileDirectory.Add(57412, new Object[] { geometry.Imaging.DeviceLocation.Latitude.BaseValue, geometry.Imaging.DeviceLocation.Longitude.BaseValue, geometry.Imaging.DeviceLocation.Height.BaseValue }); imageFileDirectory.Add(57413, new Object[] { geometry.Imaging.IncidenceAngle, geometry.Imaging.ViewingAngle, geometry.Imaging.SunAzimuth, geometry.Imaging.SunElevation }); imageFileDirectory.Add(57417, geometry.Imaging.Bands.Select(band => band.PhysicalGain).Cast <Object>().ToArray()); imageFileDirectory.Add(57418, geometry.Imaging.Bands.Select(band => band.PhysicalBias).Cast <Object>().ToArray()); imageFileDirectory.Add(57419, geometry.Imaging.Bands.Select(band => band.SolarIrradiance).Cast <Object>().ToArray()); Object[] imageLocation = new Object[12]; for (Int32 coordinateIndex = 0; coordinateIndex < geometry.Imaging.ImageLocation.Count; coordinateIndex++) { imageLocation[3 * coordinateIndex] = geometry.Imaging.ImageLocation[coordinateIndex].Latitude.BaseValue; imageLocation[3 * coordinateIndex + 1] = geometry.Imaging.ImageLocation[coordinateIndex].Longitude.BaseValue; imageLocation[3 * coordinateIndex + 2] = geometry.Imaging.ImageLocation[coordinateIndex].Height.BaseValue; } imageFileDirectory.Add(57420, imageLocation); } return(imageFileDirectory); }