├── .gitignore
├── ImageCropper.pro
├── ImageCropper.pro.user
├── README.md
├── assets
└── README
│ ├── 001.png
│ ├── 002.png
│ ├── 003.png
│ ├── 004.png
│ ├── 005.png
│ ├── 006.png
│ ├── cropper_shape.png
│ └── import_functions.png
├── base
├── imagecropperdialog.h
├── imagecropperlabel.cpp
└── imagecropperlabel.h
├── example
├── imagecropperdemo.cpp
├── imagecropperdemo.h
├── main.cpp
├── mainwindow.cpp
└── mainwindow.h
└── res
├── color-palette.ico
├── save.ico
└── select-file.ico
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/ImageCropper.pro:
--------------------------------------------------------------------------------
1 | QT += core gui
2 |
3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
4 |
5 | CONFIG += c++11
6 |
7 | # The following define makes your compiler emit warnings if you use
8 | # any Qt feature that has been marked deprecated (the exact warnings
9 | # depend on your compiler). Please consult the documentation of the
10 | # deprecated API in order to know how to port your code away from it.
11 | DEFINES += QT_DEPRECATED_WARNINGS
12 |
13 | # You can also make your code fail to compile if it uses deprecated APIs.
14 | # In order to do so, uncomment the following line.
15 | # You can also select to disable deprecated APIs only up to a certain version of Qt.
16 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
17 |
18 | SOURCES += \
19 | base/imagecropperlabel.cpp \
20 | example/imagecropperdemo.cpp \
21 | example/main.cpp \
22 | example/mainwindow.cpp
23 |
24 | HEADERS += \
25 | base/imagecropperdialog.h \
26 | base/imagecropperlabel.h \
27 | example/imagecropperdemo.h \
28 | example/mainwindow.h
29 |
30 | # Default rules for deployment.
31 | qnx: target.path = /tmp/$${TARGET}/bin
32 | else: unix:!android: target.path = /opt/$${TARGET}/bin
33 | !isEmpty(target.path): INSTALLS += target
34 |
--------------------------------------------------------------------------------
/ImageCropper.pro.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EnvironmentId
7 | {5891aaf8-91ff-44bd-a6da-fe5c450a3732}
8 |
9 |
10 | ProjectExplorer.Project.ActiveTarget
11 | 0
12 |
13 |
14 | ProjectExplorer.Project.EditorSettings
15 |
16 | true
17 | false
18 | true
19 |
20 | Cpp
21 |
22 | CppGlobal
23 |
24 |
25 |
26 | QmlJS
27 |
28 | QmlJSGlobal
29 |
30 |
31 | 2
32 | UTF-8
33 | false
34 | 4
35 | false
36 | 80
37 | true
38 | true
39 | 1
40 | true
41 | false
42 | 0
43 | true
44 | true
45 | 0
46 | 8
47 | true
48 | 1
49 | true
50 | true
51 | true
52 | false
53 |
54 |
55 |
56 | ProjectExplorer.Project.PluginSettings
57 |
58 |
59 | true
60 |
61 |
62 |
63 | ProjectExplorer.Project.Target.0
64 |
65 | Desktop Qt 5.12.6 GCC 64bit
66 | Desktop Qt 5.12.6 GCC 64bit
67 | qt.qt5.5126.gcc_64_kit
68 | 0
69 | 0
70 | 0
71 |
72 | %{CurrentProject:Path}/build/Debug
73 |
74 |
75 | true
76 | qmake
77 |
78 | QtProjectManager.QMakeBuildStep
79 | true
80 |
81 | false
82 | false
83 | false
84 |
85 |
86 | true
87 | Make
88 |
89 | Qt4ProjectManager.MakeStep
90 |
91 | false
92 |
93 |
94 | false
95 |
96 | 2
97 | Build
98 |
99 | ProjectExplorer.BuildSteps.Build
100 |
101 |
102 |
103 | true
104 | Make
105 |
106 | Qt4ProjectManager.MakeStep
107 |
108 | true
109 | clean
110 |
111 | false
112 |
113 | 1
114 | Clean
115 |
116 | ProjectExplorer.BuildSteps.Clean
117 |
118 | 2
119 | false
120 |
121 | Debug
122 | Debug
123 | Qt4ProjectManager.Qt4BuildConfiguration
124 | 2
125 | true
126 |
127 |
128 | /home/icrystal/dev/cpp/ImageCropper/build/Release
129 |
130 |
131 | true
132 | qmake
133 |
134 | QtProjectManager.QMakeBuildStep
135 | false
136 |
137 | false
138 | false
139 | true
140 |
141 |
142 | true
143 | Make
144 |
145 | Qt4ProjectManager.MakeStep
146 |
147 | false
148 |
149 |
150 | false
151 |
152 | 2
153 | Build
154 |
155 | ProjectExplorer.BuildSteps.Build
156 |
157 |
158 |
159 | true
160 | Make
161 |
162 | Qt4ProjectManager.MakeStep
163 |
164 | true
165 | clean
166 |
167 | false
168 |
169 | 1
170 | Clean
171 |
172 | ProjectExplorer.BuildSteps.Clean
173 |
174 | 2
175 | false
176 |
177 | Release
178 | Release
179 | Qt4ProjectManager.Qt4BuildConfiguration
180 | 0
181 | true
182 |
183 |
184 | /home/icrystal/dev/cpp/ImageCropper/build/Profile
185 |
186 |
187 | true
188 | qmake
189 |
190 | QtProjectManager.QMakeBuildStep
191 | true
192 |
193 | false
194 | true
195 | true
196 |
197 |
198 | true
199 | Make
200 |
201 | Qt4ProjectManager.MakeStep
202 |
203 | false
204 |
205 |
206 | false
207 |
208 | 2
209 | Build
210 |
211 | ProjectExplorer.BuildSteps.Build
212 |
213 |
214 |
215 | true
216 | Make
217 |
218 | Qt4ProjectManager.MakeStep
219 |
220 | true
221 | clean
222 |
223 | false
224 |
225 | 1
226 | Clean
227 |
228 | ProjectExplorer.BuildSteps.Clean
229 |
230 | 2
231 | false
232 |
233 | Profile
234 | Profile
235 | Qt4ProjectManager.Qt4BuildConfiguration
236 | 0
237 | true
238 |
239 | 3
240 |
241 |
242 | 0
243 | Deploy
244 |
245 | ProjectExplorer.BuildSteps.Deploy
246 |
247 | 1
248 | Deploy Configuration
249 |
250 | ProjectExplorer.DefaultDeployConfiguration
251 |
252 | 1
253 |
254 |
255 | dwarf
256 |
257 | cpu-cycles
258 |
259 |
260 | 250
261 | -F
262 | true
263 | 4096
264 | false
265 | false
266 | 1000
267 |
268 | true
269 |
270 | false
271 | false
272 | false
273 | false
274 | true
275 | 0.01
276 | 10
277 | true
278 | kcachegrind
279 | 1
280 | 25
281 |
282 | 1
283 | true
284 | false
285 | true
286 | valgrind
287 |
288 | 0
289 | 1
290 | 2
291 | 3
292 | 4
293 | 5
294 | 6
295 | 7
296 | 8
297 | 9
298 | 10
299 | 11
300 | 12
301 | 13
302 | 14
303 |
304 | 2
305 |
306 | ImageCropper
307 |
308 | Qt4ProjectManager.Qt4RunConfiguration:/home/icrystal/dev/cpp/ImageCropper/ImageCropper.pro
309 |
310 | 3768
311 | false
312 | true
313 | true
314 | false
315 | false
316 | true
317 | %{CurrentProject:Path}
318 | /home/icrystal/dev/cpp/ImageCropper/build/Debug
319 |
320 | 1
321 |
322 |
323 |
324 | ProjectExplorer.Project.TargetCount
325 | 1
326 |
327 |
328 | ProjectExplorer.Project.Updater.FileVersion
329 | 22
330 |
331 |
332 | Version
333 | 22
334 |
335 |
336 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## \[C++\]\[Qt\] custom class : ImageCropperLabel
2 |
3 | ## 一、简介
4 |
5 | 一个图像裁剪控件,可以用于但不限于:用户头像的裁剪。
6 |
7 | 支持输出矩形(包括正方形)、椭圆形(包括圆形)图像。
8 |
9 | ```txt
10 | ├── base
11 | │ ├── imagecropperdialog.h
12 | │ ├── imagecropperlabel.cpp <======== source file
13 | │ └── imagecropperlabel.h <======== header file
14 | └── example
15 | ├── imagecropperdemo.cpp
16 | ├── imagecropperdemo.h
17 | ├── main.cpp
18 | ├── mainwindow.cpp
19 | └── mainwindow.h
20 | ```
21 |
22 | 类的定义在`base/imagecropperlabel.h`文件中,(`base/imagecropperlabel.cpp`为类的实现文件),实际使用只需要用到这两个文件。
23 |
24 | 另外,`base/imagecropperdialog.h`文件实现了对该类的封装,只需如下一行代码即可弹出一个窗口,用户截取图像后,返回截取的图像。(见倒数第三张附图)
25 |
26 | ```C++
27 | QPixmap image = ImageCropperDialog::getCroppedImage("test.png", 600, 400, CropperShape::CIRCLE);
28 | ```
29 |
30 | 类似于Qt自带的`QColorDialog::getColor(...)`
31 |
32 | ## 二、类中的主要方法
33 |
34 | ### 1. 构造函数
35 |
36 | `ImageCropperLabel(int width, int height, QWidget* parent = nullptr);`
37 |
38 | 构造时必须提供该控件的固定大小,即width 和 height。
39 |
40 | ### 2. 设置原始图像
41 |
42 | `void setOriginalImage(const QPixmap& pixmap);`
43 |
44 | ### 3. 设置 裁剪器 (形状和大小)
45 |
46 | ```C++
47 | void setRectCropper();
48 | void setSquareCropper();
49 | void setEllipseCropper();
50 | void setCircleCropper();
51 | void setFixedRectCropper(QSize size);
52 | void setFixedEllipseCropper(QSize size);
53 |
54 | // Not recommended
55 | void setCropper(CropperShape shape, QSize size);
56 | ```
57 |
58 | 
59 |
60 | ```C++
61 | /*****************************************************************************
62 | * Set cropper's fixed size (Only work for FIXED_RECT and FIXED_ELLIPSE)
63 | *****************************************************************************/
64 | void setCropperFixedSize(int fixedWidth, int fixedHeight);
65 | void setCropperFixedWidth(int fixedWidht);
66 | void setCropperFixedHeight(int fixedHeight);
67 |
68 | /*****************************************************************************
69 | * Set cropper's minimum size
70 | * default: the twice of minimum of the edge lenght of drag square
71 | *****************************************************************************/
72 | void setCropperMinimumSize(int minWidth, int minHeight);
73 | void setCropperMinimumWidth(int minWidth);
74 | void setCropperMinimumHeight(int minHeight);
75 | ```
76 |
77 | ### 3. 某些效果的显示
78 |
79 | > 下图左侧的就是一个 ImageCropperLabel 控件
80 | >
81 | > 这是一个Demo窗口,用于测试该控件,从右侧可以方便的调节各种参数
82 | >
83 | > 代码在 "example" 目录下
84 |
85 | 
86 |
87 | ## 三、如何使用
88 |
89 | ```C++
90 | QPixmap pixmap;
91 | pixmap.load("test.png");
92 |
93 | // 创建控件,并设置固定大小
94 | ImageCropperLabel* imgCropperLabel = new ImageCropperLabel(600, 400, this);
95 | // 设置(圆形)裁剪器
96 | imgCropperLabel->setCircleCropper();
97 | // 设置原始图像
98 | imgCropperLabel->setOriginalImage(pixmap);
99 | // 设置输出图像的形状
100 | // OutputShape::RECT --> 矩形(正方形)
101 | // OutputShape::ELLIPSE --> 椭圆形(圆形)
102 | imgCropperLabel->setOutputShape(OutputShape::RECT);
103 | // 启用不透明效果,裁剪区域外不透明显示(默认启用)
104 | //imgCropperLabel->enableOpacity(true);
105 | // 设置不透明度(0~1的浮点数)
106 | imgCropperLabel->setOpacity(0.6); // 默认: 0.6
107 | // 显示四个角(四条边)上的矩形方块,用于捕获鼠标,调整裁剪器的大小(默认显示)
108 | //imgCropperLabel->setShowDragSquare(true);
109 | // 设置四个角(四条边)上的矩形方块的大小,颜色
110 | imgCropperLabel->setDragSquareEdge(8); // 默认: 8
111 | imgCropperLabel->setDragSquareColor(Qt::green); // 默认: Qt::white
112 |
113 | // ...
114 |
115 | // SIGNAL:void croppedImageChagned()
116 | // 用户调整裁剪区域时,会触发 croppedImageChanged() 信号
117 | // 调用 getCroppedImage() 可以获取裁剪区域的图像
118 |
119 | QPixmap resultImage = imgCropperLabel->getCroppedImage(/*OutputShape::RECT*/);
120 | ```
121 |
122 | ## 四、Screenshots
123 |
124 | 
125 |
126 | 
127 |
128 | 
129 |
130 | 
131 |
132 | 
133 |
134 | 
135 |
136 | ## END
137 |
138 |
139 |
--------------------------------------------------------------------------------
/assets/README/001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/assets/README/001.png
--------------------------------------------------------------------------------
/assets/README/002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/assets/README/002.png
--------------------------------------------------------------------------------
/assets/README/003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/assets/README/003.png
--------------------------------------------------------------------------------
/assets/README/004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/assets/README/004.png
--------------------------------------------------------------------------------
/assets/README/005.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/assets/README/005.png
--------------------------------------------------------------------------------
/assets/README/006.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/assets/README/006.png
--------------------------------------------------------------------------------
/assets/README/cropper_shape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/assets/README/cropper_shape.png
--------------------------------------------------------------------------------
/assets/README/import_functions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/assets/README/import_functions.png
--------------------------------------------------------------------------------
/base/imagecropperdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef IMAGECROPPER_H
2 | #define IMAGECROPPER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include "imagecropperlabel.h"
16 |
17 | /*******************************************************
18 | * Loacl private class, which do image-cropping
19 | * Used in class ImageCropper
20 | *******************************************************/
21 | class ImageCropperDialogPrivate : public QDialog {
22 | Q_OBJECT
23 | public:
24 | ImageCropperDialogPrivate(const QPixmap& imageIn, QPixmap& outputImage,
25 | int windowWidth, int windowHeight,
26 | CropperShape shape, QSize cropperSize = QSize()) :
27 | QDialog(nullptr), outputImage(outputImage)
28 | {
29 | this->setAttribute(Qt::WA_DeleteOnClose, true);
30 | this->setWindowTitle("Image Cropper");
31 | this->setMouseTracking(true);
32 | this->setModal(true);
33 |
34 | imageLabel = new ImageCropperLabel(windowWidth, windowHeight, this);
35 | imageLabel->setCropper(shape, cropperSize);
36 | imageLabel->setOutputShape(OutputShape::RECT);
37 | imageLabel->setOriginalImage(imageIn);
38 | imageLabel->enableOpacity(true);
39 |
40 | QHBoxLayout* btnLayout = new QHBoxLayout();
41 | btnOk = new QPushButton("OK", this);
42 | btnCancel = new QPushButton("Cancel", this);
43 | btnLayout->addStretch();
44 | btnLayout->addWidget(btnOk);
45 | btnLayout->addWidget(btnCancel);
46 |
47 | QVBoxLayout* mainLayout = new QVBoxLayout(this);
48 | mainLayout->addWidget(imageLabel);
49 | mainLayout->addLayout(btnLayout);
50 |
51 | connect(btnOk, &QPushButton::clicked, this, [this](){
52 | this->outputImage = this->imageLabel->getCroppedImage();
53 | this->close();
54 | });
55 | connect(btnCancel, &QPushButton::clicked, this, [this](){
56 | this->outputImage = QPixmap();
57 | this->close();
58 | });
59 | }
60 |
61 | private:
62 | ImageCropperLabel* imageLabel;
63 | QPushButton* btnOk;
64 | QPushButton* btnCancel;
65 | QPixmap& outputImage;
66 | };
67 |
68 |
69 | /*******************************************************************
70 | * class ImageCropperDialog
71 | * create a instane of class ImageCropperDialogPrivate
72 | * and get cropped image from the instance(after closing)
73 | ********************************************************************/
74 | class ImageCropperDialog : QObject {
75 | public:
76 | static QPixmap getCroppedImage(const QString& filename,int windowWidth, int windowHeight,
77 | CropperShape cropperShape, QSize crooperSize = QSize())
78 | {
79 | QPixmap inputImage;
80 | QPixmap outputImage;
81 |
82 | if (!inputImage.load(filename)) {
83 | QMessageBox::critical(nullptr, "Error", "Load image failed!", QMessageBox::Ok);
84 | return outputImage;
85 | }
86 |
87 | ImageCropperDialogPrivate* imageCropperDo =
88 | new ImageCropperDialogPrivate(inputImage, outputImage,
89 | windowWidth, windowHeight,
90 | cropperShape, crooperSize);
91 | imageCropperDo->exec();
92 |
93 | return outputImage;
94 | }
95 | };
96 |
97 |
98 |
99 | #endif // IMAGECROPPER_H
100 |
--------------------------------------------------------------------------------
/base/imagecropperlabel.cpp:
--------------------------------------------------------------------------------
1 | #include "imagecropperlabel.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | ImageCropperLabel::ImageCropperLabel(int width, int height, QWidget* parent) :
10 | QLabel(parent)
11 | {
12 | this->setFixedSize(width, height);
13 | this->setAlignment(Qt::AlignCenter);
14 | this->setMouseTracking(true);
15 |
16 | borderPen.setWidth(1);
17 | borderPen.setColor(Qt::white);
18 | borderPen.setDashPattern(QVector() << 3 << 3 << 3 << 3);
19 | }
20 |
21 | void ImageCropperLabel::setOriginalImage(const QPixmap &pixmap) {
22 | originalImage = pixmap;
23 |
24 | int imgWidth = pixmap.width();
25 | int imgHeight = pixmap.height();
26 | int labelWidth = this->width();
27 | int labelHeight = this->height();
28 | int imgWidthInLabel;
29 | int imgHeightInLabel;
30 |
31 | if (imgWidth * labelHeight < imgHeight * labelWidth) {
32 | scaledRate = labelHeight / double(imgHeight);
33 | imgHeightInLabel = labelHeight;
34 | imgWidthInLabel = int(scaledRate * imgWidth);
35 | imageRect.setRect((labelWidth - imgWidthInLabel) / 2, 0,
36 | imgWidthInLabel, imgHeightInLabel);
37 | }
38 | else {
39 | scaledRate = labelWidth / double(imgWidth);
40 | imgWidthInLabel = labelWidth;
41 | imgHeightInLabel = int(scaledRate * imgHeight);
42 | imageRect.setRect(0, (labelHeight - imgHeightInLabel) / 2,
43 | imgWidthInLabel, imgHeightInLabel);
44 | }
45 |
46 | tempImage = originalImage.scaled(imgWidthInLabel, imgHeightInLabel,
47 | Qt::KeepAspectRatio, Qt::SmoothTransformation);
48 | this->setPixmap(tempImage);
49 |
50 | if (cropperShape >= CropperShape::FIXED_RECT) {
51 | cropperRect.setWidth(int(cropperRect_.width() * scaledRate));
52 | cropperRect.setHeight(int(cropperRect_.height() * scaledRate));
53 | }
54 | resetCropperPos();
55 | }
56 |
57 |
58 | /*****************************************
59 | * set cropper's shape (and size)
60 | *****************************************/
61 | void ImageCropperLabel::setRectCropper() {
62 | cropperShape = CropperShape::RECT;
63 | resetCropperPos();
64 | }
65 |
66 | void ImageCropperLabel::setSquareCropper() {
67 | cropperShape = CropperShape::SQUARE;
68 | resetCropperPos();
69 | }
70 |
71 | void ImageCropperLabel::setEllipseCropper() {
72 | cropperShape = CropperShape::ELLIPSE;
73 | resetCropperPos();
74 | }
75 |
76 | void ImageCropperLabel::setCircleCropper() {
77 | cropperShape = CropperShape::CIRCLE;
78 | resetCropperPos();
79 | }
80 |
81 | void ImageCropperLabel::setFixedRectCropper(QSize size) {
82 | cropperShape = CropperShape::FIXED_RECT;
83 | cropperRect_.setSize(size);
84 | resetCropperPos();
85 | }
86 |
87 | void ImageCropperLabel::setFixedEllipseCropper(QSize size) {
88 | cropperShape = CropperShape::FIXED_ELLIPSE;
89 | cropperRect_.setSize(size);
90 | resetCropperPos();
91 | }
92 |
93 | // not recommended
94 | void ImageCropperLabel::setCropper(CropperShape shape, QSize size) {
95 | cropperShape = shape;
96 | cropperRect_.setSize(size);
97 | resetCropperPos();
98 | }
99 |
100 | /*****************************************************************************
101 | * Set cropper's fixed size
102 | *****************************************************************************/
103 | void ImageCropperLabel::setCropperFixedSize(int fixedWidth, int fixedHeight) {
104 | cropperRect_.setSize(QSize(fixedWidth, fixedHeight));
105 | resetCropperPos();
106 | }
107 |
108 | void ImageCropperLabel::setCropperFixedWidth(int fixedWidth) {
109 | cropperRect_.setWidth(fixedWidth);
110 | resetCropperPos();
111 | }
112 |
113 | void ImageCropperLabel::setCropperFixedHeight(int fixedHeight) {
114 | cropperRect_.setHeight(fixedHeight);
115 | resetCropperPos();
116 | }
117 |
118 | /**********************************************
119 | * Move cropper to the center of the image
120 | * And resize to default
121 | **********************************************/
122 | void ImageCropperLabel::resetCropperPos() {
123 | int labelWidth = this->width();
124 | int labelHeight = this->height();
125 |
126 | if (cropperShape == CropperShape::FIXED_RECT || cropperShape == CropperShape::FIXED_ELLIPSE) {
127 | cropperRect.setWidth(int(cropperRect_.width() * scaledRate));
128 | cropperRect.setHeight(int(cropperRect_.height() * scaledRate));
129 | }
130 |
131 | switch (cropperShape) {
132 | case CropperShape::UNDEFINED:
133 | break;
134 | case CropperShape::FIXED_RECT:
135 | case CropperShape::FIXED_ELLIPSE: {
136 | cropperRect.setRect((labelWidth - cropperRect.width()) / 2,
137 | (labelHeight - cropperRect.height()) / 2,
138 | cropperRect.width(), cropperRect.height());
139 | break;
140 | }
141 | case CropperShape::RECT:
142 | case CropperShape::SQUARE:
143 | case CropperShape::ELLIPSE:
144 | case CropperShape::CIRCLE: {
145 | int imgWidth = tempImage.width();
146 | int imgHeight = tempImage.height();
147 | int edge = int((imgWidth > imgHeight ? imgHeight : imgWidth) * 3 / 4.0);
148 | cropperRect.setRect((labelWidth - edge) / 2, (labelHeight - edge) / 2, edge, edge);
149 | break;
150 | }
151 | }
152 | }
153 |
154 | QPixmap ImageCropperLabel::getCroppedImage() {
155 | return getCroppedImage(this->outputShape);
156 | }
157 |
158 | QPixmap ImageCropperLabel::getCroppedImage(OutputShape shape) {
159 | int startX = int((cropperRect.left() - imageRect.left()) / scaledRate);
160 | int startY = int((cropperRect.top() - imageRect.top()) / scaledRate);
161 | int croppedWidth = int(cropperRect.width() / scaledRate);
162 | int croppedHeight = int(cropperRect.height() / scaledRate);
163 |
164 | QPixmap resultImage(croppedWidth, croppedHeight);
165 | resultImage = originalImage.copy(startX, startY, croppedWidth, croppedHeight);
166 |
167 | // Set ellipse mask (cut to ellipse shape)
168 | if (shape == OutputShape::ELLIPSE) {
169 | QSize size(croppedWidth, croppedHeight);
170 | QBitmap mask(size);
171 | QPainter painter(&mask);
172 | painter.setRenderHint(QPainter::Antialiasing);
173 | painter.setRenderHint(QPainter::SmoothPixmapTransform);
174 | painter.fillRect(0, 0, size.width(), size.height(), Qt::white);
175 | painter.setBrush(QColor(0, 0, 0));
176 | painter.drawRoundRect(0, 0, size.width(), size.height(), 99, 99);
177 | resultImage.setMask(mask);
178 | }
179 |
180 | return resultImage;
181 | }
182 |
183 |
184 | void ImageCropperLabel::paintEvent(QPaintEvent *event) {
185 | // Draw original image
186 | QLabel::paintEvent(event);
187 |
188 | // Draw cropper and set some effects
189 | switch (cropperShape) {
190 | case CropperShape::UNDEFINED:
191 | break;
192 | case CropperShape::FIXED_RECT:
193 | drawRectOpacity();
194 | break;
195 | case CropperShape::FIXED_ELLIPSE:
196 | drawEllipseOpacity();
197 | break;
198 | case CropperShape::RECT:
199 | drawRectOpacity();
200 | drawSquareEdge(!ONLY_FOUR_CORNERS);
201 | break;
202 | case CropperShape::SQUARE:
203 | drawRectOpacity();
204 | drawSquareEdge(ONLY_FOUR_CORNERS);
205 | break;
206 | case CropperShape::ELLIPSE:
207 | drawEllipseOpacity();
208 | drawSquareEdge(!ONLY_FOUR_CORNERS);
209 | break;
210 | case CropperShape::CIRCLE:
211 | drawEllipseOpacity();
212 | drawSquareEdge(ONLY_FOUR_CORNERS);
213 | break;
214 | }
215 |
216 | // Draw cropper rect
217 | if (isShowRectBorder) {
218 | QPainter painter(this);
219 | painter.setPen(borderPen);
220 | painter.drawRect(cropperRect);
221 | }
222 | }
223 |
224 | void ImageCropperLabel::drawSquareEdge(bool onlyFourCorners) {
225 | if (!isShowDragSquare)
226 | return;
227 |
228 | // Four corners
229 | drawFillRect(cropperRect.topLeft(), dragSquareEdge, dragSquareColor);
230 | drawFillRect(cropperRect.topRight(), dragSquareEdge, dragSquareColor);
231 | drawFillRect(cropperRect.bottomLeft(), dragSquareEdge, dragSquareColor);
232 | drawFillRect(cropperRect.bottomRight(), dragSquareEdge, dragSquareColor);
233 |
234 | // Four edges
235 | if (!onlyFourCorners) {
236 | int centralX = cropperRect.left() + cropperRect.width() / 2;
237 | int centralY = cropperRect.top() + cropperRect.height() / 2;
238 | drawFillRect(QPoint(cropperRect.left(), centralY), dragSquareEdge, dragSquareColor);
239 | drawFillRect(QPoint(centralX, cropperRect.top()), dragSquareEdge, dragSquareColor);
240 | drawFillRect(QPoint(cropperRect.right(), centralY), dragSquareEdge, dragSquareColor);
241 | drawFillRect(QPoint(centralX, cropperRect.bottom()), dragSquareEdge, dragSquareColor);
242 | }
243 | }
244 |
245 | void ImageCropperLabel::drawFillRect(QPoint centralPoint, int edge, QColor color) {
246 | QRect rect(centralPoint.x() - edge / 2, centralPoint.y() - edge / 2, edge, edge);
247 | QPainter painter(this);
248 | painter.fillRect(rect, color);
249 | }
250 |
251 | // Opacity effect
252 | void ImageCropperLabel::drawOpacity(const QPainterPath& path) {
253 | QPainter painterOpac(this);
254 | painterOpac.setOpacity(opacity);
255 | painterOpac.fillPath(path, QBrush(Qt::black));
256 | }
257 |
258 | void ImageCropperLabel::drawRectOpacity() {
259 | if (isShowOpacityEffect) {
260 | QPainterPath p1, p2, p;
261 | p1.addRect(imageRect);
262 | p2.addRect(cropperRect);
263 | p = p1.subtracted(p2);
264 | drawOpacity(p);
265 | }
266 | }
267 |
268 | void ImageCropperLabel::drawEllipseOpacity() {
269 | if (isShowOpacityEffect) {
270 | QPainterPath p1, p2, p;
271 | p1.addRect(imageRect);
272 | p2.addEllipse(cropperRect);
273 | p = p1.subtracted(p2);
274 | drawOpacity(p);
275 | }
276 | }
277 |
278 | bool ImageCropperLabel::isPosNearDragSquare(const QPoint& pt1, const QPoint& pt2) {
279 | return abs(pt1.x() - pt2.x()) * 2 <= dragSquareEdge
280 | && abs(pt1.y() - pt2.y()) * 2 <= dragSquareEdge;
281 | }
282 |
283 | int ImageCropperLabel::getPosInCropperRect(const QPoint &pt) {
284 | if (isPosNearDragSquare(pt, QPoint(cropperRect.right(), cropperRect.center().y())))
285 | return RECT_RIGHT;
286 | if (isPosNearDragSquare(pt, cropperRect.bottomRight()))
287 | return RECT_BOTTOM_RIGHT;
288 | if (isPosNearDragSquare(pt, QPoint(cropperRect.center().x(), cropperRect.bottom())))
289 | return RECT_BOTTOM;
290 | if (isPosNearDragSquare(pt, cropperRect.bottomLeft()))
291 | return RECT_BOTTOM_LEFT;
292 | if (isPosNearDragSquare(pt, QPoint(cropperRect.left(), cropperRect.center().y())))
293 | return RECT_LEFT;
294 | if (isPosNearDragSquare(pt, cropperRect.topLeft()))
295 | return RECT_TOP_LEFT;
296 | if (isPosNearDragSquare(pt, QPoint(cropperRect.center().x(), cropperRect.top())))
297 | return RECT_TOP;
298 | if (isPosNearDragSquare(pt, cropperRect.topRight()))
299 | return RECT_TOP_RIGHT;
300 | if (cropperRect.contains(pt, true))
301 | return RECT_INSIDE;
302 | return RECT_OUTSIZD;
303 | }
304 |
305 | /*************************************************
306 | *
307 | * Change mouse cursor type
308 | * Arrow, SizeHor, SizeVer, etc...
309 | *
310 | *************************************************/
311 |
312 | void ImageCropperLabel::changeCursor() {
313 | switch (cursorPosInCropperRect) {
314 | case RECT_OUTSIZD:
315 | setCursor(Qt::ArrowCursor);
316 | break;
317 | case RECT_BOTTOM_RIGHT: {
318 | switch (cropperShape) {
319 | case CropperShape::SQUARE:
320 | case CropperShape::CIRCLE:
321 | case CropperShape::RECT:
322 | case CropperShape::ELLIPSE:
323 | setCursor(Qt::SizeFDiagCursor);
324 | break;
325 | default:
326 | break;
327 | }
328 | break;
329 | }
330 | case RECT_RIGHT: {
331 | switch (cropperShape) {
332 | case CropperShape::RECT:
333 | case CropperShape::ELLIPSE:
334 | setCursor(Qt::SizeHorCursor);
335 | break;
336 | default:
337 | break;
338 | }
339 | break;
340 | }
341 | case RECT_BOTTOM: {
342 | switch (cropperShape) {
343 | case CropperShape::RECT:
344 | case CropperShape::ELLIPSE:
345 | setCursor(Qt::SizeVerCursor);
346 | break;
347 | default:
348 | break;
349 | }
350 | break;
351 | }
352 | case RECT_BOTTOM_LEFT: {
353 | switch (cropperShape) {
354 | case CropperShape::RECT:
355 | case CropperShape::ELLIPSE:
356 | case CropperShape::SQUARE:
357 | case CropperShape::CIRCLE:
358 | setCursor(Qt::SizeBDiagCursor);
359 | break;
360 | default:
361 | break;
362 | }
363 | break;
364 | }
365 | case RECT_LEFT: {
366 | switch (cropperShape) {
367 | case CropperShape::RECT:
368 | case CropperShape::ELLIPSE:
369 | setCursor(Qt::SizeHorCursor);
370 | break;
371 | default:
372 | break;
373 | }
374 | break;
375 | }
376 | case RECT_TOP_LEFT: {
377 | switch (cropperShape) {
378 | case CropperShape::RECT:
379 | case CropperShape::ELLIPSE:
380 | case CropperShape::SQUARE:
381 | case CropperShape::CIRCLE:
382 | setCursor(Qt::SizeFDiagCursor);
383 | break;
384 | default:
385 | break;
386 | }
387 | break;
388 | }
389 | case RECT_TOP: {
390 | switch (cropperShape) {
391 | case CropperShape::RECT:
392 | case CropperShape::ELLIPSE:
393 | setCursor(Qt::SizeVerCursor);
394 | break;
395 | default:
396 | break;
397 | }
398 | break;
399 | }
400 | case RECT_TOP_RIGHT: {
401 | switch (cropperShape) {
402 | case CropperShape::SQUARE:
403 | case CropperShape::CIRCLE:
404 | case CropperShape::RECT:
405 | case CropperShape::ELLIPSE:
406 | setCursor(Qt::SizeBDiagCursor);
407 | break;
408 | default:
409 | break;
410 | }
411 | break;
412 | }
413 | case RECT_INSIDE: {
414 | setCursor(Qt::SizeAllCursor);
415 | break;
416 | }
417 | }
418 | }
419 |
420 | /*****************************************************
421 | *
422 | * Mouse Events
423 | *
424 | *****************************************************/
425 |
426 | void ImageCropperLabel::mousePressEvent(QMouseEvent *e) {
427 | currPos = lastPos = e->pos();
428 | isLButtonPressed = true;
429 | }
430 |
431 | void ImageCropperLabel::mouseMoveEvent(QMouseEvent *e) {
432 | currPos = e->pos();
433 | if (!isCursorPosCalculated) {
434 | cursorPosInCropperRect = getPosInCropperRect(currPos);
435 | changeCursor();
436 | }
437 |
438 | if (!isLButtonPressed)
439 | return;
440 | if (!imageRect.contains(currPos))
441 | return;
442 |
443 | isCursorPosCalculated = true;
444 |
445 | int xOffset = currPos.x() - lastPos.x();
446 | int yOffset = currPos.y() - lastPos.y();
447 | lastPos = currPos;
448 |
449 | int disX = 0;
450 | int disY = 0;
451 |
452 | // Move cropper
453 | switch (cursorPosInCropperRect) {
454 | case RECT_OUTSIZD:
455 | break;
456 | case RECT_BOTTOM_RIGHT: {
457 | disX = currPos.x() - cropperRect.left();
458 | disY = currPos.y() - cropperRect.top();
459 | switch (cropperShape) {
460 | case CropperShape::UNDEFINED:
461 | case CropperShape::FIXED_RECT:
462 | case CropperShape::FIXED_ELLIPSE:
463 | break;
464 | case CropperShape::SQUARE:
465 | case CropperShape::CIRCLE:
466 | setCursor(Qt::SizeFDiagCursor);
467 | if (disX >= cropperMinimumWidth && disY >= cropperMinimumHeight) {
468 | if (disX > disY && cropperRect.top() + disX <= imageRect.bottom()) {
469 | cropperRect.setRight(currPos.x());
470 | cropperRect.setBottom(cropperRect.top() + disX);
471 | emit croppedImageChanged();
472 | }
473 | else if (disX <= disY && cropperRect.left() + disY <= imageRect.right()) {
474 | cropperRect.setBottom(currPos.y());
475 | cropperRect.setRight(cropperRect.left() + disY);
476 | emit croppedImageChanged();
477 | }
478 | }
479 | break;
480 | case CropperShape::RECT:
481 | case CropperShape::ELLIPSE:
482 | setCursor(Qt::SizeFDiagCursor);
483 | if (disX >= cropperMinimumWidth) {
484 | cropperRect.setRight(currPos.x());
485 | emit croppedImageChanged();
486 | }
487 | if (disY >= cropperMinimumHeight) {
488 | cropperRect.setBottom(currPos.y());
489 | emit croppedImageChanged();
490 | }
491 | break;
492 | }
493 | break;
494 | }
495 | case RECT_RIGHT: {
496 | disX = currPos.x() - cropperRect.left();
497 | switch (cropperShape) {
498 | case CropperShape::UNDEFINED:
499 | case CropperShape::FIXED_RECT:
500 | case CropperShape::FIXED_ELLIPSE:
501 | case CropperShape::SQUARE:
502 | case CropperShape::CIRCLE:
503 | break;
504 | case CropperShape::RECT:
505 | case CropperShape::ELLIPSE:
506 | if (disX >= cropperMinimumWidth) {
507 | cropperRect.setRight(currPos.x());
508 | emit croppedImageChanged();
509 | }
510 | break;
511 | }
512 | break;
513 | }
514 | case RECT_BOTTOM: {
515 | disY = currPos.y() - cropperRect.top();
516 | switch (cropperShape) {
517 | case CropperShape::UNDEFINED:
518 | case CropperShape::FIXED_RECT:
519 | case CropperShape::FIXED_ELLIPSE:
520 | case CropperShape::SQUARE:
521 | case CropperShape::CIRCLE:
522 | break;
523 | case CropperShape::RECT:
524 | case CropperShape::ELLIPSE:
525 | if (disY >= cropperMinimumHeight) {
526 | cropperRect.setBottom(cropperRect.bottom() + yOffset);
527 | emit croppedImageChanged();
528 | }
529 | break;
530 | }
531 | break;
532 | }
533 | case RECT_BOTTOM_LEFT: {
534 | disX = cropperRect.right() - currPos.x();
535 | disY = currPos.y() - cropperRect.top();
536 | switch (cropperShape) {
537 | case CropperShape::UNDEFINED:
538 | break;
539 | case CropperShape::FIXED_RECT:
540 | case CropperShape::FIXED_ELLIPSE:
541 | case CropperShape::RECT:
542 | case CropperShape::ELLIPSE:
543 | if (disX >= cropperMinimumWidth) {
544 | cropperRect.setLeft(currPos.x());
545 | emit croppedImageChanged();
546 | }
547 | if (disY >= cropperMinimumHeight) {
548 | cropperRect.setBottom(currPos.y());
549 | emit croppedImageChanged();
550 | }
551 | break;
552 | case CropperShape::SQUARE:
553 | case CropperShape::CIRCLE:
554 | if (disX >= cropperMinimumWidth && disY >= cropperMinimumHeight) {
555 | if (disX > disY && cropperRect.top() + disX <= imageRect.bottom()) {
556 | cropperRect.setLeft(currPos.x());
557 | cropperRect.setBottom(cropperRect.top() + disX);
558 | emit croppedImageChanged();
559 | }
560 | else if (disX <= disY && cropperRect.right() - disY >= imageRect.left()) {
561 | cropperRect.setBottom(currPos.y());
562 | cropperRect.setLeft(cropperRect.right() - disY);
563 | emit croppedImageChanged();
564 | }
565 | }
566 | break;
567 | }
568 | break;
569 | }
570 | case RECT_LEFT: {
571 | disX = cropperRect.right() - currPos.x();
572 | switch (cropperShape) {
573 | case CropperShape::UNDEFINED:
574 | case CropperShape::FIXED_RECT:
575 | case CropperShape::FIXED_ELLIPSE:
576 | case CropperShape::SQUARE:
577 | case CropperShape::CIRCLE:
578 | break;
579 | case CropperShape::RECT:
580 | case CropperShape::ELLIPSE:
581 | if (disX >= cropperMinimumHeight) {
582 | cropperRect.setLeft(cropperRect.left() + xOffset);
583 | emit croppedImageChanged();
584 | }
585 | break;
586 | }
587 | break;
588 | }
589 | case RECT_TOP_LEFT: {
590 | disX = cropperRect.right() - currPos.x();
591 | disY = cropperRect.bottom() - currPos.y();
592 | switch (cropperShape) {
593 | case CropperShape::UNDEFINED:
594 | case CropperShape::FIXED_RECT:
595 | case CropperShape::FIXED_ELLIPSE:
596 | break;
597 | case CropperShape::RECT:
598 | case CropperShape::ELLIPSE:
599 | if (disX >= cropperMinimumWidth) {
600 | cropperRect.setLeft(currPos.x());
601 | emit croppedImageChanged();
602 | }
603 | if (disY >= cropperMinimumHeight) {
604 | cropperRect.setTop(currPos.y());
605 | emit croppedImageChanged();
606 | }
607 | break;
608 | case CropperShape::SQUARE:
609 | case CropperShape::CIRCLE:
610 | if (disX >= cropperMinimumWidth && disY >= cropperMinimumHeight) {
611 | if (disX > disY && cropperRect.bottom() - disX >= imageRect.top()) {
612 | cropperRect.setLeft(currPos.x());
613 | cropperRect.setTop(cropperRect.bottom() - disX);
614 | emit croppedImageChanged();
615 | }
616 | else if (disX <= disY && cropperRect.right() - disY >= imageRect.left()) {
617 | cropperRect.setTop(currPos.y());
618 | cropperRect.setLeft(cropperRect.right() - disY);
619 | emit croppedImageChanged();
620 | }
621 | }
622 | break;
623 | }
624 | break;
625 | }
626 | case RECT_TOP: {
627 | disY = cropperRect.bottom() - currPos.y();
628 | switch (cropperShape) {
629 | case CropperShape::UNDEFINED:
630 | case CropperShape::FIXED_RECT:
631 | case CropperShape::FIXED_ELLIPSE:
632 | case CropperShape::SQUARE:
633 | case CropperShape::CIRCLE:
634 | break;
635 | case CropperShape::RECT:
636 | case CropperShape::ELLIPSE:
637 | if (disY >= cropperMinimumHeight) {
638 | cropperRect.setTop(cropperRect.top() + yOffset);
639 | emit croppedImageChanged();
640 | }
641 | break;
642 | }
643 | break;
644 | }
645 | case RECT_TOP_RIGHT: {
646 | disX = currPos.x() - cropperRect.left();
647 | disY = cropperRect.bottom() - currPos.y();
648 | switch (cropperShape) {
649 | case CropperShape::UNDEFINED:
650 | case CropperShape::FIXED_RECT:
651 | case CropperShape::FIXED_ELLIPSE:
652 | break;
653 | case CropperShape::RECT:
654 | case CropperShape::ELLIPSE:
655 | if (disX >= cropperMinimumWidth) {
656 | cropperRect.setRight(currPos.x());
657 | emit croppedImageChanged();
658 | }
659 | if (disY >= cropperMinimumHeight) {
660 | cropperRect.setTop(currPos.y());
661 | emit croppedImageChanged();
662 | }
663 | break;
664 | case CropperShape::SQUARE:
665 | case CropperShape::CIRCLE:
666 | if (disX >= cropperMinimumWidth && disY >= cropperMinimumHeight) {
667 | if (disX < disY && cropperRect.left() + disY <= imageRect.right()) {
668 | cropperRect.setTop(currPos.y());
669 | cropperRect.setRight(cropperRect.left() + disY);
670 | emit croppedImageChanged();
671 | }
672 | else if (disX >= disY && cropperRect.bottom() - disX >= imageRect.top()) {
673 | cropperRect.setRight(currPos.x());
674 | cropperRect.setTop(cropperRect.bottom() - disX);
675 | emit croppedImageChanged();
676 | }
677 | }
678 | break;
679 | }
680 | break;
681 | }
682 | case RECT_INSIDE: {
683 | // Make sure the cropperRect is entirely inside the imageRecct
684 | if (xOffset > 0) {
685 | if (cropperRect.right() + xOffset > imageRect.right())
686 | xOffset = 0;
687 | }
688 | else if (xOffset < 0) {
689 | if (cropperRect.left() + xOffset < imageRect.left())
690 | xOffset = 0;
691 | }
692 | if (yOffset > 0) {
693 | if (cropperRect.bottom() + yOffset > imageRect.bottom())
694 | yOffset = 0;
695 | }
696 | else if (yOffset < 0) {
697 | if (cropperRect.top() + yOffset < imageRect.top())
698 | yOffset = 0;
699 | }
700 | cropperRect.moveTo(cropperRect.left() + xOffset, cropperRect.top() + yOffset);
701 | emit croppedImageChanged();
702 | }
703 | break;
704 | }
705 |
706 | repaint();
707 | }
708 |
709 | void ImageCropperLabel::mouseReleaseEvent(QMouseEvent *) {
710 | isLButtonPressed = false;
711 | isCursorPosCalculated = false;
712 | setCursor(Qt::ArrowCursor);
713 | }
714 |
715 |
--------------------------------------------------------------------------------
/base/imagecropperlabel.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | * class: ImageCropperLabel
3 | * author: github@Leopard-C
4 | * email: leopard.c@outlook.com
5 | * last change: 2020-03-06
6 | *************************************************************************/
7 | #ifndef IMAGECROPPERLABEL_H
8 | #define IMAGECROPPERLABEL_H
9 |
10 | #include
11 | #include
12 | #include
13 |
14 | enum class CropperShape {
15 | UNDEFINED = 0,
16 | RECT = 1,
17 | SQUARE = 2,
18 | FIXED_RECT = 3,
19 | ELLIPSE = 4,
20 | CIRCLE = 5,
21 | FIXED_ELLIPSE = 6
22 | };
23 |
24 | enum class OutputShape {
25 | RECT = 0,
26 | ELLIPSE = 1
27 | };
28 |
29 | enum class SizeType {
30 | fixedSize = 0,
31 | fitToMaxWidth = 1,
32 | fitToMaxHeight = 2,
33 | fitToMaxWidthHeight = 3,
34 | };
35 |
36 |
37 | class ImageCropperLabel : public QLabel {
38 | Q_OBJECT
39 | public:
40 | ImageCropperLabel(int width, int height, QWidget* parent);
41 |
42 | void setOriginalImage(const QPixmap& pixmap);
43 | void setOutputShape(OutputShape shape) { outputShape = shape; }
44 | QPixmap getCroppedImage();
45 | QPixmap getCroppedImage(OutputShape shape);
46 |
47 | /*****************************************
48 | * Set cropper's shape
49 | *****************************************/
50 | void setRectCropper();
51 | void setSquareCropper();
52 | void setEllipseCropper();
53 | void setCircleCropper();
54 | void setFixedRectCropper(QSize size);
55 | void setFixedEllipseCropper(QSize size);
56 | void setCropper(CropperShape shape, QSize size); // not recommended
57 |
58 | /*****************************************************************************
59 | * Set cropper's fixed size
60 | *****************************************************************************/
61 | void setCropperFixedSize(int fixedWidth, int fixedHeight);
62 | void setCropperFixedWidth(int fixedWidht);
63 | void setCropperFixedHeight(int fixedHeight);
64 |
65 | /*****************************************************************************
66 | * Set cropper's minimum size
67 | * default: the twice of minimum of the edge lenght of drag square
68 | *****************************************************************************/
69 | void setCropperMinimumSize(int minWidth, int minHeight)
70 | { cropperMinimumWidth = minWidth; cropperMinimumHeight = minHeight; }
71 | void setCropperMinimumWidth(int minWidth) { cropperMinimumWidth = minWidth; }
72 | void setCropperMinimumHeight(int minHeight) { cropperMinimumHeight = minHeight; }
73 |
74 | /*************************************************
75 | * Set the size, color, visibility of rectangular border
76 | *************************************************/
77 | void setShowRectBorder(bool show) { isShowRectBorder = show; }
78 | QPen getBorderPen() { return borderPen; }
79 | void setBorderPen(const QPen& pen) { borderPen = pen; }
80 |
81 | /*************************************************
82 | * Set the size, color of drag square
83 | *************************************************/
84 | void setShowDragSquare(bool show) { isShowDragSquare = show; }
85 | void setDragSquareEdge(int edge) { dragSquareEdge = (edge >= 3 ? edge : 3); }
86 | void setDragSquareColor(const QColor& color) { dragSquareColor = color; }
87 |
88 | /*****************************************
89 | * Opacity Effect
90 | *****************************************/
91 | void enableOpacity(bool b = true) { isShowOpacityEffect = b; }
92 | void setOpacity(double newOpacity) { opacity = newOpacity; }
93 |
94 | signals:
95 | void croppedImageChanged();
96 |
97 | protected:
98 | /*****************************************
99 | * Event
100 | *****************************************/
101 | virtual void paintEvent(QPaintEvent *event) override;
102 | virtual void mousePressEvent(QMouseEvent *e) override;
103 | virtual void mouseMoveEvent(QMouseEvent *e) override;
104 | virtual void mouseReleaseEvent(QMouseEvent *e) override;
105 |
106 | private:
107 | /***************************************
108 | * Draw shapes
109 | ***************************************/
110 | void drawFillRect(QPoint centralPoint, int edge, QColor color);
111 | void drawRectOpacity();
112 | void drawEllipseOpacity();
113 | void drawOpacity(const QPainterPath& path); // shadow effect
114 | void drawSquareEdge(bool onlyFourCorners);
115 |
116 | /***************************************
117 | * Other utility methods
118 | ***************************************/
119 | int getPosInCropperRect(const QPoint& pt);
120 | bool isPosNearDragSquare(const QPoint& pt1, const QPoint& pt2);
121 | void resetCropperPos();
122 | void changeCursor();
123 |
124 | enum {
125 | RECT_OUTSIZD = 0,
126 | RECT_INSIDE = 1,
127 | RECT_TOP_LEFT, RECT_TOP, RECT_TOP_RIGHT, RECT_RIGHT,
128 | RECT_BOTTOM_RIGHT, RECT_BOTTOM, RECT_BOTTOM_LEFT, RECT_LEFT
129 | };
130 |
131 | const bool ONLY_FOUR_CORNERS = true;
132 |
133 | private:
134 | QPixmap originalImage;
135 | QPixmap tempImage;
136 |
137 | bool isShowRectBorder = true;
138 | QPen borderPen;
139 |
140 | CropperShape cropperShape = CropperShape::UNDEFINED;
141 | OutputShape outputShape = OutputShape::RECT;
142 |
143 | QRect imageRect; // the whole image area in the label (not real size)
144 | QRect cropperRect; // a rectangle frame to choose image area (not real size)
145 | QRect cropperRect_; // cropper rect (real size)
146 | double scaledRate = 1.0;
147 |
148 | bool isLButtonPressed = false;
149 | bool isCursorPosCalculated = false;
150 | int cursorPosInCropperRect = RECT_OUTSIZD;
151 | QPoint lastPos;
152 | QPoint currPos;
153 |
154 | bool isShowDragSquare = true;
155 | int dragSquareEdge = 8;
156 | QColor dragSquareColor = Qt::white;
157 |
158 | int cropperMinimumWidth = dragSquareEdge * 2;
159 | int cropperMinimumHeight = dragSquareEdge * 2;
160 |
161 | bool isShowOpacityEffect = false;
162 | double opacity = 0.6;
163 | };
164 |
165 | #endif // IMAGECROPPERLABEL_H
166 |
--------------------------------------------------------------------------------
/example/imagecropperdemo.cpp:
--------------------------------------------------------------------------------
1 | #include "imagecropperdemo.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | ImageCropperDemo::ImageCropperDemo(QWidget* parent) :
9 | QDialog(parent)
10 | {
11 | setupLayout();
12 | init();
13 |
14 | this->setAttribute(Qt::WA_DeleteOnClose, true);
15 | this->setWindowTitle("Image Cropper Demo");
16 | }
17 |
18 |
19 | void ImageCropperDemo::setupLayout() {
20 | imgCropperLabel = new ImageCropperLabel(600, 500, this);
21 | imgCropperLabel->setFrameStyle(1);
22 |
23 | comboOutputShape = new QComboBox(this);
24 | comboCropperShape = new QComboBox(this);
25 |
26 | labelPreviewImage = new QLabel(this);
27 |
28 | editOriginalImagePath = new QLineEdit(this);
29 | btnChooseOriginalImagePath = new QPushButton(this);
30 | QHBoxLayout* hOriginalImagePathLayout = new QHBoxLayout();
31 | hOriginalImagePathLayout->addWidget(editOriginalImagePath);
32 | hOriginalImagePathLayout->addWidget(btnChooseOriginalImagePath);
33 |
34 | editCropperFixedWidth = new QLineEdit(this);
35 | editCropperFixedHeight = new QLineEdit(this);
36 | QHBoxLayout* hCropperFixedSizeLayout = new QHBoxLayout();
37 | hCropperFixedSizeLayout->addWidget(editCropperFixedWidth);
38 | hCropperFixedSizeLayout->addWidget(editCropperFixedHeight);
39 |
40 | editCropperMinWidth = new QLineEdit("8", this);
41 | editCropperMinHeight = new QLineEdit("8", this);
42 | QHBoxLayout* hCropperMinSizeLayout = new QHBoxLayout();
43 | hCropperMinSizeLayout->addWidget(editCropperMinWidth);
44 | hCropperMinSizeLayout->addWidget(editCropperMinHeight);
45 |
46 | checkEnableOpacity = new QCheckBox(this);
47 | sliderOpacity = new QSlider(Qt::Horizontal, this);
48 |
49 | checkShowDragSquare = new QCheckBox(this);
50 | editDragSquareEdge = new QLineEdit("8", this);
51 | checkShowRectBorder = new QCheckBox(this);
52 |
53 | labelRectBorderColor = new QLabel(this);
54 | btnChooseRectBorderCorlor = new QPushButton(this);
55 | QHBoxLayout* hRectBorderColorLayout = new QHBoxLayout();
56 | hRectBorderColorLayout->addWidget(labelRectBorderColor);
57 | hRectBorderColorLayout->addWidget(btnChooseRectBorderCorlor);
58 |
59 | labelDragSquareColor = new QLabel(this);
60 | btnChooseDragSquareColor = new QPushButton(this);
61 | QHBoxLayout* hDragSquareColorLayout = new QHBoxLayout();
62 | hDragSquareColorLayout->addWidget(labelDragSquareColor);
63 | hDragSquareColorLayout->addWidget(btnChooseDragSquareColor);
64 |
65 | QFormLayout* formLayout1 = new QFormLayout();
66 | formLayout1->addRow(new QLabel("Preview:"), labelPreviewImage);
67 | formLayout1->addRow(new QLabel("OriginalImage:", this), hOriginalImagePathLayout);
68 | formLayout1->addRow(new QLabel("OutputShape:", this), comboOutputShape);
69 | formLayout1->addRow(new QLabel("CropperShape:", this), comboCropperShape);
70 | formLayout1->addRow(new QLabel("FixedSize:", this), hCropperFixedSizeLayout);
71 | formLayout1->addRow(new QLabel("MinimumSize:", this), hCropperMinSizeLayout);
72 |
73 | QFormLayout* formLayout2 = new QFormLayout();
74 | formLayout2->addRow(new QLabel("EnableOpacity:", this), checkEnableOpacity);
75 | formLayout2->addRow(new QLabel("Opacity:", this), sliderOpacity);
76 |
77 | QFormLayout* formLayout3 = new QFormLayout();
78 | formLayout3->addRow(new QLabel("ShowDragSquare:", this), checkShowDragSquare);
79 | formLayout3->addRow(new QLabel("DragSquareEdge:", this), editDragSquareEdge);
80 | formLayout3->addRow(new QLabel("DragSquareColor:", this), hDragSquareColorLayout);
81 |
82 | QFormLayout* formLayout4 = new QFormLayout();
83 | formLayout4->addRow(new QLabel("ShowRectBorder:", this), checkShowRectBorder);
84 | formLayout4->addRow(new QLabel("RectBorderColor:", this), hRectBorderColorLayout);
85 |
86 | btnSavePreview = new QPushButton("Save", this);
87 | btnQuit = new QPushButton("Quit", this);
88 | QHBoxLayout* btnLayout = new QHBoxLayout();
89 | btnLayout->addStretch();
90 | btnLayout->addWidget(btnSavePreview);
91 | btnLayout->addStretch();
92 | btnLayout->addWidget(btnQuit);
93 | btnLayout->addStretch();
94 |
95 | QVBoxLayout* vLayout = new QVBoxLayout();
96 | vLayout->addLayout(formLayout1);
97 | vLayout->addStretch();
98 | vLayout->addLayout(formLayout2);
99 | vLayout->addStretch();
100 | vLayout->addLayout(formLayout3);
101 | vLayout->addStretch();
102 | vLayout->addLayout(formLayout4);
103 | vLayout->addStretch();
104 | vLayout->addLayout(btnLayout);
105 |
106 | mainLayout = new QHBoxLayout(this);
107 | mainLayout->addWidget(imgCropperLabel);
108 | mainLayout->addLayout(vLayout);
109 | }
110 |
111 | void ImageCropperDemo::init() {
112 | imgCropperLabel->setRectCropper();
113 | editCropperFixedWidth->setEnabled(false);
114 | editCropperFixedHeight->setEnabled(false);
115 |
116 | labelPreviewImage->setFixedSize(96, 96);
117 | labelPreviewImage->setAlignment(Qt::AlignCenter);
118 | labelPreviewImage->setFrameStyle(QFrame::Panel | QFrame::Sunken);
119 | connect(imgCropperLabel, &ImageCropperLabel::croppedImageChanged,
120 | this, &ImageCropperDemo::onUpdatePreview);
121 |
122 | btnChooseOriginalImagePath->setIcon(QIcon("res/select-file.ico"));
123 | btnChooseOriginalImagePath->setFixedWidth(30);
124 | connect(btnChooseOriginalImagePath, &QPushButton::clicked,
125 | this, &ImageCropperDemo::onChooseOriginalImage);
126 |
127 | comboOutputShape->addItem("Rect/Square");
128 | comboOutputShape->addItem("Ellipse/Circle");
129 | connect(comboOutputShape, SIGNAL(currentIndexChanged(int)),
130 | this, SLOT(onOutputShapeChanged(int)));
131 |
132 | comboCropperShape->addItem("Rect");
133 | comboCropperShape->addItem("Square");
134 | comboCropperShape->addItem("FixedRect");
135 | comboCropperShape->addItem("Ellipse");
136 | comboCropperShape->addItem("Circle");
137 | comboCropperShape->addItem("FixedEllipse");
138 | connect(comboCropperShape, SIGNAL(currentIndexChanged(int)),
139 | this, SLOT(onCropperShapeChanged(int)));
140 |
141 | connect(editCropperFixedWidth, &QLineEdit::textChanged,
142 | this, &ImageCropperDemo::onFixedWidthChanged);
143 | connect(editCropperFixedHeight, &QLineEdit::textChanged,
144 | this, &ImageCropperDemo::onFixedHeightChanged);
145 | connect(editCropperMinWidth, &QLineEdit::textChanged,
146 | this, &ImageCropperDemo::onMinWidthChanged);
147 | connect(editCropperMinHeight, &QLineEdit::textChanged,
148 | this, &ImageCropperDemo::onMinHeightChanged);
149 |
150 | checkEnableOpacity->setCheckState(Qt::Checked);
151 | imgCropperLabel->enableOpacity(true);
152 | connect(checkEnableOpacity, &QCheckBox::stateChanged,
153 | this, &ImageCropperDemo::onEnableOpacityChanged);
154 |
155 | checkShowDragSquare->setCheckState(Qt::Checked);
156 | imgCropperLabel->setShowDragSquare(true);
157 | connect(checkShowDragSquare, &QCheckBox::stateChanged,
158 | this, &ImageCropperDemo::onShowDragSquareChanged);
159 | connect(editDragSquareEdge, &QLineEdit::textChanged,
160 | this, &ImageCropperDemo::onDragSquareEdgeChanged);
161 |
162 | sliderOpacity->setRange(0, 100);
163 | sliderOpacity->setValue(60);
164 | connect(sliderOpacity, &QSlider::valueChanged,
165 | this, &ImageCropperDemo::onOpacityChanged);
166 |
167 | checkShowRectBorder->setCheckState(Qt::Checked);
168 | connect(checkShowRectBorder, &QCheckBox::stateChanged,
169 | this, &ImageCropperDemo::onShowRectBorder);
170 |
171 | setLabelColor(labelRectBorderColor, Qt::white);
172 | btnChooseRectBorderCorlor->setIcon(QIcon("res/color-palette.ico"));
173 | btnChooseRectBorderCorlor->setFixedWidth(40);
174 | connect(btnChooseRectBorderCorlor, &QPushButton::clicked,
175 | this, &ImageCropperDemo::onChooseRectBorderColor);
176 |
177 | setLabelColor(labelDragSquareColor, Qt::white);
178 | btnChooseDragSquareColor->setIcon(QIcon("res/color-palette.ico"));
179 | btnChooseDragSquareColor->setFixedWidth(40);
180 | connect(btnChooseDragSquareColor, &QPushButton::clicked,
181 | this, &ImageCropperDemo::onChooseDragSquareColor);
182 |
183 | connect(btnSavePreview, &QPushButton::clicked,
184 | this, &ImageCropperDemo::onSaveCroppedImage);
185 | connect(btnQuit, &QPushButton::clicked,
186 | this, &ImageCropperDemo::close);
187 |
188 | imgCropperLabel->update();
189 | }
190 |
191 |
192 | /*****************************************************************************
193 | *
194 | * slots
195 | *
196 | *****************************************************************************/
197 |
198 | void ImageCropperDemo::onChooseOriginalImage() {
199 | QString filename = QFileDialog::getOpenFileName(this, "Select a picture", "",
200 | "picture (*.jpg *.png *.bmp)");
201 | if (filename.isNull())
202 | return;
203 |
204 | QPixmap pixmap;
205 | if (!pixmap.load(filename)) {
206 | QMessageBox::critical(this, "Error", "Load image failed", QMessageBox::Ok);
207 | return;
208 | }
209 |
210 | editOriginalImagePath->setText(filename);
211 | imgCropperLabel->setOriginalImage(pixmap);
212 | imgCropperLabel->update();
213 | onUpdatePreview();
214 | labelPreviewImage->setFrameStyle(0);
215 | }
216 |
217 | void ImageCropperDemo::onOutputShapeChanged(int idx) {
218 | // Output: Rectangular
219 | if (idx == 0)
220 | imgCropperLabel->setOutputShape(OutputShape::RECT);
221 | else
222 | imgCropperLabel->setOutputShape(OutputShape::ELLIPSE);
223 | onUpdatePreview();
224 | }
225 |
226 | void ImageCropperDemo::onCropperShapeChanged(int idx) {
227 | switch (CropperShape(idx + 1)) {
228 | case CropperShape::RECT: {
229 | imgCropperLabel->setRectCropper();
230 | editCropperFixedWidth->setEnabled(false);
231 | editCropperFixedHeight->setEnabled(false);
232 | editCropperMinWidth->setEnabled(true);
233 | editCropperMinHeight->setEnabled(true);
234 | checkShowDragSquare->setEnabled(true);
235 | editDragSquareEdge->setEnabled(true);
236 | btnChooseDragSquareColor->setEnabled(true);
237 | break;
238 | }
239 | case CropperShape::SQUARE: {
240 | imgCropperLabel->setSquareCropper();
241 | editCropperFixedWidth->setEnabled(false);
242 | editCropperFixedHeight->setEnabled(false);
243 | editCropperMinWidth->setEnabled(true);
244 | editCropperMinHeight->setEnabled(true);
245 | checkShowDragSquare->setEnabled(true);
246 | editDragSquareEdge->setEnabled(true);
247 | btnChooseDragSquareColor->setEnabled(true);
248 | break;
249 | }
250 | case CropperShape::FIXED_RECT: {
251 | imgCropperLabel->setFixedRectCropper(QSize(64, 64));
252 | editCropperFixedWidth->setEnabled(true);
253 | editCropperFixedHeight->setEnabled(true);
254 | editCropperMinWidth->setEnabled(false);
255 | editCropperMinHeight->setEnabled(false);
256 | editCropperFixedWidth->setText("64");
257 | editCropperFixedHeight->setText("64");
258 | checkShowDragSquare->setEnabled(false);
259 | editDragSquareEdge->setEnabled(false);
260 | btnChooseDragSquareColor->setEnabled(false);
261 | break;
262 | }
263 | case CropperShape::ELLIPSE: {
264 | imgCropperLabel->setEllipseCropper();
265 | editCropperFixedWidth->setEnabled(false);
266 | editCropperFixedHeight->setEnabled(false);
267 | editCropperMinWidth->setEnabled(true);
268 | editCropperMinHeight->setEnabled(true);
269 | checkShowDragSquare->setEnabled(true);
270 | editDragSquareEdge->setEnabled(true);
271 | btnChooseDragSquareColor->setEnabled(true);
272 | break;
273 | }
274 | case CropperShape::CIRCLE: {
275 | imgCropperLabel->setCircleCropper();
276 | editCropperFixedWidth->setEnabled(false);
277 | editCropperFixedHeight->setEnabled(false);
278 | editCropperMinWidth->setEnabled(true);
279 | editCropperMinHeight->setEnabled(true);
280 | checkShowDragSquare->setEnabled(true);
281 | editDragSquareEdge->setEnabled(true);
282 | btnChooseDragSquareColor->setEnabled(true);
283 | break;
284 | }
285 | case CropperShape::FIXED_ELLIPSE:
286 | imgCropperLabel->setFixedEllipseCropper(QSize(64, 64));
287 | editCropperFixedWidth->setEnabled(true);
288 | editCropperFixedHeight->setEnabled(true);
289 | editCropperMinWidth->setEnabled(false);
290 | editCropperMinHeight->setEnabled(false);
291 | editCropperFixedWidth->setText("64");
292 | editCropperFixedHeight->setText("64");
293 | checkShowDragSquare->setEnabled(false);
294 | editDragSquareEdge->setEnabled(false);
295 | btnChooseDragSquareColor->setEnabled(false);
296 | break;
297 | case CropperShape::UNDEFINED:
298 | break;
299 | }
300 |
301 | imgCropperLabel->update();
302 | onUpdatePreview();
303 | }
304 |
305 | void ImageCropperDemo::onEnableOpacityChanged(int state) {
306 | if (state == Qt::Checked) {
307 | sliderOpacity->setEnabled(true);
308 | imgCropperLabel->enableOpacity(true);
309 | }
310 | else {
311 | sliderOpacity->setEnabled(false);
312 | imgCropperLabel->enableOpacity(false);
313 | }
314 | imgCropperLabel->update();
315 | }
316 |
317 | void ImageCropperDemo::onShowDragSquareChanged(int state) {
318 | if (state == Qt::Checked) {
319 | editDragSquareEdge->setEnabled(true);
320 | btnChooseDragSquareColor->setEnabled(true);
321 | imgCropperLabel->setShowDragSquare(true);
322 | }
323 | else {
324 | editDragSquareEdge->setEnabled(false);
325 | btnChooseDragSquareColor->setEnabled(false);
326 | imgCropperLabel->setShowDragSquare(false);
327 | }
328 | imgCropperLabel->update();
329 | }
330 |
331 | void ImageCropperDemo::onDragSquareEdgeChanged(QString edge) {
332 | imgCropperLabel->setDragSquareEdge(edge.toInt());
333 | imgCropperLabel->update();
334 | }
335 |
336 | void ImageCropperDemo::onOpacityChanged(int val) {
337 | imgCropperLabel->setOpacity(val / 100.0);
338 | imgCropperLabel->update();
339 | }
340 |
341 | void ImageCropperDemo::onFixedWidthChanged(QString width) {
342 | imgCropperLabel->setCropperFixedWidth(width.toInt());
343 | imgCropperLabel->update();
344 | }
345 |
346 | void ImageCropperDemo::onFixedHeightChanged(QString height) {
347 | imgCropperLabel->setCropperFixedHeight(height.toInt());
348 | imgCropperLabel->update();
349 | }
350 |
351 | void ImageCropperDemo::onMinWidthChanged(QString width) {
352 | imgCropperLabel->setCropperMinimumWidth(width.toInt());
353 | imgCropperLabel->update();
354 | }
355 |
356 | void ImageCropperDemo::onMinHeightChanged(QString height) {
357 | imgCropperLabel->setMinimumHeight(height.toInt());
358 | imgCropperLabel->update();
359 | }
360 |
361 | void ImageCropperDemo::onShowRectBorder(int state) {
362 | if (state == Qt::Checked) {
363 | btnChooseRectBorderCorlor->setEnabled(true);
364 | imgCropperLabel->setShowRectBorder(true);
365 | }
366 | else {
367 | btnChooseRectBorderCorlor->setEnabled(false);
368 | imgCropperLabel->setShowRectBorder(false);
369 | }
370 | imgCropperLabel->update();
371 | }
372 |
373 | void ImageCropperDemo::onChooseRectBorderColor() {
374 | QColor color = QColorDialog::getColor(imgCropperLabel->getBorderPen().color(), this);
375 | if (color.isValid()) {
376 | setLabelColor(labelRectBorderColor, color);
377 | QPen pen = imgCropperLabel->getBorderPen();
378 | pen.setColor(color);
379 | imgCropperLabel->setBorderPen(pen);
380 | imgCropperLabel->update();
381 | }
382 | }
383 |
384 | void ImageCropperDemo::onChooseDragSquareColor() {
385 | QColor color = QColorDialog::getColor(Qt::white, this);
386 | if (color.isValid()) {
387 | setLabelColor(labelDragSquareColor, color);
388 | imgCropperLabel->setDragSquareColor(color);
389 | imgCropperLabel->update();
390 | }
391 | }
392 |
393 | void ImageCropperDemo::onUpdatePreview() {
394 | QPixmap preview = imgCropperLabel->getCroppedImage();
395 | preview = preview.scaled(labelPreviewImage->width(), labelPreviewImage->height(),
396 | Qt::KeepAspectRatio, Qt::SmoothTransformation);
397 | labelPreviewImage->setPixmap(preview);
398 | }
399 |
400 | void ImageCropperDemo::onSaveCroppedImage() {
401 | const QPixmap* pixmap = labelPreviewImage->pixmap();
402 | if (!pixmap) {
403 | QMessageBox::information(this, "Error", "There is no cropped image to save.", QMessageBox::Ok);
404 | return ;
405 | }
406 |
407 | QString filename = QFileDialog::getSaveFileName(this, "Save cropped image", "", "picture (*.png)");
408 | if (!filename.isNull()) {
409 | if (imgCropperLabel->getCroppedImage().save(filename, "PNG"))
410 | QMessageBox::information(this, "Prompt", "Saved successfully", QMessageBox::Ok);
411 | else
412 | QMessageBox::information(this, "Error", "Save image failed!", QMessageBox::Ok);
413 | }
414 | }
415 |
416 |
--------------------------------------------------------------------------------
/example/imagecropperdemo.h:
--------------------------------------------------------------------------------
1 | #ifndef TESTIMAGECROPPERLABEL_H
2 | #define TESTIMAGECROPPERLABEL_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "../base/imagecropperlabel.h"
15 |
16 | class ImageCropperDemo : public QDialog
17 | {
18 | Q_OBJECT
19 | public:
20 | ImageCropperDemo(QWidget* parent = nullptr);
21 |
22 | void setupLayout();
23 |
24 | void init();
25 |
26 | public slots:
27 | void onOutputShapeChanged(int idx);
28 | void onCropperShapeChanged(int idx);
29 | void onEnableOpacityChanged(int state);
30 | void onShowDragSquareChanged(int state);
31 | void onDragSquareEdgeChanged(QString edge);
32 | void onOpacityChanged(int val);
33 | void onFixedWidthChanged(QString width);
34 | void onFixedHeightChanged(QString height);
35 | void onMinWidthChanged(QString width);
36 | void onMinHeightChanged(QString height);
37 | void onShowRectBorder(int state);
38 | void onChooseRectBorderColor();
39 | void onChooseDragSquareColor();
40 |
41 | void onChooseOriginalImage();
42 | void onUpdatePreview();
43 | void onSaveCroppedImage();
44 |
45 | private:
46 | void setLabelColor(QLabel* label, QColor color) {
47 | QPixmap pixmap(QSize(80, 25));
48 | pixmap.fill(color);
49 | label->setPixmap(pixmap);
50 | }
51 |
52 | private:
53 | ImageCropperLabel* imgCropperLabel;
54 | QHBoxLayout* mainLayout;
55 |
56 | QLabel* labelPreviewImage;
57 |
58 | QComboBox* comboOutputShape;
59 | QComboBox* comboCropperShape;
60 |
61 | QLineEdit* editOriginalImagePath;
62 | QPushButton* btnChooseOriginalImagePath;
63 |
64 | QLineEdit* editCropperFixedWidth;
65 | QLineEdit* editCropperFixedHeight;
66 | QLineEdit* editCropperMinWidth;
67 | QLineEdit* editCropperMinHeight;
68 |
69 | QCheckBox* checkShowDragSquare;
70 | QCheckBox* checkEnableOpacity;
71 | QSlider* sliderOpacity;
72 | QLineEdit* editDragSquareEdge;
73 |
74 | QCheckBox* checkShowRectBorder;
75 | QLabel* labelRectBorderColor;
76 | QPushButton* btnChooseRectBorderCorlor;
77 |
78 | QLabel* labelDragSquareColor;
79 | QPushButton* btnChooseDragSquareColor;
80 |
81 | QPushButton* btnSavePreview;
82 | QPushButton* btnQuit;
83 | };
84 |
85 | #endif // TESTIMAGECROPPERLABEL_H
86 |
--------------------------------------------------------------------------------
/example/main.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | #include
4 |
5 | int main(int argc, char *argv[])
6 | {
7 | QApplication a(argc, argv);
8 | MainWindow w;
9 | w.show();
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/example/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include "imagecropperdemo.h"
3 |
4 | #include "../base/imagecropperdialog.h"
5 |
6 | #include
7 | #include
8 | #include
9 |
10 |
11 | MainWindow::MainWindow(QWidget *parent)
12 | : QMainWindow(parent)
13 | {
14 | setupLayout();
15 | }
16 |
17 | MainWindow::~MainWindow()
18 | {
19 | }
20 |
21 | void MainWindow::setupLayout() {
22 | QWidget* centralWidget = new QWidget(this);
23 |
24 | btnCustomCrop = new QPushButton("Custom Crop", centralWidget);
25 | btnSimpleCrop = new QPushButton("Simple Crop", centralWidget);
26 |
27 | QVBoxLayout* mainLayout = new QVBoxLayout(centralWidget);
28 | mainLayout->addWidget(btnCustomCrop);
29 | mainLayout->addWidget(btnSimpleCrop);
30 | this->setCentralWidget(centralWidget);
31 |
32 | connect(btnCustomCrop, &QPushButton::clicked, this, &MainWindow::onCustomCrop);
33 | connect(btnSimpleCrop, &QPushButton::clicked, this, &MainWindow::onSimpleCrop);
34 | }
35 |
36 | void MainWindow::onCustomCrop() {
37 | ImageCropperDemo* dialog = new ImageCropperDemo(this);
38 | dialog->show();
39 | }
40 |
41 | void MainWindow::onSimpleCrop() {
42 | QMessageBox::information(this, "Prompt", "Please select a picture", QMessageBox::Ok);
43 | QString filename = QFileDialog::getOpenFileName(this, "Select image", "", "image (*.png *.jpg)");
44 | if (filename.isNull())
45 | return;
46 |
47 | // *********
48 | // *******
49 | // *****
50 | // ***
51 | // *
52 | QPixmap image = ImageCropperDialog::getCroppedImage(filename, 600, 400, CropperShape::CIRCLE);
53 | if (image.isNull())
54 | return;
55 |
56 | QDialog* dialog = new QDialog(nullptr);
57 | dialog->setAttribute(Qt::WA_DeleteOnClose, true);
58 | QLabel* label = new QLabel(dialog);
59 | label->setFixedSize(image.size());
60 | label->setPixmap(image);
61 | dialog->exec();
62 | }
63 |
--------------------------------------------------------------------------------
/example/mainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINWINDOW_H
2 | #define MAINWINDOW_H
3 |
4 | #include
5 | #include
6 |
7 | class MainWindow : public QMainWindow
8 | {
9 | Q_OBJECT
10 |
11 | public:
12 | MainWindow(QWidget *parent = nullptr);
13 | ~MainWindow();
14 |
15 | public slots:
16 | void onCustomCrop();
17 | void onSimpleCrop();
18 |
19 | private:
20 | void setupLayout();
21 |
22 | private:
23 | QPushButton* btnCustomCrop;
24 | QPushButton* btnSimpleCrop;
25 | };
26 | #endif // MAINWINDOW_H
27 |
--------------------------------------------------------------------------------
/res/color-palette.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/res/color-palette.ico
--------------------------------------------------------------------------------
/res/save.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/res/save.ico
--------------------------------------------------------------------------------
/res/select-file.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Leopard-C/ImageCropper/8fb7e22bc76676b3f7cf80cf5e80d3bcedaeb55c/res/select-file.ico
--------------------------------------------------------------------------------