21 #include <QApplication>
23 #include <QImageReader>
34 class TileCreatorPrivate
37 TileCreatorPrivate( TileCreatorSource *source,
40 m_targetDir( targetDir ),
42 m_tileFormat(
"jpg" ),
47 if ( m_dem ==
"true" ) {
68 TileCreatorSource *m_source;
71 class TileCreatorSourceImage :
public TileCreatorSource
74 TileCreatorSourceImage(
const QString &sourcePath )
75 : m_sourceImage(
QImage( sourcePath ) ),
80 virtual QSize fullImageSize()
const
82 if ( m_sourceImage.size().width() > 21600 || m_sourceImage.height() > 10800 ) {
83 qDebug(
"Install map too large!");
86 return m_sourceImage.size();
89 virtual QImage tile(
int n,
int m,
int maxTileLevel)
94 int imageHeight = m_sourceImage.height();
95 int imageWidth = m_sourceImage.width();
104 mDebug() <<
"Image Size doesn't match 2*n*TILEWIDTH x n*TILEHEIGHT geometry. Scaling ...";
107 if ( stdImageWidth == 0 )
111 if ( stdImageWidth != imageWidth ) {
113 QString(
"TileCreator::createTiles() The size of the final image will measure %1 x %2 pixels").
arg(stdImageWidth).
arg(stdImageHeight);
118 if ( m_cachedRowNum == n ) {
124 QRect sourceRowRect( 0, (
int)( (qreal)( n * imageHeight ) / (qreal)( nmax )),
125 imageWidth,(
int)( (qreal)( imageHeight ) / (qreal)( nmax ) ) );
128 row = m_sourceImage.
copy( sourceRowRect );
130 if ( needsScaling ) {
133 QSize destSize( stdImageWidth, c_defaultTileSize );
134 row = row.
scaled( destSize,
135 Qt::IgnoreAspectRatio,
136 Qt::SmoothTransformation );
144 mDebug() <<
"Read-Error! Null QImage!";
148 QImage tile = row.
copy( m * stdImageWidth / mmax, 0, c_defaultTileSize, c_defaultTileSize );
164 d( new TileCreatorPrivate( 0, dem, targetDir ) )
167 mDebug() <<
"Prefix: " << sourceDir
168 <<
"installmap:" << installMap;
175 sourcePath = sourceDir +
'/' + installMap;
176 mDebug() <<
"Trying absolute path*:" << sourcePath;
180 +
'/' + installMap );
181 mDebug() <<
"Trying relative path*:"
182 <<
"maps/" + sourceDir +
'/' + installMap;
185 mDebug() <<
"Creating tiles from*: " << sourcePath;
187 d->m_source =
new TileCreatorSourceImage( sourcePath );
189 if ( d->m_targetDir.isNull() )
191 + sourcePath.
section(
'/', -3, -2 ) +
'/';
198 d( new TileCreatorPrivate( source, dem, targetDir ) )
210 d->m_cancelled =
true;
215 if ( d->m_resume && d->m_tileFormat ==
"jpg" && d->m_tileQuality != 100 ) {
216 qWarning() <<
"Resuming jpegs is only supported with tileQuality 100";
220 if ( !d->m_targetDir.endsWith(
'/') )
221 d->m_targetDir +=
'/';
223 mDebug() <<
"Installing tiles to: " << d->m_targetDir;
226 for (
int cnt = 0; cnt <= 255; ++cnt ) {
227 grayScalePalette.
insert(cnt, qRgb(cnt, cnt, cnt));
230 QSize fullImageSize = d->m_source->fullImageSize();
231 int imageWidth = fullImageSize.
width();
232 int imageHeight = fullImageSize.
height();
234 mDebug() <<
QString(
"TileCreator::createTiles() image dimensions %1 x %2").
arg(imageWidth).
arg(imageHeight);
236 if ( imageWidth < 1 || imageHeight < 1 ) {
237 qDebug(
"Invalid imagemap!");
242 float approxMaxTileLevel = std::log( imageWidth / ( 2.0 * c_defaultTileSize ) ) / std::log( 2.0 );
244 int maxTileLevel = 0;
245 if ( approxMaxTileLevel ==
int( approxMaxTileLevel ) )
246 maxTileLevel =
static_cast<int>( approxMaxTileLevel );
248 maxTileLevel =
static_cast<int>( approxMaxTileLevel + 1 );
250 if ( maxTileLevel < 0 ) {
252 <<
QString(
"TileCreator::createTiles(): Invalid Maximum Tile Level: %1" )
253 .
arg( maxTileLevel );
255 mDebug() <<
"Maximum Tile Level: " << maxTileLevel;
265 int totalTileCount = 0;
267 while ( tileLevel <= maxTileLevel ) {
273 mDebug() << totalTileCount <<
" tiles to be created in total.";
279 int percentCompleted = 0;
280 int createdTilesCount = 0;
284 QString dirName( d->m_targetDir
285 +
QString(
"%1").arg(maxTileLevel) );
286 if ( !
QDir( dirName ).exists() )
289 for (
int n = 0; n < nmax; ++n ) {
290 QString dirName( d->m_targetDir
292 if ( !
QDir( dirName ).exists() )
296 for (
int n = 0; n < nmax; ++n ) {
298 for (
int m = 0; m < mmax; ++m ) {
300 mDebug() <<
"** tile" << m <<
"x" << n;
302 if ( d->m_cancelled )
305 tileName = d->m_targetDir + (
QString(
"%1/%2/%2_%3.%4")
309 .arg( d->m_tileFormat );
317 QImage tile = d->m_source->tile( n, m, maxTileLevel );
320 mDebug() <<
"Read-Error! Null QImage!";
324 if ( d->m_dem ==
"true" ) {
327 Qt::ThresholdDither);
330 bool ok = tile.
save( tileName, d->m_tileFormat.toLatin1().data(), d->m_tileFormat ==
"jpg" ? 100 : d->m_tileQuality );
332 mDebug() <<
"Error while writing Tile: " << tileName;
337 QImage writtenTile(tileName);
338 Q_ASSERT( writtenTile.
size() == tile.
size() );
339 for (
int i=0; i < writtenTile.
size().
width(); ++i) {
340 for (
int j=0; j < writtenTile.
size().
height(); ++j) {
341 if ( writtenTile.
pixel( i, j ) != tile.
pixel( i, j ) ) {
342 unsigned int pixel = tile.
pixel( i, j);
343 unsigned int writtenPixel = writtenTile.
pixel( i, j);
344 qWarning() <<
"***** pixel" << i << j <<
"is off by" << (pixel - writtenPixel) <<
"pixel" << pixel <<
"writtenPixel" << writtenPixel;
345 QByteArray baPixel((
char*)&pixel,
sizeof(
unsigned int));
346 qWarning() <<
"pixel" << baPixel.size() <<
"0x" << baPixel.toHex();
347 QByteArray baWrittenPixel((
char*)&writtenPixel,
sizeof(
unsigned int));
348 qWarning() <<
"writtenPixel" << baWrittenPixel.
size() <<
"0x" << baWrittenPixel.
toHex();
357 percentCompleted = (int) ( 90 * (qreal)(createdTilesCount)
358 / (qreal)(totalTileCount) );
361 mDebug() <<
"percentCompleted" << percentCompleted;
366 mDebug() <<
"tileLevel: " << maxTileLevel <<
" successfully created.";
368 tileLevel = maxTileLevel;
373 while( tileLevel > 0 ) {
378 for (
int n = 0; n < nmaxit; ++n ) {
379 QString dirName( d->m_targetDir
385 if ( !
QDir( dirName ).exists() )
389 for (
int m = 0; m < mmaxit; ++m ) {
391 if ( d->m_cancelled )
394 QString newTileName = d->m_targetDir + (
QString(
"%1/%2/%2_%3.%4")
398 .arg( d->m_tileFormat );
403 tileName = d->m_targetDir + (
QString(
"%1/%2/%2_%3.%4")
404 .
arg( tileLevel + 1 )
407 .arg( d->m_tileFormat );
408 QImage img_topleft( tileName );
410 tileName = d->m_targetDir + (
QString(
"%1/%2/%2_%3.%4")
411 .
arg( tileLevel + 1 )
414 .arg( d->m_tileFormat );
415 QImage img_topright( tileName );
417 tileName = d->m_targetDir + (
QString(
"%1/%2/%2_%3.%4")
418 .
arg( tileLevel + 1 )
421 .arg( d->m_tileFormat );
422 QImage img_bottomleft( tileName );
424 tileName = d->m_targetDir + (
QString(
"%1/%2/%2_%3.%4")
425 .
arg( tileLevel + 1 )
428 .arg( d->m_tileFormat );
429 QImage img_bottomright( tileName );
431 QSize const expectedSize( c_defaultTileSize, c_defaultTileSize );
432 if ( img_topleft.
size() != expectedSize ||
433 img_topright.
size() != expectedSize ||
434 img_bottomleft.
size() != expectedSize ||
435 img_bottomright.
size() != expectedSize ) {
436 mDebug() <<
"Tile write failure. Missing write permissions?";
440 QImage tile = img_topleft;
442 if ( d->m_dem ==
"true" ) {
447 for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
449 const uchar* srcLine = img_topleft.
scanLine( 2 * y );
450 for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
451 destLine[x] = srcLine[ 2*x ];
453 for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
455 const uchar* srcLine = img_topright.
scanLine( 2 * y );
457 destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
461 const uchar* srcLine = img_bottomleft.
scanLine( 2 * ( y - c_defaultTileSize / 2 ) );
462 for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
463 destLine[ x ] = srcLine[ 2 * x ];
467 const uchar* srcLine = img_bottomright.
scanLine( 2 * ( y - c_defaultTileSize/2 ) );
469 destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
478 img_bottomleft = img_bottomleft.
convertToFormat( QImage::Format_ARGB32 );
479 img_bottomright = img_bottomright.
convertToFormat( QImage::Format_ARGB32 );
484 for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
485 destLine = (QRgb*) tile.
scanLine( y );
486 const QRgb* srcLine = (QRgb*) img_topleft.
scanLine( 2 * y );
487 for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
488 destLine[x] = srcLine[ 2 * x ];
490 for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
491 destLine = (QRgb*) tile.
scanLine( y );
492 const QRgb* srcLine = (QRgb*) img_topright.
scanLine( 2 * y );
494 destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
497 destLine = (QRgb*) tile.
scanLine( y );
498 const QRgb* srcLine = (QRgb*) img_bottomleft.
scanLine( 2 * ( y-c_defaultTileSize/2 ) );
499 for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
500 destLine[x] = srcLine[ 2 * x ];
503 destLine = (QRgb*) tile.
scanLine( y );
504 const QRgb* srcLine = (QRgb*) img_bottomright.
scanLine( 2 * ( y-c_defaultTileSize / 2 ) );
506 destLine[x] = srcLine[ 2*( x-c_defaultTileSize / 2 ) ];
514 bool ok = tile.
save( newTileName, d->m_tileFormat.toLatin1().data(), d->m_tileFormat ==
"jpg" ? 100 : d->m_tileQuality );
516 mDebug() <<
"Error while writing Tile: " << newTileName;
519 percentCompleted = (int) ( 90 * (qreal)(createdTilesCount)
520 / (qreal)(totalTileCount) );
524 mDebug() <<
"percentCompleted" << percentCompleted;
527 mDebug() <<
"tileLevel: " << tileLevel <<
" successfully created.";
529 mDebug() <<
"Tile creation completed.";
531 if ( d->m_tileFormat ==
"jpg" && d->m_tileQuality != 100 ) {
534 int savedTilesCount = 0;
537 while ( tileLevel <= maxTileLevel ) {
539 for (
int n = 0; n < nmaxit; ++n) {
541 for (
int m = 0; m < mmaxit; ++m) {
543 if ( d->m_cancelled )
548 tileName = d->m_targetDir + (
QString(
"%1/%2/%2_%3.%4")
552 .arg( d->m_tileFormat );
557 ok = tile.
save( tileName, d->m_tileFormat.toLatin1().data(), d->m_tileQuality );
560 mDebug() <<
"Error while writing Tile: " << tileName;
562 percentCompleted = 90 + (int)( 9 * (qreal)(savedTilesCount)
563 / (qreal)(totalTileCount) );
565 mDebug() <<
"percentCompleted" << percentCompleted;
575 percentCompleted = 100;
578 mDebug() <<
"percentCompleted: " << percentCompleted;
583 d->m_tileFormat = format;
588 return d->m_tileFormat;
593 d->m_tileQuality = quality;
598 return d->m_tileQuality;
613 d->m_verify = verify;
624 #include "TileCreator.moc"
static QString path(const QString &relativePath)
bool verifyExactResult() const
bool save(const QString &fileName, const char *format, int quality) const
void insert(int i, const T &value)
QString tileFormat() const
static QString localPath()
QImage copy(const QRect &rectangle) const
const int defaultLevelZeroColumns
Base Class for custom tile source.
TileCreator(const QString &sourceDir, const QString &installMap, const QString &dem, const QString &targetDir=QString())
Constructor for standard Image source.
QRgb pixel(int x, int y) const
void setVerifyExactResult(bool verify)
const unsigned int c_defaultTileSize
virtual qint64 size() const
void setTileFormat(const QString &format)
bool isAbsolutePath(const QString &path)
void setTerminationEnabled(bool enabled)
MARBLE_EXPORT int levelToRow(int levelZeroRows, int level)
Get the maximum number of tile rows for a given tile level.
void setColorTable(const QVector< QRgb > colors)
MARBLE_EXPORT int levelToColumn(int levelZeroColumns, int level)
Get the maximum number of tile columns for a given tile level.
QString section(QChar sep, int start, int end, QFlags< QString::SectionFlag > flags) const
void setTileQuality(int quality)
void cancelTileCreation()
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QDebug mDebug()
a function to replace qDebug() in Marble library code
QImage scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const
void setResume(bool resume)
const int defaultLevelZeroRows