diff --git a/app/advancedconfigpage.ui b/app/advancedconfigpage.ui index 096cef08..e6eb2515 100644 --- a/app/advancedconfigpage.ui +++ b/app/advancedconfigpage.ui @@ -1,218 +1,218 @@ AdvancedConfigPage 0 0 482 300 Cache: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - Delete thumbnail cache folder on exit + Low resource usage mode Qt::Horizontal 40 20 - Enable this option if you do not have a lot of disk space.<br/><br/><em>Be careful:</em> this will delete the folder named <filename>.thumbnails</filename> in your home folder, deleting all thumbnails previously generated by Gwenview and other applications. + Enable this option if you do not have a lot of disk space. This will avoid storing thumbnails on disk and will prefer embedded thumbnails of lower quality that are faster to load, if available.<br/><br/><em>Be careful:</em> this will delete the folder named <filename>.thumbnails</filename> in your home folder, deleting all thumbnails previously generated by Gwenview and other applications. true Qt::Vertical QSizePolicy::Fixed 20 20 History: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Remember folders and URLs Qt::Horizontal 40 20 Qt::Vertical QSizePolicy::Fixed 20 20 Rendering intent: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter relativeRenderingIntentRadioButton Perceptual true Scale all colors equally to fit them within the active color profile's color gamut true Qt::Vertical QSizePolicy::Fixed 20 10 Relative Colorimetric true Squash colors that don't fit within the active color profile's color gamut, leaving other colors untouched true Qt::Vertical 20 20 diff --git a/doc/index.docbook b/doc/index.docbook index ca7cde00..dc6d3bd3 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -1,907 +1,907 @@ ]> Gwenview User Manual Aurélien Gâteau
agateau@kde.org
ChristopherMartin
chrsmrtn@debian.org
Henry de Valence
hdevalence@gmail.com
2005 Aurélien Gâteau 2008 Henry de Valence &FDLNotice; 2018-10-14 Applications 18.12 &gwenview; is an image and video viewer. KDE image viewer artist photo picture
Introduction What is &gwenview; &gwenview; is a fast and easy to use image and video viewer. &gwenview; features two main modes: Browse and View. Both modes can be used in a normal application window and Full Screen. Browse Mode lets you navigate through your computer showing thumbnails of your images, View Mode lets you view images one at a time, and Full Screen lets you make quick slideshows. There is also a start screen that displays a list of recently opened folders and &URL;s as well as your places and tags. Image loading is handled by the &Qt; library, so &gwenview; supports all image formats your &Qt; installation supports. &gwenview; correctly displays images with an alpha channel (transparency) as well as animations. &gwenview; supports the displaying and editing of EXIF comments in JPEG images. Lossless JPEG transforms such as rotations and mirroring are also supported. &gwenview; can read embedded color profiles from PNG and JPEG files. It can use the image color profile together with the display color profile to output correct colors on the screen. The Interface Start Page The start page lists recently opened folders and &URL;s on the left side, and your places and tags on the right side. Start Page Screenshot Image Operations &gwenview; has a few features which are available in both Browse, View, and Full Screen view. &gwenview; has the capability to do basic alteration of your images. Rotate: A rotate operation will rotate the image either to the left or to the right, depending on whether you do &Ctrl;R Edit Rotate Right or &Ctrl;L Edit Rotate Left Edit Mirror : This operation will reflect the image along the vertical axis, as if you were seeing it in a mirror. Edit Flip : This operation will reflect the image upside-down (a reflection along the horizontal axis) &Shift;R Edit Resize : This operation will allow you to shrink or expand the image. Note that if you increase the size of an image, it may appear blurry and/or pixelated. These actions are also available on the Operations tab of the sidebar. If you have edited one or more images a bar with additional actions is displayed at the top of the image. You can undo or redo your changes, go to the previous or next modified image and there are three options to save the changed images. Actions bar for modified images If you have installed the KIPI Plugins, a Plugins menu will be available that will allow you to perform many additional operations on your images. Browse Mode When in Browse Mode, you can easily navigate through your files and folders. The preview window shows thumbnails of the images in the current folder, as well as subfolders. Browse Mode Screenshot Moving the mouse over an image shows buttons to select or rotate the image as well as a button to enter Fullscreen Mode. Modified images are indicated by an icon down right, click it to save the changed image. Clicking on an image takes you into View Mode. You may select multiple images and switch to View Mode to view them side-by-side. The slider at the bottom right allows you to change the size of the images. You can also filter the images by filename, date, tag or rating using the box on the lower left. The toolbar appears in both Browse mode as well as View mode and contains the most commonly used actions. Start Page: Open the start page. Browse: Switches to Browse Mode. View: Switches to View Mode. Full Screen: Switches to Full Screen Mode. Previous: Clicking this icon will go to the previous image in the folder. Next: Clicking this button will go to the next image in the folder. Rotate Left/Right: Same as discussed in Image Operations Share: Clicking this button opens an export menu to share your images through social media and image collection web services. This functionality depends on the list of installed KIPI plugins. View Mode View Mode displays full-size images. The same sidebar available in Browse Mode is displayed on the left. At the bottom, there is the Thumbnail Bar, which allows you to scroll through the images in the current folder. The Thumbnail Bar can be minimized by clicking on the Thumbnail Bar button. Clicking again will restore it. To change the size of the thumbnails move the splitter with the &LMB;. View Mode supports viewing multiple images side-by-side. You may select multiple images in Browse Mode before switching to View Mode, or you may click the + button that appears when hovering over images in the Thumbnail Bar to add a pane displaying that image. A - will then appear that will permit you to remove its pane. When multiple images are displayed, a small toolbar appears below each image that permits you to delete the image or remove its pane. You may perform zoom operations independently for each image, or synchronize them. Toggle this by checking the Synchronize to the left of the zoom slider or by pressing &Ctrl;Y. You can switch images by clicking on their pane, or using your keyboard. To switch to the image on the right, press . To switch to the image on the left, press &Shift; . View Mode Screenshot The slider at the bottom right controls the zoom of the image. The Fit, Fill and 100% buttons are next to the zoom slider and are three preset zoom levels. The Fit button zooms the current image to fit the size of the window, the Fill button zooms the image to fill the window by fitting width or height and the 100% button zooms the image to the actual pixel size. The shortcut F toggles between Fit mode and 100%, pressing &Shift;F will toggle Fill respectively. When an image is in zoom-to-fit mode, you can go to the previous and next image with the arrow keys. When you zoom in, arrow keys are used to scroll the image. This is very similar to the behavior provided by phones or digital cameras. When an image is zoomed in, a bird-eye view appears and lets you scroll the image using the mouse and the arrow keys. The bird-eye view automatically hides itself after a short delay, showing back only while zooming or scrolling. You can define what happens when going to image B after having zoomed in on an area of image A using the options in the Zoom mode group on the Image View page of the &gwenview; configuration window which can be reached using the SettingsConfigure &gwenview;.... If set to Autofit each image, image B is zoomed out to fit the screen. If set to Keep same zoom and position, all images share the same zoom and position: image B is set to the same zoom parameters as image A (and if these are changed, image A will then be displayed with the updated zoom and position). If set to Per image zoom and position, all images remember their own zoom and position: image B is initially set to the same zoom parameters as image A, but will then remember its own zoom and position (if these are changed, image A will not be displayed with the updated zoom and position). You can start directly in View mode by starting &gwenview; from a context menu like Open With in another program or by launching it from the command line with an image as an argument. The following additional image operations are available only in View Mode: &Shift;C Edit Crop : This operation lets you discard parts of the image you don't want. You can access the advanced cropping parameters by ticking Advanced settings check box on the bottom popup pane. Use the corresponding fields to tune up the cropping operation. It is also possible to adjust the cropped area by dragging the gray square handles on the borders of the image. You can move the cropped area by clicking and holding the &LMB; and drag it with the mouse pointer. Press the Crop button to see the results when you are ready. Use the upper popup pane to save the results or undo/redo the operation. Edit Red Eye Reduction : This operation reduces the "red eye" effect commonly found in photographs taken with a flash camera. Full Screen Modes Access Full Screen by pressing the Full Screen button on the toolbar, or by &Ctrl;&Shift;F View Full Screen Mode . To leave this mode press the &Esc; key. Browse Mode Full Screen In Browse Mode you can switch to fullscreen also by clicking on the button that appears when you move the mouse over the thumbnails. Full Screen View Mode Screenshot Going fullscreen while browsing gives you a more immersive experience while you go through your pictures. It is quite nice on your regular computer, but makes even more sense when you connect your laptop to the big TV in the living room to show pictures to your guests. View Mode Full Screen The full screen View Mode shows a slideshow of your images. Access Full Screen Mode by clicking on the button that appears when you move the mouse over the thumbnails in Browse Mode, by pressing the Full Screen button on the taskbar. Full Screen Browse Mode Screenshot The top bar will hide itself automatically; to show it simply move the mouse to the top of the screen. If the mouse cursor is over the top bar, it will not autohide. Most of the buttons on the bar are the same as the ones on the toolbar in Browse or View Modes, except for the Exit Full Screen Mode button which returns you to the &gwenview; window, the Pause/Resume Slideshow button, and the Configure Full Screen Mode button which shows a small settings dialog that allows you to easily and quickly configure the slideshow. The slideshow controls there are: The Interval slider controls how long &gwenview; will show an image before it move to the next one. If the Loop check box is checked, when the end of the slideshow is reached, it will continue from the beginning instead of stopping. If the Random check box is checked, instead of progressing through the folder alphabetically, images will be shown in random order. Select Image Information to Display allows you to define what metadata is displayed under the buttons on the toolbar. If the Show thumbnails check box is checked, thumbnails for all images in the current folder will be displayed to the right of the toolbar. The Height slider changes the size of the thumbnails displayed. If enabled, an area that shows you the other images in the current folder will be shown on the top bar. Clicking on one will display it. Sidebar The sidebar on the left is available in the Browse and View modes, but does not appear by default in Browse Mode. Its appearance can be toggled using F4 View Sidebar or using the ▮← / ▮→ button at the left side of the statusbar. When clicked it collapses or expands the sidebar. The sidebar contains several tabs: Folders Displays a list of all folders on your system permitting you to switch between them. In Browse Mode thumbnails from the folder will be displayed, while in View Mode the first image in the folder will appear, from which you can browse through the folder using the Previous and Next buttons or shortcuts. Clicking on a folder multiple times toggles between View Mode and Browse Mode. Information Displays Meta Information like the filename and size. The More... link permits you to view all available metadata and select which data appear in the sidebar. Operations This permits you to perform the previously described global image operations as well as those specific to View Mode. It also permits common file operations like copying, renaming, deleting, and creating new folders. &gwenview; Importer Introduction The &gwenview; Importer allows you to import images from a digital camera or removable media. To launch it, select Download Photos with &gwenview; in the &kde; Device Notifier after connecting a supported device. When you plug in a device the &gwenview; importer recursively lists all images and videos. This is not always what you expect, ⪚ plugging a smartphone you do not want to list all medias of the device; but only the pictures you took, which are usually in a special subfolder. Root Folder Picking It is possible to select the root folder to list, and &gwenview; Importer will remember the last root folder for each device. This way, next time you plug a device in, only the relevant pictures and videos should be listed. Importing Images &gwenview; Importer Screenshot If you wish, you may select the images you want to import under Select the documents to import by pressing the + button that appears when hovering over an image. You may also select the folder that images are imported to in the text box at the bottom of the window. When you are done, click the Import Selected button to import only the images you have selected, or click Import All to import all images found on the device. Automatic Renaming &gwenview; Importer can rename your files according to a specified pattern. To configure this, select the Settings in the lower left corner. You may turn this feature on or off using the check box at the top. The Rename Format supports several special parameters, which will be replaced by metadata such as the date the image was created or its filename. They are listed below the text box. You may either click on the parameter name to enter it into the text box or type one manually. Tips Using the mouse Panning with the mouse Holding down the left mouse button on an image allows you to scroll the image. The mouse wheel will scroll the image up and down. Zooming with the mouse Clicking the middle mouse button will toggle the Fit zoom button. Hold down the &Shift; key and middle-click to toggle the Fill zoom button. Hold down the &Ctrl; key, then either use the mouse wheel to zoom in and out or left click to zoom in and right click to zoom out. The mouse wheel, used while holding down the &Alt; key, will scroll the image horizontally. Browsing with the mouse When in Browse mode, clicking an image switches into View mode and shows that image. When in Browse mode, scrolling the mouse wheel will scroll up or down the thumbnail view area. If the Mouse wheel behavior option in SettingsConfigure &gwenview; is set to Browse, scrolling the mouse wheel while in View Mode will move you through the images in the folder. Key bindings &gwenview; comes with a range of keyboard shortcuts, all of which can be viewed and remapped by selecting SettingsConfigure Shortcuts.... Note that in the Files and Folders windows, all the normal &plasma; shortcuts are functional, unless otherwise remapped. A few of the most useful default bindings are: Space: Displays the next image in the directory. &Backspace;: Displays the previous image in the directory. &Alt;Up: Moves to the parent folder of the current folder. &Ctrl;&Shift;F: Switches into Full Screen Mode. &Esc;: Switches back to Browse Mode. &Ctrl;M: Show or hide the menubar. &Ctrl;B: Show or hide the Thumbnail bar. F4: Show or hide the Sidebar. F6: Make the Location bar editable so that you can directly type in a file path. You can return to the standard Location Bar by pressing the arrow at the right. &Ctrl;R: Rotate the current image to the right. &Ctrl;L: Rotate the current image to the left. &Shift;R: Resize the current image. &Shift;C: Crop the current image. &Ctrl;Y: When multiple images are displayed in View Mode, this synchronizes their views. &Ctrl;S: Save any changes made to the image. Del: Move the current image to the trash. &Shift;Del: Permanently delete the image from the disk. Note that this operation is irreversible and cannot be undone. &Ctrl;P: Print the current image. &Ctrl;O: Open an image using the standard file selection dialog. F: Pressing this shortcut toggles zoom-to-fit on and off. P: Viewing a video this shortcut toggles playback on and off. &Ctrl;T: Edit tags. F2: Rename an image inline. Del: Move an image to the trash. &Shift;Del: Delete an image. &Ctrl;F7: Copy an image. &Ctrl;F8: Move an image. &Ctrl;F9: Link an image. Configuring &gwenview; Configuration overview You can configure &gwenview; by choosing Settings Configure &gwenview;.... The configuration dialog is split into three sections. This chapter describes the available options in detail. General Image View Advanced General Videos Check the Show videos checkbox to allow &gwenview; to show videos among the images. Background color Move the slider to change the color of the gray background in Browse and View mode from black (the leftmost position) to white (the rightmost position). Thumbnail actions Whether the thumbnail action buttons should be shown as overlays above image thumbnails. All buttons — Show all buttons Show selection button only — Show select/unselect button only None — Do not show any thumbnail button Image View Show transparency with Choose how the background of transparent raster or SVG images is rendered. Surrounding background — Use background color from the General page. Checkerboard background — Use the traditional checkerboard background. Solid color background — Use a color that can be chosen using the color selector. Mouse wheel behavior Select how scrolling over an image in View mode behaves. Scroll — When zoomed in, pan the image vertically. Otherwise, nothing will happen. Browse — Switch to the next or the previous image. Zoom — Use mouse wheel to zoom in/out the current image. Zoom mode Allows choosing how zooming in View mode works. Autofit each image — Automatically resize images to the view pane. Keep same zoom and position — Use the same zoom level for all images. Per image zoom and position — Use individual zoom levels for each image. Enlarge smaller images — check this item to make &gwenview; enlarge smaller images in View mode. Animations Allows choosing how fading between images is done in View mode. OpenGL — Use hardware accelerated animations. Software — Do not use hardware accelerated animations. Select this option if OpenGL does not work satisfactory, but you still want to fade between images. None — Do not use animations when switching between images. Thumbnail Bar Allows configuring the thumbnail bar. Orientation Horizontal — Show a horizontal thumbnail strip below the image. Vertical — Show a vertical thumbnail strip to the right of the image. Row count — Use the spin box to change the number of rows on the thumbnail bar Advanced Cache - Enable the Delete thumbnail cache folder on exit option if you do not have a lot of disk space. + Enable the Low resource usage mode option if you do not have a lot of disk space. This will avoid storing thumbnails on disk and will prefer embedded thumbnails of lower quality that are faster to load, if available. Be careful: This will delete the folder named .thumbnails in your home folder, deleting all thumbnails previously generated by &gwenview; and other applications. History Check the Remember folders and URLs to make &gwenview; remember visited folders and &URL;s and show them on the Recent Folders pane. Rendering intent Allows choosing the rendering intent for showing images. Perceptual — scale all colors equally to fit them within the active color profile's color gamut Relative Colorimetric — squash colors that don't fit within the active color profile's color gamut, leaving other colors untouched Hidden Configuration Options Some notes on hidden &gwenview; options can be found on this page. The options described on the above-mentioned page may help you tune &gwenview; for specific needs, but please keep in mind there is no warranty they will continue working from one version to another. Credits and Copyright &gwenview; is currently maintained by Aurélien Gâteau This document was written by Christopher Martin This document was updated for &kde; 4 by Henry de Valence &underFDL; &underGPL;
diff --git a/lib/thumbnailprovider/thumbnailgenerator.cpp b/lib/thumbnailprovider/thumbnailgenerator.cpp index 26402cf2..de2061d1 100644 --- a/lib/thumbnailprovider/thumbnailgenerator.cpp +++ b/lib/thumbnailprovider/thumbnailgenerator.cpp @@ -1,304 +1,308 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2012 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "thumbnailgenerator.h" // Local #include "jpegcontent.h" #include "gwenviewconfig.h" #include "exiv2imageloader.h" // KDE #include #ifdef KDCRAW_FOUND #include #endif // Qt #include #include #include namespace Gwenview { #undef ENABLE_LOG #undef LOG //#define ENABLE_LOG #ifdef ENABLE_LOG #define LOG(x) //qDebug() << x #else #define LOG(x) ; #endif //------------------------------------------------------------------------ // // ThumbnailContext // //------------------------------------------------------------------------ bool ThumbnailContext::load(const QString &pixPath, int pixelSize) { mImage = QImage(); mNeedCaching = true; QImage originalImage; QSize originalSize; QByteArray formatHint = pixPath.section(QLatin1Char('.'), -1).toLocal8Bit().toLower(); QImageReader reader(pixPath); JpegContent content; QByteArray format; QByteArray data; QBuffer buffer; int previewRatio = 1; #ifdef KDCRAW_FOUND // raw images deserve special treatment if (KDcrawIface::KDcraw::rawFilesList().contains(QString::fromLatin1(formatHint))) { // use KDCraw to extract the preview bool ret = KDcrawIface::KDcraw::loadEmbeddedPreview(data, pixPath); // We need QImage. Loading JpegContent from QImage - exif lost // Loading QImage from JpegContent - unimplemented, would go with loadFromData if (!ret) { // if the embedded preview loading failed, load half preview instead. That's slower... if (!KDcrawIface::KDcraw::loadHalfPreview(data, pixPath)) { qWarning() << "unable to get preview for " << pixPath.toUtf8().constData(); return false; } previewRatio = 2; } // And we need JpegContent too because of EXIF (orientation!). if (!content.loadFromData(data)) { qWarning() << "unable to load preview for " << pixPath.toUtf8().constData(); return false; } buffer.setBuffer(&data); buffer.open(QIODevice::ReadOnly); reader.setDevice(&buffer); reader.setFormat(formatHint); } else { #else { #endif if (!reader.canRead()) { reader.setDecideFormatFromContent(true); // Set filename again, otherwise QImageReader won't restart from scratch reader.setFileName(pixPath); } if (reader.format() == "jpeg" && GwenviewConfig::applyExifOrientation()) { content.load(pixPath); } } // If there's jpeg content (from jpg or raw files), try to load an embedded thumbnail, if available. if (!content.rawData().isEmpty()) { QImage thumbnail = content.thumbnail(); - if (qMax(thumbnail.width(), thumbnail.height()) >= pixelSize) { + // If the user does not care about the generated thumbnails (by deleting them on exit), use ANY + // embedded thumnail, even if it's too small. + if (!thumbnail.isNull() && + (GwenviewConfig::deleteThumbnailCacheOnExit() || qMax(thumbnail.width(), thumbnail.height()) >= pixelSize) + ) { mImage = std::move(thumbnail); mOriginalWidth = content.size().width(); mOriginalHeight = content.size().height(); return true; } } // Generate thumbnail from full image originalSize = reader.size(); if (originalSize.isValid() && reader.supportsOption(QImageIOHandler::ScaledSize) && qMax(originalSize.width(), originalSize.height()) >= pixelSize) { QSizeF scaledSize = originalSize; scaledSize.scale(pixelSize, pixelSize, Qt::KeepAspectRatio); if (!scaledSize.isEmpty()) { reader.setScaledSize(scaledSize.toSize()); } } // Rotate if necessary if (GwenviewConfig::applyExifOrientation()) { reader.setAutoTransform(true); } // format() is empty after QImageReader::read() is called format = reader.format(); if (!reader.read(&originalImage)) { return false; } if (!originalSize.isValid()) { originalSize = originalImage.size(); } mOriginalWidth = originalSize.width() * previewRatio; mOriginalHeight = originalSize.height() * previewRatio; if (qMax(mOriginalWidth, mOriginalHeight) <= pixelSize) { mImage = originalImage; mNeedCaching = format != "png"; } else { mImage = originalImage.scaled(pixelSize, pixelSize, Qt::KeepAspectRatio); } if (reader.autoTransform() && (reader.transformation() & QImageIOHandler::TransformationRotate90)) { qSwap(mOriginalWidth, mOriginalHeight); } return true; } //------------------------------------------------------------------------ // // ThumbnailGenerator // //------------------------------------------------------------------------ ThumbnailGenerator::ThumbnailGenerator() : mCancel(false) {} void ThumbnailGenerator::load( const QString& originalUri, time_t originalTime, KIO::filesize_t originalFileSize, const QString& originalMimeType, const QString& pixPath, const QString& thumbnailPath, ThumbnailGroup::Enum group) { QMutexLocker lock(&mMutex); Q_ASSERT(mPixPath.isNull()); mOriginalUri = originalUri; mOriginalTime = originalTime; mOriginalFileSize = originalFileSize; mOriginalMimeType = originalMimeType; mPixPath = pixPath; mThumbnailPath = thumbnailPath; mThumbnailGroup = group; if (!isRunning()) start(); mCond.wakeOne(); } QString ThumbnailGenerator::originalUri() const { return mOriginalUri; } time_t ThumbnailGenerator::originalTime() const { return mOriginalTime; } KIO::filesize_t ThumbnailGenerator::originalFileSize() const { return mOriginalFileSize; } QString ThumbnailGenerator::originalMimeType() const { return mOriginalMimeType; } bool ThumbnailGenerator::testCancel() { QMutexLocker lock(&mMutex); return mCancel; } void ThumbnailGenerator::cancel() { QMutexLocker lock(&mMutex); mCancel = true; mCond.wakeOne(); } void ThumbnailGenerator::run() { LOG(""); while (!testCancel()) { QString pixPath; int pixelSize; { QMutexLocker lock(&mMutex); // empty mPixPath means nothing to do LOG("Waiting for mPixPath"); if (mPixPath.isNull()) { LOG("mPixPath.isNull"); mCond.wait(&mMutex); } } if (testCancel()) { return; } { QMutexLocker lock(&mMutex); pixPath = mPixPath; pixelSize = ThumbnailGroup::pixelSize(mThumbnailGroup); } Q_ASSERT(!pixPath.isNull()); LOG("Loading" << pixPath); ThumbnailContext context; bool ok = context.load(pixPath, pixelSize); { QMutexLocker lock(&mMutex); if (ok) { mImage = context.mImage; mOriginalWidth = context.mOriginalWidth; mOriginalHeight = context.mOriginalHeight; if (context.mNeedCaching && mThumbnailGroup <= ThumbnailGroup::Large) { cacheThumbnail(); } } else { // avoid emitting the thumb from the previous successful run mImage = QImage(); qWarning() << "Could not generate thumbnail for file" << mOriginalUri; } mPixPath.clear(); // done, ready for next } if (testCancel()) { return; } { QSize size(mOriginalWidth, mOriginalHeight); LOG("emitting done signal, size=" << size); QMutexLocker lock(&mMutex); emit done(mImage, size); LOG("Done"); } } LOG("Ending thread"); } void ThumbnailGenerator::cacheThumbnail() { mImage.setText(QStringLiteral("Thumb::URI") , mOriginalUri); mImage.setText(QStringLiteral("Thumb::MTime") , QString::number(mOriginalTime)); mImage.setText(QStringLiteral("Thumb::Size") , QString::number(mOriginalFileSize)); mImage.setText(QStringLiteral("Thumb::Mimetype") , mOriginalMimeType); mImage.setText(QStringLiteral("Thumb::Image::Width") , QString::number(mOriginalWidth)); mImage.setText(QStringLiteral("Thumb::Image::Height"), QString::number(mOriginalHeight)); mImage.setText(QStringLiteral("Software") , QStringLiteral("Gwenview")); emit thumbnailReadyToBeCached(mThumbnailPath, mImage); } } // namespace diff --git a/tests/auto/thumbnailprovidertest.cpp b/tests/auto/thumbnailprovidertest.cpp index 958165eb..cb895c54 100644 --- a/tests/auto/thumbnailprovidertest.cpp +++ b/tests/auto/thumbnailprovidertest.cpp @@ -1,278 +1,284 @@ /* Gwenview: an image viewer Copyright 2007 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "thumbnailprovidertest.h" // Qt #include #include #include #include // KDE #include #include #include #include // Local #include "../lib/thumbnailprovider/thumbnailprovider.h" #include "testutils.h" +#include "gwenviewconfig.h" // libc #include #include using namespace Gwenview; QTEST_MAIN(ThumbnailProviderTest) SandBox::SandBox() : mPath(QDir::currentPath() + "/sandbox") {} void SandBox::initDir() { KIO::Job* job; QDir dir(mPath); if (dir.exists()) { QUrl sandBoxUrl("file://" + mPath); job = KIO::del(sandBoxUrl); QVERIFY2(job->exec(), "Couldn't delete sandbox"); } dir.mkpath("."); } void SandBox::fill() { initDir(); createTestImage("red.png", 300, 200, Qt::red); createTestImage("blue.png", 200, 300, Qt::blue); createTestImage("small.png", 50, 50, Qt::green); copyTestImage("orient6.jpg", 128, 256); copyTestImage("orient6-small.jpg", 32, 64); } void SandBox::copyTestImage(const QString& testFileName, int width, int height) { QUrl testPath = urlForTestFile(testFileName); QUrl testDest = QUrl("file://" + mPath + '/' + testFileName); KIO::Job* job = KIO::copy(testPath, testDest); QVERIFY2(job->exec(), "Couldn't copy test image"); mSizeHash.insert(testFileName, QSize(width, height)); } static QImage createColoredImage(int width, int height, const QColor& color) { QImage image(width, height, QImage::Format_RGB32); QPainter painter(&image); painter.fillRect(image.rect(), color); return image; } void SandBox::createTestImage(const QString& name, int width, int height, const QColor& color) { QImage image = createColoredImage(width, height, color); image.save(mPath + '/' + name, "png"); mSizeHash.insert(name, QSize(width, height)); } void ThumbnailProviderTest::initTestCase() { qRegisterMetaType("KFileItem"); } void ThumbnailProviderTest::init() { ThumbnailProvider::setThumbnailBaseDir(mSandBox.mPath + "/thumbnails/"); mSandBox.fill(); } static void syncRun(ThumbnailProvider *provider) { QEventLoop loop; QObject::connect(provider, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); } void ThumbnailProviderTest::testLoadLocal() { QDir dir(mSandBox.mPath); // Create a list of items which will be thumbnailed KFileItemList list; Q_FOREACH(const QFileInfo & info, dir.entryInfoList(QDir::Files)) { QUrl url("file://" + info.absoluteFilePath()); KFileItem item(url); list << item; } // Generate the thumbnails ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Normal); provider.appendItems(list); QSignalSpy spy(&provider, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize,qulonglong))); syncRun(&provider); while (!ThumbnailProvider::isThumbnailWriterEmpty()) { QTest::qWait(100); } // Check we generated the correct number of thumbnails QDir thumbnailDir = ThumbnailProvider::thumbnailBaseDir(ThumbnailGroup::Normal); // There should be one file less because small.png is a png and is too // small to have a thumbnail QStringList entryList = thumbnailDir.entryList(QStringList("*.png")); QCOMPARE(entryList.count(), mSandBox.mSizeHash.size() - 1); // Check thumbnail keys QHash > thumbnailHash; Q_FOREACH(const QString& name, entryList) { QImage thumb; QVERIFY(thumb.load(thumbnailDir.filePath(name))); QUrl url(thumb.text("Thumb::URI")); KFileItem item = list.findByUrl(url); QVERIFY(!item.isNull()); QSize originalSize = mSandBox.mSizeHash.value(item.url().fileName()); uint mtime = item.time(KFileItem::ModificationTime).toTime_t(); if (mtime == uint(-1)) { // This happens from time to time on build.kde.org, but I haven't // been able to reproduce it locally, so let's try to gather more // information. qWarning() << "mtime == -1 for url" << url << ". This should not happen!"; qWarning() << "errno:" << errno << "message:" << strerror(errno); qWarning() << "QFile::exists(" << url.toLocalFile() << "):" << QFile::exists(url.toLocalFile()); qWarning() << "Recalculating mtime" << item.time(KFileItem::ModificationTime).toTime_t(); QFAIL("Invalid time for test KFileItem"); } QCOMPARE(thumb.text("Thumb::Image::Width"), QString::number(originalSize.width())); QCOMPARE(thumb.text("Thumb::Image::Height"), QString::number(originalSize.height())); QCOMPARE(thumb.text("Thumb::Mimetype"), item.mimetype()); QCOMPARE(thumb.text("Thumb::Size"), QString::number(item.size())); QCOMPARE(thumb.text("Thumb::MTime"), QString::number(mtime)); } // Check what was in the thumbnailLoaded() signals QCOMPARE(spy.count(), mSandBox.mSizeHash.size()); QSignalSpy::ConstIterator it = spy.constBegin(), end = spy.constEnd(); for (; it != end; ++it) { const QVariantList args = *it; const KFileItem item = qvariant_cast(args.at(0)); const QSize size = args.at(2).toSize(); const QSize expectedSize = mSandBox.mSizeHash.value(item.url().fileName()); QCOMPARE(size, expectedSize); } } void ThumbnailProviderTest::testUseEmbeddedOrNot() { QImage expectedThumbnail; QPixmap thumbnailPix; SandBox sandBox; sandBox.initDir(); // This image is red (0xfe0000) and 256x128 but contains a white 128x64 thumbnail sandBox.copyTestImage("embedded-thumbnail.jpg", 256, 128); KFileItemList list; QUrl url("file://" + QDir(sandBox.mPath).absoluteFilePath("embedded-thumbnail.jpg")); list << KFileItem(url); // Loading a normal thumbnail should bring the white one { ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Normal); provider.appendItems(list); QSignalSpy spy(&provider, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize,qulonglong))); syncRun(&provider); QCOMPARE(spy.count(), 1); expectedThumbnail = createColoredImage(128, 64, Qt::white); thumbnailPix = qvariant_cast(spy.at(0).at(1)); QVERIFY(TestUtils::imageCompare(expectedThumbnail, thumbnailPix.toImage())); } - // Loading a large thumbnail should bring the red one + // Loading a large thumbnail should bring the red one, unless thumbnails are deleted on exit, + // which should bring the white one { ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Large); provider.appendItems(list); QSignalSpy spy(&provider, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize,qulonglong))); syncRun(&provider); QCOMPARE(spy.count(), 1); - expectedThumbnail = createColoredImage(256, 128, QColor(254, 0, 0)); + if (GwenviewConfig::deleteThumbnailCacheOnExit()) { + expectedThumbnail = createColoredImage(128, 64, Qt::white); + } else { + expectedThumbnail = createColoredImage(256, 128, QColor(254, 0, 0)); + } thumbnailPix = qvariant_cast(spy.at(0).at(1)); QVERIFY(TestUtils::imageCompare(expectedThumbnail, thumbnailPix.toImage())); } } void ThumbnailProviderTest::testLoadRemote() { QUrl url = setUpRemoteTestDir("test.png"); if (!url.isValid()) { QSKIP("Not running this test: failed to setup remote test dir."); } url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + "test.png"); KFileItemList list; KFileItem item(url); list << item; ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Normal); provider.appendItems(list); syncRun(&provider); while (!ThumbnailProvider::isThumbnailWriterEmpty()) { QTest::qWait(100); } QDir thumbnailDir = ThumbnailProvider::thumbnailBaseDir(ThumbnailGroup::Normal); QStringList entryList = thumbnailDir.entryList(QStringList("*.png")); QCOMPARE(entryList.count(), 1); } void ThumbnailProviderTest::testRemoveItemsWhileGenerating() { QDir dir(mSandBox.mPath); // Create a list of items which will be thumbnailed KFileItemList list; Q_FOREACH(const QFileInfo & info, dir.entryInfoList(QDir::Files)) { QUrl url("file://" + info.absoluteFilePath()); KFileItem item(url); list << item; } // Start generating thumbnails for items ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Normal); provider.appendItems(list); QEventLoop loop; connect(&provider, SIGNAL(finished()), &loop, SLOT(quit())); // Remove items, it should not crash provider.removeItems(list); loop.exec(); }