PyQt/QLabel/Lib/QtNinePatch/QtNinePatch.cpp
2018-12-28 23:13:05 +08:00

136 lines
4.3 KiB
C++

#include "QtNinePatch.h"
struct Part {
bool stretchable;
int pos;
int len;
Part()
: stretchable(false)
, pos(0)
, len(0)
{
}
Part(int pos, int len, bool stretchable)
: stretchable(stretchable)
, pos(pos)
, len(len)
{
}
};
static inline bool isStretchableMarker(QRgb pixel)
{
return (qAlpha(pixel) >> 7) & 1;
}
static QPixmap resize9patch(QImage const &image, int dw, int dh)
{
int sw = image.width();
int sh = image.height();
if (sw > 2 && sh > 2 && dw > 0 && dh > 0) {
QPixmap pixmap(dw, dh);
pixmap.fill(Qt::transparent);
QPainter pr(&pixmap);
pr.setRenderHint(QPainter::SmoothPixmapTransform);
std::vector<Part> horz;
std::vector<Part> vert;
int horz_stretch = 0;
int vert_stretch = 0;
{
int pos;
QRgb last;
QRgb next;
pos = 0;
last = image.pixel(1, 0);
for (int x = 1; x < sw - 1; x++) {
next = image.pixel(x + 1, 0);
if (isStretchableMarker(last) != isStretchableMarker(next) || x == sw - 2) {
bool stretchable = isStretchableMarker(last);
int len = x - pos;
horz.push_back(Part(pos, len, stretchable));
if (stretchable) horz_stretch += len;
last = next;
pos = x;
}
}
pos = 0;
last = image.pixel(0, 1);
for (int y = 1; y < sh - 1; y++) {
next = image.pixel(0, y + 1);
if (isStretchableMarker(last) != isStretchableMarker(next) || y == sh - 2) {
bool stretchable = isStretchableMarker(last);
int len = y - pos;
vert.push_back(Part(pos, len, stretchable));
if (stretchable) vert_stretch += len;
last = next;
pos = y;
}
}
}
double horz_mul = 0;
double vert_mul = 0;
if (horz_stretch > 0) horz_mul = (double)(dw - (sw - 2 - horz_stretch)) / horz_stretch;
if (vert_stretch > 0) vert_mul = (double)(dh - (sh - 2 - vert_stretch)) / vert_stretch;
int dy0 = 0;
int dy1 = 0;
double vstretch = 0;
for (int i = 0; i < (int)vert.size(); i++) {
int sy0 = vert[i].pos;
int sy1 = vert[i].pos + vert[i].len;
if (i + 1 == (int)vert.size()) {
dy1 = dh;
} else if (vert[i].stretchable) {
vstretch += (double)vert[i].len * vert_mul;
double s = floor(vstretch);
vstretch -= s;
dy1 += (int)s;
} else {
dy1 += vert[i].len;
}
int dx0 = 0;
int dx1 = 0;
double hstretch = 0;
for (int j = 0; j < (int)horz.size(); j++) {
int sx0 = horz[j].pos;
int sx1 = horz[j].pos + horz[j].len;
if (j + 1 == (int)horz.size()) {
dx1 = dw;
} else if (horz[j].stretchable) {
hstretch += (double)horz[j].len * horz_mul;
double s = floor(hstretch);
hstretch -= s;
dx1 += (int)s;
} else {
dx1 += horz[j].len;
}
pr.drawImage(QRect(dx0, dy0, dx1 - dx0, dy1 - dy0), image, QRect(sx0 + 1, sy0 + 1, sx1 - sx0, sy1 - sy0));
dx0 = dx1;
}
dy0 = dy1;
}
return pixmap;
}
return QPixmap();
}
QPixmap QtNinePatch::createPixmapFromNinePatchImage(const QImage &image, int dw, int dh)
{
int w = dw;
int h = dh;
if (w < image.width() || h < image.height()) { // shrink
if (w < image.width()) w = image.width();
if (h < image.height()) h = image.height();
QPixmap pm1 = resize9patch(image, w, h);
if (pm1.isNull()) return QPixmap();
QPixmap pm2(dw, dh);
pm2.fill(Qt::transparent);
QPainter pr(&pm2);
pr.setRenderHint(QPainter::SmoothPixmapTransform);
pr.drawPixmap(0, 0, dw, dh, pm1, 0, 0, w, h);
return pm2;
} else {
return resize9patch(image, w, h);
}
}