File indexing completed on 2024-04-21 07:36:33

0001 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
0002 // SPDX-FileCopyrightText: 2007-2008 Inge Wallin <ingwa@kde.org>
0003 // SPDX-FileCopyrightText: 2011 Niko Sams <niko.sams@gmail.com>
0004 //
0005 // SPDX-License-Identifier: LGPL-2.1-or-later
0006 
0007 #include "TileCreator.h"
0008 
0009 #include <cmath>
0010 
0011 #include <QDir>
0012 #include <QRect>
0013 #include <QSize>
0014 #include <QVector>
0015 #include <QApplication>
0016 #include <QImage>
0017 #include <QPainter>
0018 
0019 #include "MarbleGlobal.h"
0020 #include "MarbleDirs.h"
0021 #include "MarbleDebug.h"
0022 #include "TileLoaderHelper.h"
0023 
0024 namespace Marble
0025 {
0026 
0027 class TileCreatorPrivate
0028 {
0029  public:
0030     TileCreatorPrivate( TileCreatorSource *source,
0031                         const QString& dem, const QString& targetDir=QString() )
0032        : m_dem( dem ),
0033          m_targetDir( targetDir ),
0034          m_cancelled( false ),
0035          m_tileFormat( "jpg" ),
0036          m_resume( false ),
0037          m_verify( false ),
0038          m_source( source )
0039      {
0040         if (m_dem == QLatin1String("true")) {
0041             m_tileQuality = 70;
0042         } else {
0043             m_tileQuality = 85;
0044         }
0045     }
0046 
0047     ~TileCreatorPrivate()
0048     {
0049         delete m_source;
0050     }
0051 
0052  public:
0053     QString  m_dem;
0054     QString  m_targetDir;
0055     bool     m_cancelled;
0056     QString  m_tileFormat;
0057     int      m_tileQuality;
0058     bool     m_resume;
0059     bool     m_verify;
0060 
0061     TileCreatorSource  *m_source;
0062 };
0063 
0064 class TileCreatorSourceImage : public TileCreatorSource
0065 {
0066 public:
0067     explicit TileCreatorSourceImage( const QString &sourcePath )
0068         : m_sourceImage( QImage( sourcePath ) ),
0069           m_cachedRowNum( -1 )
0070     {
0071     }
0072 
0073     QSize fullImageSize() const override
0074     {
0075         if ( m_sourceImage.size().width() > 21600 || m_sourceImage.height() > 10800 ) {
0076             qDebug("Install map too large!");
0077             return QSize();
0078         }
0079         return m_sourceImage.size();
0080     }
0081 
0082     QImage tile(int n, int m, int maxTileLevel) override
0083     {
0084         int  mmax = TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, maxTileLevel );
0085         int  nmax = TileLoaderHelper::levelToRow( defaultLevelZeroRows, maxTileLevel );
0086 
0087         int imageHeight = m_sourceImage.height();
0088         int imageWidth = m_sourceImage.width();
0089 
0090         // If the image size of the image source does not match the expected
0091         // geometry we need to smooth-scale the image in advance to match
0092         // the required size
0093         bool needsScaling = ( imageWidth != 2 * nmax * (int)( c_defaultTileSize )
0094                             ||  imageHeight != nmax * (int)( c_defaultTileSize ) );
0095 
0096         if ( needsScaling )
0097             mDebug() << "Image Size doesn't match 2*n*TILEWIDTH x n*TILEHEIGHT geometry. Scaling ...";
0098 
0099         int  stdImageWidth  = 2 * nmax * c_defaultTileSize;
0100         if ( stdImageWidth == 0 )
0101             stdImageWidth = 2 * c_defaultTileSize;
0102 
0103         int  stdImageHeight  = nmax * c_defaultTileSize;
0104         if ( stdImageWidth != imageWidth ) {
0105             mDebug() <<
0106             QString( "TileCreator::createTiles() The size of the final image will measure  %1 x %2 pixels").arg(stdImageWidth).arg(stdImageHeight);
0107         }
0108 
0109         QImage row;
0110 
0111         if ( m_cachedRowNum == n ) {
0112 
0113             row = m_rowCache;
0114 
0115         } else {
0116 
0117             QRect   sourceRowRect( 0, (int)( (qreal)( n * imageHeight ) / (qreal)( nmax )),
0118                                 imageWidth,(int)( (qreal)( imageHeight ) / (qreal)( nmax ) ) );
0119 
0120 
0121             row = m_sourceImage.copy( sourceRowRect );
0122 
0123             if ( needsScaling ) {
0124                 // Pick the current row and smooth scale it
0125                 // to make it match the expected size
0126                 QSize destSize( stdImageWidth, c_defaultTileSize );
0127                 row = row.scaled( destSize,
0128                                 Qt::IgnoreAspectRatio,
0129                                 Qt::SmoothTransformation );
0130             }
0131 
0132             m_cachedRowNum = n;
0133             m_rowCache = row;
0134         }
0135 
0136         if ( row.isNull() ) {
0137             mDebug() << "Read-Error! Null QImage!";
0138             return QImage();
0139         }
0140 
0141         QImage  tile = row.copy( m * stdImageWidth / mmax, 0, c_defaultTileSize, c_defaultTileSize );
0142 
0143         return tile;
0144     }
0145 
0146 private:
0147     QImage m_sourceImage;
0148 
0149     QImage m_rowCache;
0150     int m_cachedRowNum;
0151 };
0152 
0153 
0154 TileCreator::TileCreator(const QString& sourceDir, const QString& installMap,
0155                          const QString& dem, const QString& targetDir)
0156     : QThread(nullptr),
0157       d( new TileCreatorPrivate( nullptr, dem, targetDir ) )
0158 
0159 {
0160     mDebug() << "Prefix: " << sourceDir
0161         << "installmap:" << installMap;
0162 
0163     QString sourcePath;
0164 
0165     // If the sourceDir starts with a '/' assume an absolute path.
0166     // Otherwise assume a relative marble data path
0167     if ( QDir::isAbsolutePath( sourceDir ) ) {
0168         sourcePath = sourceDir + QLatin1Char('/') + installMap;
0169         mDebug() << "Trying absolute path*:" << sourcePath;
0170     }
0171     else {
0172         sourcePath = MarbleDirs::path(QLatin1String("maps/") + sourceDir + QLatin1Char('/') + installMap);
0173         mDebug() << "Trying relative path*:"
0174                 << QLatin1String("maps/") + sourceDir + QLatin1Char('/') + installMap;
0175     }
0176 
0177     mDebug() << "Creating tiles from*: " << sourcePath;
0178 
0179     d->m_source = new TileCreatorSourceImage( sourcePath );
0180 
0181     if ( d->m_targetDir.isNull() )
0182         d->m_targetDir = MarbleDirs::localPath() + QLatin1String("/maps/")
0183             + sourcePath.section(QLatin1Char('/'), -3, -2) + QLatin1Char('/');
0184 
0185     setTerminationEnabled( true );
0186 }
0187 
0188 TileCreator::TileCreator( TileCreatorSource* source, const QString& dem, const QString& targetDir )
0189     : QThread(nullptr),
0190       d( new TileCreatorPrivate( source, dem, targetDir ) )
0191 {
0192     setTerminationEnabled( true );
0193 }
0194 
0195 TileCreator::~TileCreator()
0196 {
0197     delete d;
0198 }
0199 
0200 void TileCreator::cancelTileCreation()
0201 {
0202     d->m_cancelled = true;
0203 }
0204 
0205 void TileCreator::run()
0206 {
0207     if (d->m_resume && d->m_tileFormat == QLatin1String("jpg") && d->m_tileQuality != 100) {
0208         qWarning() << "Resuming jpegs is only supported with tileQuality 100";
0209         return;
0210     }
0211 
0212     if (!d->m_targetDir.endsWith(QLatin1Char('/')))
0213         d->m_targetDir += QLatin1Char('/');
0214 
0215     mDebug() << "Installing tiles to: " << d->m_targetDir;
0216 
0217     QVector<QRgb> grayScalePalette;
0218     for ( int cnt = 0; cnt <= 255; ++cnt ) {
0219         grayScalePalette.insert(cnt, qRgb(cnt, cnt, cnt));
0220     }
0221 
0222     QSize fullImageSize = d->m_source->fullImageSize();
0223     int  imageWidth  = fullImageSize.width();
0224     int  imageHeight = fullImageSize.height();
0225 
0226     mDebug() << QString( "TileCreator::createTiles() image dimensions %1 x %2").arg(imageWidth).arg(imageHeight);
0227 
0228     if ( imageWidth < 1 || imageHeight < 1 ) {
0229         qDebug("Invalid imagemap!");
0230         return;
0231     }
0232 
0233     // Calculating Maximum Tile Level
0234     float approxMaxTileLevel = std::log( imageWidth / ( 2.0 * c_defaultTileSize ) ) / std::log( 2.0 );
0235 
0236     int  maxTileLevel = 0;
0237     if ( approxMaxTileLevel == int( approxMaxTileLevel ) )
0238         maxTileLevel = static_cast<int>( approxMaxTileLevel );
0239     else
0240         maxTileLevel = static_cast<int>( approxMaxTileLevel + 1 );
0241 
0242     if ( maxTileLevel < 0 ) {
0243         mDebug() 
0244         << QString( "TileCreator::createTiles(): Invalid Maximum Tile Level: %1" )
0245         .arg( maxTileLevel );
0246     }
0247     mDebug() << "Maximum Tile Level: " << maxTileLevel;
0248 
0249 
0250     if ( !QDir( d->m_targetDir ).exists() )
0251         ( QDir::root() ).mkpath( d->m_targetDir );
0252 
0253     // Counting total amount of tiles to be generated for the progressbar
0254     // to prevent compiler warnings this var should
0255     // match the type of maxTileLevel
0256     int  tileLevel      = 0;
0257     int  totalTileCount = 0;
0258 
0259     while ( tileLevel <= maxTileLevel ) {
0260         totalTileCount += ( TileLoaderHelper::levelToRow( defaultLevelZeroRows, tileLevel )
0261                             * TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, tileLevel ) );
0262         tileLevel++;
0263     }
0264 
0265     mDebug() << totalTileCount << " tiles to be created in total.";
0266 
0267     int  mmax = TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, maxTileLevel );
0268     int  nmax = TileLoaderHelper::levelToRow( defaultLevelZeroRows, maxTileLevel );
0269 
0270     // Loading each row at highest spatial resolution and cropping tiles
0271     int      percentCompleted = 0;
0272     int      createdTilesCount = 0;
0273     QString  tileName;
0274 
0275     // Creating directory structure for the highest level
0276     QString  dirName( d->m_targetDir
0277                       + QString("%1").arg(maxTileLevel) );
0278     if ( !QDir( dirName ).exists() ) 
0279         ( QDir::root() ).mkpath( dirName );
0280 
0281     for ( int n = 0; n < nmax; ++n ) {
0282         QString dirName( d->m_targetDir
0283                          + QString("%1/%2").arg(maxTileLevel).arg(n, tileDigits, 10, QLatin1Char('0')));
0284         if ( !QDir( dirName ).exists() ) 
0285             ( QDir::root() ).mkpath( dirName );
0286     }
0287 
0288     for ( int n = 0; n < nmax; ++n ) {
0289 
0290         for ( int m = 0; m < mmax; ++m ) {
0291 
0292             mDebug() << "** tile" << m << "x" << n;
0293 
0294             if ( d->m_cancelled ) 
0295                 return;
0296 
0297             tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
0298                                        .arg( maxTileLevel )
0299                                        .arg(n, tileDigits, 10, QLatin1Char('0'))
0300                                        .arg(m, tileDigits, 10, QLatin1Char('0'))
0301                                        .arg( d->m_tileFormat );
0302 
0303             if ( QFile::exists( tileName ) && d->m_resume ) {
0304 
0305                 //mDebug() << tileName << "exists already";
0306 
0307             } else {
0308 
0309                 QImage tile = d->m_source->tile( n, m, maxTileLevel );
0310 
0311                 if ( tile.isNull() ) {
0312                     mDebug() << "Read-Error! Null QImage!";
0313                     return;
0314                 }
0315 
0316                 if (d->m_dem == QLatin1String("true")) {
0317                     tile = tile.convertToFormat(QImage::Format_Indexed8,
0318                                                 grayScalePalette,
0319                                                 Qt::ThresholdDither);
0320                 }
0321 
0322                 bool  ok = tile.save(tileName, d->m_tileFormat.toLatin1().data(), d->m_tileFormat == QLatin1String("jpg") ? 100 : d->m_tileQuality);
0323                 if ( !ok )
0324                     mDebug() << "Error while writing Tile: " << tileName;
0325 
0326                 mDebug() << tileName << "size" << QFile( tileName ).size();
0327 
0328                 if ( d->m_verify ) {
0329                     QImage writtenTile(tileName);
0330                     Q_ASSERT( writtenTile.size() == tile.size() );
0331                     for ( int i=0; i < writtenTile.size().width(); ++i) {
0332                         for ( int j=0; j < writtenTile.size().height(); ++j) {
0333                             if ( writtenTile.pixel( i, j ) != tile.pixel( i, j ) ) {
0334                                 unsigned int  pixel = tile.pixel( i, j);
0335                                 unsigned int  writtenPixel = writtenTile.pixel( i, j);
0336                                 qWarning() << "***** pixel" << i << j << "is off by" << (pixel - writtenPixel) << "pixel" << pixel << "writtenPixel" << writtenPixel;
0337                                 QByteArray baPixel((char*)&pixel, sizeof(unsigned int));
0338                                 qWarning() << "pixel" << baPixel.size() << "0x" << baPixel.toHex();
0339                                 QByteArray baWrittenPixel((char*)&writtenPixel, sizeof(unsigned int));
0340                                 qWarning() << "writtenPixel" << baWrittenPixel.size() << "0x" << baWrittenPixel.toHex();
0341                                 Q_ASSERT(false);
0342                             }
0343                         }
0344                     }
0345                 }
0346 
0347             }
0348 
0349             percentCompleted =  (int) ( 90 * (qreal)(createdTilesCount) 
0350                                         / (qreal)(totalTileCount) );    
0351             createdTilesCount++;
0352 
0353             mDebug() << "percentCompleted" << percentCompleted;
0354             emit progress( percentCompleted );
0355         }
0356     }
0357 
0358     mDebug() << "tileLevel: " << maxTileLevel << " successfully created.";
0359 
0360     tileLevel = maxTileLevel;
0361 
0362     // Now that we have the tiles at the highest resolution lets build
0363     // them together four by four.
0364 
0365     while( tileLevel > 0 ) {
0366         tileLevel--;
0367 
0368         int  nmaxit =  TileLoaderHelper::levelToRow( defaultLevelZeroRows, tileLevel );
0369 
0370         for ( int n = 0; n < nmaxit; ++n ) {
0371             QString  dirName( d->m_targetDir
0372                               + QString("%1/%2")
0373                                   .arg(tileLevel)
0374                                   .arg(n, tileDigits, 10, QLatin1Char('0')));
0375 
0376             // mDebug() << "dirName: " << dirName;
0377             if ( !QDir( dirName ).exists() ) 
0378                 ( QDir::root() ).mkpath( dirName );
0379 
0380             int   mmaxit = TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, tileLevel );
0381             for ( int m = 0; m < mmaxit; ++m ) {
0382 
0383                 if ( d->m_cancelled )
0384                     return;
0385 
0386                 QString newTileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
0387                                            .arg( tileLevel )
0388                                            .arg(n, tileDigits, 10, QLatin1Char('0'))
0389                                            .arg(m, tileDigits, 10, QLatin1Char('0'))
0390                                            .arg( d->m_tileFormat );
0391 
0392                 if ( QFile::exists( newTileName ) && d->m_resume ) {
0393                     //mDebug() << newTileName << "exists already";
0394                 } else {
0395                     tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
0396                                             .arg( tileLevel + 1 )
0397                                             .arg(2*n, tileDigits, 10, QLatin1Char('0'))
0398                                             .arg(2*m, tileDigits, 10, QLatin1Char('0'))
0399                                             .arg( d->m_tileFormat );
0400                     QImage  img_topleft( tileName );
0401 
0402                     tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
0403                                             .arg( tileLevel + 1 )
0404                                             .arg(2*n, tileDigits, 10, QLatin1Char('0'))
0405                                             .arg(2*m+1, tileDigits, 10, QLatin1Char('0'))
0406                                             .arg( d->m_tileFormat );
0407                     QImage  img_topright( tileName );
0408 
0409                     tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
0410                                             .arg( tileLevel + 1 )
0411                                             .arg(2*n+1, tileDigits, 10, QLatin1Char('0'))
0412                                             .arg(2*m, tileDigits, 10, QLatin1Char('0'))
0413                                             .arg( d->m_tileFormat );
0414                     QImage  img_bottomleft( tileName );
0415 
0416                     tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
0417                                             .arg( tileLevel + 1 )
0418                                             .arg(2*n+1, tileDigits, 10, QLatin1Char('0'))
0419                                             .arg(2*m+1, tileDigits, 10, QLatin1Char('0'))
0420                                             .arg( d->m_tileFormat );
0421                     QImage  img_bottomright( tileName );
0422 
0423                     QSize const expectedSize( c_defaultTileSize, c_defaultTileSize );
0424                     if ( img_topleft.size() != expectedSize ||
0425                          img_topright.size() != expectedSize ||
0426                          img_bottomleft.size() != expectedSize ||
0427                          img_bottomright.size() != expectedSize ) {
0428                         mDebug() << "Tile write failure. Missing write permissions?";
0429                         emit progress( 100 );
0430                         return;
0431                     }
0432                     QImage  tile = img_topleft;
0433 
0434                     if (d->m_dem == QLatin1String("true")) {
0435 
0436                         tile.setColorTable( grayScalePalette );
0437                         uchar* destLine;
0438 
0439                         for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
0440                             destLine = tile.scanLine( y );
0441                             const uchar* srcLine = img_topleft.scanLine( 2 * y );
0442                             for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
0443                                 destLine[x] = srcLine[ 2*x ];
0444                         }
0445                         for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
0446                             destLine = tile.scanLine( y );
0447                             const uchar* srcLine = img_topright.scanLine( 2 * y );
0448                             for ( uint x = c_defaultTileSize / 2; x < c_defaultTileSize; ++x )
0449                                 destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
0450                         }
0451                         for ( uint y = c_defaultTileSize / 2; y < c_defaultTileSize; ++y ) {
0452                             destLine = tile.scanLine( y );
0453                             const uchar* srcLine = img_bottomleft.scanLine( 2 * ( y - c_defaultTileSize / 2 ) );
0454                             for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
0455                                 destLine[ x ] = srcLine[ 2 * x ];
0456                         }
0457                         for ( uint y = c_defaultTileSize / 2; y < c_defaultTileSize; ++y ) {
0458                             destLine = tile.scanLine( y );
0459                             const uchar* srcLine = img_bottomright.scanLine( 2 * ( y - c_defaultTileSize/2 ) );
0460                             for ( uint x = c_defaultTileSize / 2; x < c_defaultTileSize; ++x )
0461                                 destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
0462                         }
0463                     }
0464                     else {
0465 
0466                         // tile.depth() != 8
0467 
0468                         img_topleft = img_topleft.convertToFormat( QImage::Format_ARGB32 );
0469                         img_topright = img_topright.convertToFormat( QImage::Format_ARGB32 );
0470                         img_bottomleft = img_bottomleft.convertToFormat( QImage::Format_ARGB32 );
0471                         img_bottomright = img_bottomright.convertToFormat( QImage::Format_ARGB32 );
0472                         tile = img_topleft;
0473 
0474                         QRgb* destLine;
0475 
0476                         for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
0477                             destLine = (QRgb*) tile.scanLine( y );
0478                             const QRgb* srcLine = (QRgb*) img_topleft.scanLine( 2 * y );
0479                             for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
0480                                 destLine[x] = srcLine[ 2 * x ];
0481                         }
0482                         for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
0483                             destLine = (QRgb*) tile.scanLine( y );
0484                             const QRgb* srcLine = (QRgb*) img_topright.scanLine( 2 * y );
0485                             for ( uint x = c_defaultTileSize / 2; x < c_defaultTileSize; ++x )
0486                                 destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
0487                         }
0488                         for ( uint y = c_defaultTileSize / 2; y < c_defaultTileSize; ++y ) {
0489                             destLine = (QRgb*) tile.scanLine( y );
0490                             const QRgb* srcLine = (QRgb*) img_bottomleft.scanLine( 2 * ( y-c_defaultTileSize/2 ) );
0491                             for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
0492                                 destLine[x] = srcLine[ 2 * x ];
0493                         }
0494                         for ( uint y = c_defaultTileSize / 2; y < c_defaultTileSize; ++y ) {
0495                             destLine = (QRgb*) tile.scanLine( y );
0496                             const QRgb* srcLine = (QRgb*) img_bottomright.scanLine( 2 * ( y-c_defaultTileSize / 2 ) );
0497                             for ( uint x = c_defaultTileSize / 2; x < c_defaultTileSize; ++x )
0498                                 destLine[x] = srcLine[ 2*( x-c_defaultTileSize / 2 ) ];
0499                         }
0500                     }
0501 
0502                     mDebug() << newTileName;
0503 
0504                     // Saving at 100% JPEG quality to have a high-quality
0505                     // version to create the remaining needed tiles from.
0506                     bool  ok = tile.save(newTileName, d->m_tileFormat.toLatin1().data(), d->m_tileFormat == QLatin1String("jpg") ? 100 : d->m_tileQuality);
0507                     if ( ! ok )
0508                         mDebug() << "Error while writing Tile: " << newTileName;
0509                 }
0510 
0511                 percentCompleted =  (int) ( 90 * (qreal)(createdTilesCount)
0512                                             / (qreal)(totalTileCount) );    
0513                 createdTilesCount++;
0514                         
0515                 emit progress( percentCompleted );
0516                 mDebug() << "percentCompleted" << percentCompleted;
0517             }
0518         }
0519         mDebug() << "tileLevel: " << tileLevel << " successfully created.";
0520     }
0521     mDebug() << "Tile creation completed.";
0522 
0523     if (d->m_tileFormat == QLatin1String("jpg") && d->m_tileQuality != 100) {
0524 
0525         // Applying correct lower JPEG compression now that we created all tiles
0526         int savedTilesCount = 0;
0527 
0528         tileLevel = 0;
0529         while ( tileLevel <= maxTileLevel ) {
0530             int nmaxit =  TileLoaderHelper::levelToRow( defaultLevelZeroRows, tileLevel );
0531             for ( int n = 0; n < nmaxit; ++n) {
0532                 int mmaxit =  TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, tileLevel );
0533                 for ( int m = 0; m < mmaxit; ++m) {
0534 
0535                     if ( d->m_cancelled )
0536                         return;
0537 
0538                     savedTilesCount++;
0539 
0540                     tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
0541                                             .arg( tileLevel )
0542                                             .arg(n, tileDigits, 10, QLatin1Char('0'))
0543                                             .arg(m, tileDigits, 10, QLatin1Char('0'))
0544                                             .arg( d->m_tileFormat );
0545                     QImage tile( tileName );
0546 
0547                     bool ok;
0548 
0549                     ok = tile.save( tileName, d->m_tileFormat.toLatin1().data(), d->m_tileQuality );
0550 
0551                     if ( !ok )
0552                         mDebug() << "Error while writing Tile: " << tileName;
0553                     // Don't exceed 99% as this would cancel the thread unexpectedly
0554                     percentCompleted = 90 + (int)( 9 * (qreal)(savedTilesCount)
0555                                                 / (qreal)(totalTileCount) );
0556                     emit progress( percentCompleted );
0557                     mDebug() << "percentCompleted" << percentCompleted;
0558                     //mDebug() << "Saving Tile #" << savedTilesCount
0559                     //         << " of " << totalTileCount
0560                     //         << " Percent: " << percentCompleted;
0561                 }
0562             }
0563             tileLevel++;
0564         }
0565     }
0566 
0567     percentCompleted = 100;
0568     emit progress( percentCompleted );
0569 
0570     mDebug() << "percentCompleted: " << percentCompleted;
0571 }
0572 
0573 void TileCreator::setTileFormat(const QString& format)
0574 {
0575     d->m_tileFormat = format;
0576 }
0577 
0578 QString TileCreator::tileFormat() const
0579 {
0580     return d->m_tileFormat;
0581 }
0582 
0583 void TileCreator::setTileQuality(int quality)
0584 {
0585     d->m_tileQuality = quality;
0586 }
0587 
0588 int TileCreator::tileQuality() const
0589 {
0590     return d->m_tileQuality;
0591 }
0592 
0593 void TileCreator::setResume(bool resume)
0594 {
0595     d->m_resume = resume;
0596 }
0597 
0598 bool TileCreator::resume() const
0599 {
0600     return d->m_resume;
0601 }
0602 
0603 void TileCreator::setVerifyExactResult(bool verify)
0604 {
0605     d->m_verify = verify;
0606 }
0607 
0608 bool TileCreator::verifyExactResult() const
0609 {
0610     return d->m_verify;
0611 }
0612 
0613 
0614 }
0615 
0616 #include "moc_TileCreator.cpp"