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 @@
AdvancedConfigPage00482300Cache:Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- Delete thumbnail cache folder on exit
+ Low resource usage modeQt::Horizontal4020
- 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.trueQt::VerticalQSizePolicy::Fixed2020History:Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenterRemember folders and URLsQt::Horizontal4020Qt::VerticalQSizePolicy::Fixed2020Rendering intent:Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenterrelativeRenderingIntentRadioButtonPerceptualtrueScale all colors equally to fit them within the active color profile's color gamuttrueQt::VerticalQSizePolicy::Fixed2010Relative ColorimetrictrueSquash colors that don't fit within the active color profile's color gamut, leaving other colors untouchedtrueQt::Vertical2020
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 ManualAurélienGâteauagateau@kde.orgChristopherMartinchrsmrtn@debian.orgHenryde Valencehdevalence@gmail.com2005Aurélien Gâteau2008Henry de Valence&FDLNotice;2018-10-14Applications 18.12&gwenview; is an image and video viewer.KDEimageviewerartistphotopictureIntroductionWhat 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 InterfaceStart PageThe start page lists recently opened folders and &URL;s on the left side,
and your places and tags on the right side.Start Page ScreenshotImage 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;REditRotate Right
or
&Ctrl;LEditRotate LeftEditMirror:
This operation will reflect the image along the vertical
axis, as if you were seeing it in a mirror.EditFlip:
This operation will reflect the image upside-down (a
reflection along the horizontal axis)&Shift;REditResize:
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 imagesIf 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 ModeWhen 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 OperationsShare: 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 ModeView 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 ScreenshotThe 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;CEditCrop:
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.
EditRed Eye Reduction:
This operation reduces the "red eye" effect commonly found in photographs taken
with a flash camera.
Full Screen ModesAccess Full Screen by pressing the Full Screen
button on the toolbar, or by
&Ctrl;&Shift;FViewFull Screen Mode.
To leave this mode press the &Esc; key.Browse Mode Full ScreenIn 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 ScreenshotGoing 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 ScreenThe 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 ScreenshotThe 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.SidebarThe 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
F4ViewSidebar
or using the ▮← / ▮→ button at the left side
of the statusbar. When clicked it collapses or expands the sidebar.
The sidebar contains several tabs:FoldersDisplays 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.InformationDisplays 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.OperationsThis 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; ImporterIntroductionThe &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 PickingIt 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 ScreenshotIf 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.TipsUsing the mousePanning with the mouseHolding 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 mouseClicking 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 mouseWhen 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 SettingsConfigure &gwenview;....
The configuration dialog is split into three sections. This chapter describes the available
options in detail.
GeneralImage ViewAdvancedGeneralVideosCheck the Show videos checkbox to allow &gwenview; to show videos among the images.Background colorMove 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 actionsWhether the thumbnail action buttons should be shown as overlays above image thumbnails.All buttons — Show all buttonsShow selection button only — Show select/unselect button onlyNone — Do not show any thumbnail buttonImage ViewShow transparency withChoose 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 behaviorSelect 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 modeAllows 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.AnimationsAllows 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 BarAllows configuring the thumbnail bar.OrientationHorizontal — 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 barAdvancedCache
- 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.HistoryCheck the Remember folders and URLs to make &gwenview; remember visited folders and &URL;s and show them on the Recent Folders pane.Rendering intentAllows choosing the rendering intent for showing images.Perceptual — scale all colors equally to fit them within the active color profile's color gamutRelative Colorimetric — squash colors that don't fit within the active color profile's color gamut, leaving other colors untouchedHidden 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âteauThis document was written by Christopher MartinThis 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();
}