Export image
The Export image step saves the converted BitmapImage
with additional metadata information into a standard file format.
After the Convert pipeline (see Convert Pipeline) produced a BitmapImage
data, one might want to store the result on the file system as part of a delivery, or to further process the image with another application. This step is meant for this use case.
The current version supports the following output formats:
Joint Photographic Experts Group (JPEG) format
JPEG 2000 (JP2) format
Tag Image File Format (TIFF) with GeoTIFF extension
PGM Image File Format (PGM) - a textual greyscale image format
Exporting into Joint Photographic Experts Group (JPEG) format
To export into JPEG format one must obtain both the original RawImage
and the produced BitmapImage
along with the JpegConfig
configuring the output file.
P1::ImageSdk::RawImage rawImage;
P1::ImageSdk::BitmapImage bitmap;
P1::ImageSdk::JpegConfig config;
std::string filename;
config.compression = 80;
P1::ImageSdk::JpegWriter jpegWriter(filename, bitmap, rawImage, config);
P1.ImageSdk.RawImage rawImage;
P1.ImageSdk.BitmapImage bitmap;
P1.ImageSdk.JpegConfig config;
System.String filename;
config.compression = 80;
rawImage.WriteAsJpeg(filename, bitmap, config);
Exporting into JPEG 2000 (JP2) format
To export into JP2 format one must obtain both the original RawImage
and the produced BitmapImage
along with the Jp2Config
configuring the output file.
P1::ImageSdk::RawImage rawImage;
P1::ImageSdk::BitmapImage bitmap;
P1::ImageSdk::Jp2Config config;
std::string filename;
P1::ImageSdk::Jp2Writer jp2Writer(filename, bitmap, rawImage, config);
P1.ImageSdk.RawImage rawImage;
P1.ImageSdk.BitmapImage bitmap;
P1.ImageSdk.Jp2Config config;
System.String filename;
rawImage.WriteAsJp2(filename, bitmap, config);
Exporting into Tag Image File Format (TIFF)
To export into TIFF format one must obtain both the original RawImage
and the produced BitmapImage
along with the TiffConfig
configuring the output file.
P1::ImageSdk::RawImage rawImage;
P1::ImageSdk::BitmapImage bitmap;
P1::ImageSdk::TiffConfig config;
std::string filename;
config.tileSize = P1::ImageSdk::tileSize512;
P1::ImageSdk::TiffWriter tiffWriter(filename, bitmap, rawImage, config);
P1.ImageSdk.RawImage rawImage;
P1.ImageSdk.BitmapImage bitmap;
P1.ImageSdk.TiffConfig config;
System.String filename;
config.tileSize = P1.ImageSdk.TiffTileSize.tileSize512;
rawImage.WriteAsTiff(filename, bitmap, config);
Exporting into PGM Format (PGM)
To export into PGM format one must obtain both the original RawImage
and the produced BitmapImage
The PGM image format is a textual greyscale format. The greyscale values are found by taking the luminosity value of
the Red, Green and Blue channel.
P1::ImageSdk::RawImage image;
P1::ImageSdk::BitmapImage bitmap;
std::string filename;
P1::ImageSdk::PgmWriter(filename, bitmap, image);
P1.ImageSdk.RawImage rawImage;
P1.ImageSdk.BitmapImage bitmap;
P1.ImageSdk.Jp2Config config;
System.String filename;
rawImage.WriteAsPgm(filename, bitmap);
Output color space
By default the ImageSDK will output images in sRGB color space (IEC 61966-2-1). Although this color space has relatively small gamut, it is adequate for most applications. In case the end user needs to output the images in wider color gamut, ImageSDK can produce them in Adobe RGB (1998) color space (IEC 61966-2-5:2007).
config.SetOutputColorSpace(P1::ImageSdk::ColorSpace::adobeRGB);
config.SetOutputColorSpace(P1.ImageSdk.ColorSpace.adobeRGB);
The such converted bitmap needs to be supplemented with an Adobe RGB (1998) color profile so that the writer can output a file which is interpreted correctly by any color managed viewer.
std::string colorProfileFilename = "Adobe RGB (1998).icm";
P1::ImageSdk::TiffConfig outputConfig; // The same applies to all other output formats
char* colorProfileBuffer = nullptr;
FILE* fp = fopen(colorProfileFilename.c_str(), "rb");
if (fp)
{
long colorProfileFileLength;
if (fseek(fp, 0, SEEK_END) == 0 &&
0 <= (colorProfileFileLength = ftell(fp)) )
{
rewind(fp);
colorProfileBuffer = new char[colorProfileFileLength];
if (fread(colorProfileBuffer, 1, colorProfileFileLength, fp) == (size_t)colorProfileFileLength)
{
outputConfig.commonConfig.iccProfileData = colorProfileBuffer;
outputConfig.commonConfig.iccProfileSize = colorProfileFileLength;
}
else
{
std::cout << "Could not read icc profile" << std::endl;
}
fclose(fp);
}
else
{
std::cout << "Could not find size of icc profile" << std::endl;
}
}
else
{
std::cout << "Could not find icc profile" << std::endl;
}
TiffConfig tiffConfig = new TiffConfig(); // The same applies to all other output formats
tiffConfig.commonConfig.iccProfileData = File.ReadAllBytes("Adobe RGB (1998).icm");
Adding GeoTIFF fields to the metadata
To output a valid GeoTIFF file, the ImageSdk requires a couple of fields to be defined in the TiffConfig structure. A minimum set of required parameters are currently supported.
GTRasterTypeGeoKey
GTModelTypeGeoKey
ModelTiepointTag
ModelPixelScaleTag
ModelTransformationTag
GTCitationGeoKey
See an example of how to add the fields to the configuration.
std::vector< P1::ImageSdk::GeoTiffField > geoTiffFieldList;
// Pixel Scale tag
double pixelScaleArray[3];
if (pixelScaleArray == NULL) return false;
pixelScaleArray[0] = 10.0; // x
pixelScaleArray[1] = 15.0; // y
pixelScaleArray[2] = 0.0; // z
P1::ImageSdk::GeoTiffField pixelScale;
pixelScale.key = P1::ImageSdk::GeoTiffModelPixelScaleTag;
pixelScale.valueType = P1::ImageSdk::GeoTiffValueTypeDouble;
pixelScale.data = pixelScaleArray;
pixelScale.count = 3;
geoTiffFieldList.push_back(pixelScale);
// Tie Point tag
double tiePointArray[6];
tiePointArray[0] = 0.0; // I (raster space x)
tiePointArray[1] = 5.0; // J (raster space y)
tiePointArray[2] = 0.0; // K (pixel value, should be 0)
tiePointArray[3] = 0.0; // X (model space x)
tiePointArray[4] = 5.0; // Y (model space y)
tiePointArray[5] = 0.0; // Z (model space z, should be 0 for 2D model space)
P1::ImageSdk::GeoTiffField tiePoint;
tiePoint.key = P1::ImageSdk::GeoTiffModelTiepointTag;
tiePoint.valueType = P1::ImageSdk::GeoTiffValueTypeDouble;
tiePoint.data = tiePointArray;
tiePoint.count = 6;
geoTiffFieldList.push_back(tiePoint);
// Model Type tag
P1::ImageSdk::GeoTiffField modelType;
modelType.key = P1::ImageSdk::GTModelType;
modelType.valueType = P1::ImageSdk::GeoTiffValueTypeShort;
modelType.count = 0;
modelType.value = 1; // ModelTypeProjected
modelType.data = nullptr;
geoTiffFieldList.push_back(modelType);
// Raster Type tag
P1::ImageSdk::GeoTiffField rasterType;
rasterType.key = P1::ImageSdk::GTRasterType;
rasterType.valueType = P1::ImageSdk::GeoTiffValueTypeShort;
rasterType.count = 0;
rasterType.value = 1; // RasterPixelIsArea
rasterType.data = nullptr;
geoTiffFieldList.push_back(rasterType);
// Citation tag (optional)
char const* citationText = "Test Citation";
auto const citationTextBuffer = (unsigned char*)malloc(strlen(citationText));
if (citationTextBuffer != NULL)
{
memcpy(citationTextBuffer, citationText, strlen(citationText)); // move the string to the heap so is survives the exiting of the scope
P1::ImageSdk::GeoTiffField citation;
citation.key = P1::ImageSdk::GTCitation;
citation.valueType = P1::ImageSdk::GeoTiffValueTypeAscii;
citation.data = citationTextBuffer;
citation.count = strlen(citationText);
geoTiffFieldList.push_back(citation);
}
P1::ImageSdk::GeoTiffField* const geoTiffFieldListRaw = (P1::ImageSdk::GeoTiffField*)malloc(geoTiffFieldList.size() * sizeof(P1::ImageSdk::GeoTiffField));
if (geoTiffFieldListRaw != NULL)
{
memcpy(geoTiffFieldListRaw, geoTiffFieldList.data(), geoTiffFieldList.size() * sizeof(GeoTiffField));
config.commonConfig.geoTiffFieldList = geoTiffFieldListRaw;
config.commonConfig.geoTiffFieldCount = geoTiffFieldList.size();
}
List<GeoTiffField> geoTiffFieldList = new List<GeoTiffField>();
// Pixel Scale tag
GeoTiffField pixelScale = new GeoTiffField()
{
key = GeoTiffKey.GeoTiffModelPixelScaleTag,
doubleArrayValue = new List<double>() { 1.0, 2.5, 0.0 },
};
geoTiffFieldList.Add(pixelScale);
// Tie Point tag
GeoTiffField tiePoint = new GeoTiffField()
{
key = GeoTiffKey.GeoTiffModelTiepointTag,
doubleArrayValue = new List<double>() { 0.0, 5.0, 0.0, 1.0, 42.5, 3.14159265 },
};
geoTiffFieldList.Add(tiePoint);
// Model Type tag
GeoTiffField modelType = new GeoTiffField()
{
key = GeoTiffKey.GTModelType,
value = 1,
};
geoTiffFieldList.Add(modelType);
// Raster Type tag
GeoTiffField rasterType = new GeoTiffField()
{
key = GeoTiffKey.GTRasterType,
value = 1,
};
geoTiffFieldList.Add(rasterType);
// Citation tag (optional)
GeoTiffField citation = new GeoTiffField()
{
key = GeoTiffKey.GTCitation,
stringValue = "Test Citation",
};
geoTiffFieldList.Add(citation);
// Add to the configuration
config.commonConfig.geoTiffFieldList = geoTiffFieldList;