/// <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++;
        }
        /// <summary>
        /// Writes the raster of the geometry into a strip.
        /// </summary>
        /// <param name="raster">The raster.</param>
        /// <param name="compression">The compression.</param>
        /// <param name="format">The sample format.</param>
        private void WriteRasterContentToStrip(IRaster raster, TiffCompression compression, TiffSampleFormat format)
        {
            _baseStream.Seek(_currentImageStartPosition, SeekOrigin.Begin);

            // mark the starting position of the strip
            UInt32 numberOfBytes     = (UInt32)(Math.Ceiling(raster.RadiometricResolution / 8.0) * raster.NumberOfBands * raster.NumberOfRows * raster.NumberOfColumns);
            UInt32 numberOfBytesLeft = numberOfBytes;

            if (numberOfBytes % 2 != 0) // correct the number of bytes
            {
                numberOfBytes++;
            }

            Byte[] bytes     = new Byte[numberOfBytes < NumberOfWritableBytes ? numberOfBytes : NumberOfWritableBytes];
            Int32  byteIndex = 0;
            Int32  bitIndex  = 8;

            for (Int32 rowIndex = 0; rowIndex < raster.NumberOfRows; rowIndex++)
            {
                for (Int32 columnIndex = 0; columnIndex < raster.NumberOfColumns; columnIndex++)
                {
                    // write the values for each band into the buffer
                    for (Int32 bandIndex = 0; bandIndex < raster.NumberOfBands; bandIndex++)
                    {
                        switch (format)
                        {
                        case TiffSampleFormat.Undefined:
                        case TiffSampleFormat.UnsignedInteger:
                            WriteUnsignedIntergerValue(raster.GetValue(rowIndex, columnIndex, bandIndex), raster.RadiometricResolution, bytes, ref byteIndex, ref bitIndex);
                            break;

                        case TiffSampleFormat.SignedInteger:
                        case TiffSampleFormat.Floating:
                            WriteFloatValue(raster.GetFloatValue(rowIndex, columnIndex, bandIndex), raster.RadiometricResolution, bytes, ref byteIndex, ref bitIndex);
                            break;
                        }

                        if (byteIndex == bytes.Length)
                        {
                            // write the buffer to the file
                            _baseStream.Write(bytes, 0, byteIndex);

                            byteIndex = 0;

                            numberOfBytesLeft -= (UInt32)byteIndex;
                            // the final array of bytes should not be the number of bytes left
                            if (numberOfBytes > NumberOfWritableBytes && numberOfBytesLeft > 0 && numberOfBytesLeft < NumberOfWritableBytes)
                            {
                                bytes = new Byte[numberOfBytesLeft % 2 == 0 ? numberOfBytesLeft : numberOfBytesLeft + 1];
                            }
                        }
                    }
                }
            }

            // if any values are left
            if (numberOfBytesLeft > 0)
            {
                _baseStream.Write(bytes, 0, byteIndex);
            }
        }
        /// <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);
        }
Exemple #4
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 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);
        }