553 changes: 2 additions & 551 deletions src/core/raster/qgsrasterdataprovider.cpp

Large diffs are not rendered by default.

150 changes: 11 additions & 139 deletions src/core/raster/qgsrasterdataprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,6 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast

public:

//! If you add to this, please also add to capabilitiesString()
enum Capability
{
NoCapabilities = 0,
Identify = 1,
ExactMinimumMaximum = 1 << 1,
ExactResolution = 1 << 2,
EstimatedMinimumMaximum = 1 << 3,
BuildPyramids = 1 << 4,
Histogram = 1 << 5,
Size = 1 << 6, // has fixed source type
Create = 1 << 7, //create new datasets
Remove = 1 << 8, //delete datasets
IdentifyValue = 1 << 9,
IdentifyText = 1 << 10,
IdentifyHtml = 1 << 11,
IdentifyFeature = 1 << 12 // WMS GML -> feature
};

// This is modified copy of GDALColorInterp
enum ColorInterpretation
{
Expand Down Expand Up @@ -150,26 +131,16 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
*/
virtual QImage* draw( const QgsRectangle & viewExtent, int pixelWidth, int pixelHeight ) = 0;

/** Returns a bitmask containing the supported capabilities
Note, some capabilities may change depending on whether
a spatial filter is active on this provider, so it may
be prudent to check this value per intended operation.
*/
virtual int capabilities() const
{
return QgsRasterDataProvider::NoCapabilities;
}

/**
* Returns the above in friendly format.
*/
QString capabilitiesString() const;


// TODO: Get the supported formats by this provider

// TODO: Get the file masks supported by this provider, suitable for feeding into the file open dialog box

/**
* Get the extent of the data source.
* @return QgsRectangle containing the extent of the layer
*/
virtual QgsRectangle extent() = 0;

/** Returns data type for the band specified by number */
virtual QGis::DataType dataType( int bandNo ) const = 0;

Expand Down Expand Up @@ -254,12 +225,12 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
}

/** Get block size */
virtual int xBlockSize() const { return 0; }
virtual int yBlockSize() const { return 0; }
//virtual int xBlockSize() const { return 0; }
//virtual int yBlockSize() const { return 0; }

/** Get raster size */
virtual int xSize() const { return 0; }
virtual int ySize() const { return 0; }
//virtual int xSize() const { return 0; }
//virtual int ySize() const { return 0; }

// TODO: remove or make protected all readBlock working with void*

Expand All @@ -278,7 +249,7 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
virtual QgsRasterBlock *block( int theBandNo, const QgsRectangle &theExtent, int theWidth, int theHeight );

/* Read a value from a data block at a given index. */
virtual double readValue( void *data, int type, int index );
//virtual double readValue( void *data, int type, int index );

/* Return true if source band has no data value */
virtual bool srcHasNoDataValue( int bandNo ) const { return mSrcHasNoDataValue.value( bandNo -1 ); }
Expand Down Expand Up @@ -318,53 +289,6 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
return QStringList();
}

/** \brief Get histogram. Histograms are cached in providers.
* @param theBandNo The band (number).
* @param theBinCount Number of bins (intervals,buckets). If 0, the number of bins is decided automaticaly according to data type, raster size etc.
* @param theMinimum Minimum value, if NaN, raster minimum value will be used.
* @param theMaximum Maximum value, if NaN, raster minimum value will be used.
* @param theExtent Extent used to calc histogram, if empty, whole raster extent is used.
* @param theSampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
* @param theIncludeOutOfRange include out of range values
* @return Vector of non NULL cell counts for each bin.
* @note theBinCount, theMinimun and theMaximum not optional in python bindings
*/
virtual QgsRasterHistogram histogram( int theBandNo,
int theBinCount = 0,
double theMinimum = std::numeric_limits<double>::quiet_NaN(),
double theMaximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0,
bool theIncludeOutOfRange = false );

/** \brief Returns true if histogram is available (cached, already calculated), the parameters are the same as in histogram()
* @note theBinCount, theMinimun and theMaximum not optional in python bindings
*/
virtual bool hasHistogram( int theBandNo,
int theBinCount,
double theMinimum = std::numeric_limits<double>::quiet_NaN(),
double theMaximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0,
bool theIncludeOutOfRange = false );

/** \brief Find values for cumulative pixel count cut.
* @param theBandNo The band (number).
* @param theLowerCount The lower count as fraction of 1, e.g. 0.02 = 2%
* @param theUpperCount The upper count as fraction of 1, e.g. 0.98 = 98%
* @param theLowerValue Location into which the lower value will be set.
* @param theUpperValue Location into which the upper value will be set.
* @param theExtent Extent used to calc histogram, if empty, whole raster extent is used.
* @param theSampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
*/
virtual void cumulativeCut( int theBandNo,
double theLowerCount,
double theUpperCount,
double &theLowerValue,
double &theUpperValue,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

/** \brief Create pyramid overviews */
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
const QString & theResamplingMethod = "NEAREST",
Expand All @@ -387,35 +311,6 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
/** \brief Returns true if raster has at least one populated histogram. */
bool hasPyramids();

/** If the provider supports it, return band stats for the
given band. Default behaviour is to blockwise read the data
and generate the stats unless the provider overloads this function. */
//virtual QgsRasterBandStats bandStatistics( int theBandNo );

/** \brief Get band statistics.
* @param theBandNo The band (number).
* @param theStats Requested statistics
* @param theExtent Extent used to calc histogram, if empty, whole raster extent is used.
* @param theSampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
* @return Band statistics.
*/
virtual QgsRasterBandStats bandStatistics( int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

/** \brief Returns true if histogram is available (cached, already calculated), the parameters are the same as in histogram() */
virtual bool hasStatistics( int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

/** \brief helper function to create zero padded band names */
QString generateBandName( int theBandNumber ) const
{
return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber, 1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) );
}

/**
* Get metadata in a format suitable for feeding directly
* into a subset of the GUI raster properties "Metadata" tab.
Expand Down Expand Up @@ -590,28 +485,5 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast

QgsRectangle mExtent;

/** \brief List of cached statistics, all bands mixed */
QList <QgsRasterBandStats> mStatistics;

/** \brief List of cached histograms, all bands mixed */
QList <QgsRasterHistogram> mHistograms;

/** Fill in histogram defaults if not specified
* @note theBinCount, theMinimun and theMaximum not optional in python bindings
*/
void initHistogram( QgsRasterHistogram &theHistogram, int theBandNo,
int theBinCount = 0,
double theMinimum = std::numeric_limits<double>::quiet_NaN(),
double theMaximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0,
bool theIncludeOutOfRange = false );

/** Fill in statistics defaults if not specified */
void initStatistics( QgsRasterBandStats &theStatistics, int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theBinCount = 0 );

};
#endif
561 changes: 560 additions & 1 deletion src/core/raster/qgsrasterinterface.cpp

Large diffs are not rendered by default.

153 changes: 153 additions & 0 deletions src/core/raster/qgsrasterinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,45 @@

#include <limits>

#include <QCoreApplication> // for tr()
#include <QImage>

#include "qgslogger.h"
#include "qgsrasterblock.h"
#include "qgsrectangle.h"
#include "qgsrasterbandstats.h"
#include "qgsrasterhistogram.h"

/** \ingroup core
* Base class for processing modules.
*/
// TODO: inherit from QObject? It would be probably better but QgsDataProvider inherits already from QObject and multiple inheritance from QObject is not allowed
class CORE_EXPORT QgsRasterInterface
{
Q_DECLARE_TR_FUNCTIONS( QgsRasterInterface );

public:

//! If you add to this, please also add to capabilitiesString()
enum Capability
{
NoCapabilities = 0,
Identify = 1,
ExactMinimumMaximum = 1 << 1,
ExactResolution = 1 << 2,
EstimatedMinimumMaximum = 1 << 3,
BuildPyramids = 1 << 4,
Histogram = 1 << 5,
Size = 1 << 6, // has fixed source type
Create = 1 << 7, //create new datasets
Remove = 1 << 8, //delete datasets
IdentifyValue = 1 << 9,
IdentifyText = 1 << 10,
IdentifyHtml = 1 << 11,
IdentifyFeature = 1 << 12 // WMS GML -> feature
};


#if 0
struct Range
{
Expand All @@ -53,8 +78,26 @@ class CORE_EXPORT QgsRasterInterface
/** Clone itself, create deep copy */
virtual QgsRasterInterface *clone() const = 0;

/** Returns a bitmask containing the supported capabilities
*/
virtual int capabilities() const
{
return QgsRasterInterface::NoCapabilities;
}

/**
* Returns the above in friendly format.
*/
QString capabilitiesString() const;

/** Returns data type for the band specified by number */
virtual QGis::DataType dataType( int bandNo ) const = 0;

/** Returns source data type for the band specified by number,
* source data type may be shorter than dataType
*/
virtual QGis::DataType srcDataType( int bandNo ) { if ( mInput ) return mInput->srcDataType( bandNo ); else return QGis::UnknownDataType; };

#if 0
{
Q_UNUSED( bandNo );
Expand All @@ -63,11 +106,31 @@ class CORE_EXPORT QgsRasterInterface
}
#endif

/**
* Get the extent of the interface.
* @return QgsRectangle containing the extent of the layer
*/
virtual QgsRectangle extent() { if ( mInput ) return mInput->extent(); else return QgsRectangle(); }

int dataTypeSize( int bandNo ) { return QgsRasterBlock::typeSize( dataType( bandNo ) ); }

/** Get number of bands */
virtual int bandCount() const = 0;

/** Get block size */
virtual int xBlockSize() const { if ( mInput ) return mInput->xBlockSize(); else return 0; }
virtual int yBlockSize() const { if ( mInput ) return mInput->yBlockSize(); else return 0; }

/** Get raster size */
virtual int xSize() const { if ( mInput ) return mInput->xSize(); else return 0; }
virtual int ySize() const { if ( mInput ) return mInput->ySize(); else return 0; }

/** \brief helper function to create zero padded band names */
virtual QString generateBandName( int theBandNumber ) const
{
return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber, 1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) );
}

/** Return no data value for specific band. Each band/provider must have
* no data value, if there is no one set in original data, provider decides one
* possibly using wider data type.
Expand Down Expand Up @@ -129,6 +192,73 @@ class CORE_EXPORT QgsRasterInterface
return mInput ? mInput->srcInput() : this;
}

/** \brief Get band statistics.
* @param theBandNo The band (number).
* @param theStats Requested statistics
* @param theExtent Extent used to calc statistics, if empty, whole raster extent is used.
* @param theSampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
* @return Band statistics.
*/
virtual QgsRasterBandStats bandStatistics( int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

/** \brief Returns true if histogram is available (cached, already calculated). * The parameters are the same as in bandStatistics()
* @return true if statistics are available (ready to use)
*/
virtual bool hasStatistics( int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

/** \brief Get histogram. Histograms are cached in providers.
* @param theBandNo The band (number).
* @param theBinCount Number of bins (intervals,buckets). If 0, the number of bins is decided automaticaly according to data type, raster size etc.
* @param theMinimum Minimum value, if NaN, raster minimum value will be used.
* @param theMaximum Maximum value, if NaN, raster minimum value will be used.
* @param theExtent Extent used to calc histogram, if empty, whole raster extent is used.
* @param theSampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
* @param theIncludeOutOfRange include out of range values
* @return Vector of non NULL cell counts for each bin.
* @note theBinCount, theMinimun and theMaximum not optional in python bindings
*/
virtual QgsRasterHistogram histogram( int theBandNo,
int theBinCount = 0,
double theMinimum = std::numeric_limits<double>::quiet_NaN(),
double theMaximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0,
bool theIncludeOutOfRange = false );

/** \brief Returns true if histogram is available (cached, already calculated), the parameters are the same as in histogram()
* @note theBinCount, theMinimun and theMaximum not optional in python bindings
*/
virtual bool hasHistogram( int theBandNo,
int theBinCount,
double theMinimum = std::numeric_limits<double>::quiet_NaN(),
double theMaximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0,
bool theIncludeOutOfRange = false );

/** \brief Find values for cumulative pixel count cut.
* @param theBandNo The band (number).
* @param theLowerCount The lower count as fraction of 1, e.g. 0.02 = 2%
* @param theUpperCount The upper count as fraction of 1, e.g. 0.98 = 98%
* @param theLowerValue Location into which the lower value will be set.
* @param theUpperValue Location into which the upper value will be set.
* @param theExtent Extent used to calc histogram, if empty, whole raster extent is used.
* @param theSampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
*/
virtual void cumulativeCut( int theBandNo,
double theLowerCount,
double theUpperCount,
double &theLowerValue,
double &theUpperValue,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

/** Switch on (and clear old statistics) or off collection of statistics */
//void setStatsOn( bool on );

Expand All @@ -142,9 +272,32 @@ class CORE_EXPORT QgsRasterInterface
// QgsRasterInterface used as input
QgsRasterInterface* mInput;

/** \brief List of cached statistics, all bands mixed */
QList <QgsRasterBandStats> mStatistics;

/** \brief List of cached histograms, all bands mixed */
QList <QgsRasterHistogram> mHistograms;

// On/off state, if off, it does not do anything, replicates input
bool mOn;

/** Fill in histogram defaults if not specified
* @note theBinCount, theMinimun and theMaximum not optional in python bindings
*/
void initHistogram( QgsRasterHistogram &theHistogram, int theBandNo,
int theBinCount = 0,
double theMinimum = std::numeric_limits<double>::quiet_NaN(),
double theMaximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0,
bool theIncludeOutOfRange = false );

/** Fill in statistics defaults if not specified */
void initStatistics( QgsRasterBandStats &theStatistics, int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theBinCount = 0 );

private:
// Last rendering cumulative (this and all preceding interfaces) times, from index 1
//QVector<double> mTime;
Expand Down
8 changes: 8 additions & 0 deletions tests/testdata/raster/band1_byte_noct_epsg4326.tif.aux.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
<Approximate>0</Approximate>
<HistCounts>0|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|19</HistCounts>
</HistItem>
<HistItem>
<HistMin>0.74</HistMin>
<HistMax>255.26</HistMax>
<BucketCount>100</BucketCount>
<IncludeOutOfRange>0</IncludeOutOfRange>
<Approximate>0</Approximate>
<HistCounts>1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|20</HistCounts>
</HistItem>
</Histograms>
<Metadata>
<MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI>
Expand Down
24 changes: 24 additions & 0 deletions tests/testdata/raster/band3_byte_noct_epsg4326.tif.aux.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
<Approximate>0</Approximate>
<HistCounts>0|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|19</HistCounts>
</HistItem>
<HistItem>
<HistMin>0.74</HistMin>
<HistMax>255.26</HistMax>
<BucketCount>100</BucketCount>
<IncludeOutOfRange>0</IncludeOutOfRange>
<Approximate>0</Approximate>
<HistCounts>1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|20</HistCounts>
</HistItem>
</Histograms>
<Metadata>
<MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI>
Expand All @@ -30,6 +38,14 @@
<Approximate>0</Approximate>
<HistCounts>0|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|19</HistCounts>
</HistItem>
<HistItem>
<HistMin>0.74</HistMin>
<HistMax>255.26</HistMax>
<BucketCount>100</BucketCount>
<IncludeOutOfRange>0</IncludeOutOfRange>
<Approximate>0</Approximate>
<HistCounts>1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|20</HistCounts>
</HistItem>
</Histograms>
<Metadata>
<MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI>
Expand All @@ -51,6 +67,14 @@
<Approximate>0</Approximate>
<HistCounts>0|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|0|0|1|0|0|1|0|1|0|0|1|0|1|0|0|1|0|0|1|19</HistCounts>
</HistItem>
<HistItem>
<HistMin>0.74</HistMin>
<HistMax>255.26</HistMax>
<BucketCount>100</BucketCount>
<IncludeOutOfRange>0</IncludeOutOfRange>
<Approximate>0</Approximate>
<HistCounts>1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|1|1|1|0|1|1|1|1|1|1|20</HistCounts>
</HistItem>
</Histograms>
<Metadata>
<MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI>
Expand Down