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