qTox  Version: nightly | Commit: bc751c8e1cac455f9690654fcfe0f560d2d7dfdd
imagepreviewwidget.cpp
Go to the documentation of this file.
1 /*
2  Copyright © 2020 by The qTox Project Contributors
3 
4  This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6  qTox is libre software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  qTox is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "imagepreviewwidget.h"
22 
23 #include <QFile>
24 #include <QFileInfo>
25 #include <QString>
26 #include <QApplication>
27 #include <QDesktopWidget>
28 #include <QBuffer>
29 
30 namespace
31 {
32 QPixmap pixmapFromFile(const QString& filename)
33 {
34  static const QStringList previewExtensions = {"png", "jpeg", "jpg", "gif", "svg",
35  "PNG", "JPEG", "JPG", "GIF", "SVG"};
36 
37  if (!previewExtensions.contains(QFileInfo(filename).suffix())) {
38  return QPixmap();
39  }
40 
41  QFile imageFile(filename);
42  if (!imageFile.open(QIODevice::ReadOnly)) {
43  return QPixmap();
44  }
45 
46  const QByteArray imageFileData = imageFile.readAll();
47  QImage image = QImage::fromData(imageFileData);
48  auto orientation = ExifTransform::getOrientation(imageFileData);
49  image = ExifTransform::applyTransformation(image, orientation);
50 
51  return QPixmap::fromImage(image);
52 }
53 
54 QPixmap scaleCropIntoSquare(const QPixmap& source, const int targetSize)
55 {
56  QPixmap result;
57 
58  // Make sure smaller-than-icon images (at least one dimension is smaller) will not be
59  // upscaled
60  if (source.width() < targetSize || source.height() < targetSize) {
61  result = source;
62  } else {
63  result = source.scaled(targetSize, targetSize, Qt::KeepAspectRatioByExpanding,
64  Qt::SmoothTransformation);
65  }
66 
67  // Then, image has to be cropped (if needed) so it will not overflow rectangle
68  // Only one dimension will be bigger after Qt::KeepAspectRatioByExpanding
69  if (result.width() > targetSize) {
70  return result.copy((result.width() - targetSize) / 2, 0, targetSize, targetSize);
71  } else if (result.height() > targetSize) {
72  return result.copy(0, (result.height() - targetSize) / 2, targetSize, targetSize);
73  }
74 
75  // Picture was rectangle in the first place, no cropping
76  return result;
77 }
78 
79 QString getToolTipDisplayingImage(const QPixmap& image)
80 {
81  // Show mouseover preview, but make sure it's not larger than 50% of the screen
82  // width/height
83  const QRect desktopSize = QApplication::desktop()->geometry();
84  const int maxPreviewWidth{desktopSize.width() / 2};
85  const int maxPreviewHeight{desktopSize.height() / 2};
86  const QPixmap previewImage = [&image, maxPreviewWidth, maxPreviewHeight]() {
87  if (image.width() > maxPreviewWidth || image.height() > maxPreviewHeight) {
88  return image.scaled(maxPreviewWidth, maxPreviewHeight, Qt::KeepAspectRatio,
89  Qt::SmoothTransformation);
90  } else {
91  return image;
92  }
93  }();
94 
95  QByteArray imageData;
96  QBuffer buffer(&imageData);
97  buffer.open(QIODevice::WriteOnly);
98  previewImage.save(&buffer, "PNG");
99  buffer.close();
100 
101  return "<img src=data:image/png;base64," + imageData.toBase64() + "/>";
102 }
103 
104 } // namespace
105 
107 
108 void ImagePreviewButton::initialize(const QPixmap& image)
109 {
110  auto desiredSize = qMin(width(), height()); // Assume widget is a square
111  desiredSize = qMax(desiredSize, 4) - 4; // Leave some room for a border
112 
113  auto croppedImage = scaleCropIntoSquare(image, desiredSize);
114  setIcon(QIcon(croppedImage));
115  setIconSize(croppedImage.size());
116  setToolTip(getToolTipDisplayingImage(image));
117 }
118 
119 void ImagePreviewButton::setIconFromFile(const QString& filename)
120 {
121  initialize(pixmapFromFile(filename));
122 }
123 
124 void ImagePreviewButton::setIconFromPixmap(const QPixmap& pixmap)
125 {
126  initialize(pixmap);
127 }
ExifTransform::applyTransformation
QImage applyTransformation(QImage image, Orientation orientation)
Definition: exiftransform.cpp:73
imagepreviewwidget.h
ExifTransform::getOrientation
Orientation getOrientation(QByteArray imageData)
Definition: exiftransform.cpp:28
ImagePreviewButton::setIconFromPixmap
void setIconFromPixmap(const QPixmap &image)
Definition: imagepreviewwidget.cpp:124
exiftransform.h
ImagePreviewButton::setIconFromFile
void setIconFromFile(const QString &filename)
Definition: imagepreviewwidget.cpp:119
ImagePreviewButton::~ImagePreviewButton
~ImagePreviewButton()
ImagePreviewButton::initialize
void initialize(const QPixmap &image)
Definition: imagepreviewwidget.cpp:108