HOME/Articles/

pyqt example QtNinePatch2 (snippet)

Article Outline

Python pyqt (gui) example 'QtNinePatch2'

Functions in program:

  • def createPixmapFromNinePatchImage(image, dw, dh):
  • def resize9patch(image, dw, dh):
  • def isStretchableMarker(pixel):

QtNinePatch2

Python pyqt example: QtNinePatch2

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Created on 2018年10月25日
@author: Irony
@site: https://pyqt5.com , https://github.com/892768447
@email: [email protected]
@file: QtNinePatch
@description: 
"""
from math import floor

from PyQt5.QtCore import Qt, QRect
from PyQt5.QtGui import qAlpha, QPixmap, QPainter


__Author__ = """By: Irony
QQ: 892768447
Email: [email protected]"""
__Copyright__ = "Copyright (c) 2018 Irony"
__Version__ = "Version 1.0"


class Part:

    def __init__(self, pos=0, length=0, stretchable=False):
        self.pos = pos
        self.length = length
        self.stretchable = stretchable


def isStretchableMarker(pixel):
    return (qAlpha(pixel) >> 7) & 1


def resize9patch(image, dw, dh):
    sw = image.width()
    sh = image.height()
    if sw > 2 and sh > 2 and dw > 0 and dh > 0:
        pixmap = QPixmap(dw, dh)
        pixmap.fill(Qt.transparent)
        pr = QPainter(pixmap)
        pr.setRenderHint(QPainter.Antialiasing)
        pr.setRenderHint(QPainter.SmoothPixmapTransform)

        horz = []
        vert = []
        horz_stretch = 0
        vert_stretch = 0

        pos = 0
        last = image.pixel(1, 0)
        for x in range(1, sw - 1):
            nextP = image.pixel(x + 1, 0)
            if isStretchableMarker(last) != isStretchableMarker(nextP) or x == sw - 2:
                stretchable = isStretchableMarker(last)
                length = x - pos
                horz.append(Part(pos, length, stretchable))
                if stretchable:
                    horz_stretch += length
                last = nextP
                pos = x
        pos = 0
        last = image.pixel(0, 1)
        for y in range(1, sh - 1):
            nextP = image.pixel(0, y + 1)
            if isStretchableMarker(last) != isStretchableMarker(nextP) or y == sh - 2:
                stretchable = isStretchableMarker(last)
                length = y - pos
                vert.append(Part(pos, length, stretchable))
                if stretchable:
                    vert_stretch += length
                last = nextP
                pos = y

        horz_mul = 0
        vert_mul = 0
        if horz_stretch > 0:
            horz_mul = float((dw - (sw - 2 - horz_stretch)) / horz_stretch)
        if vert_stretch > 0:
            vert_mul = float((dh - (sh - 2 - vert_stretch)) / vert_stretch)
        dy0 = 0
        dy1 = 0
        vstretch = 0
        len_vert = len(vert)
        len_horz = len(horz)
        for i in range(len_vert):
            sy0 = vert[i].pos
            sy1 = vert[i].pos + vert[i].length
            if i + 1 == len_vert:
                dy1 = dh
            elif vert[i].stretchable:
                vstretch += float(vert[i].length * vert_mul)
                s = floor(vstretch)
                vstretch -= s
                dy1 += int(s)
            else:
                dy1 += vert[i].length
            dx0 = 0
            dx1 = 0
            hstretch = 0
            for j in range(len_horz):
                sx0 = horz[j].pos
                sx1 = horz[j].pos + horz[j].length
                if j + 1 == len_horz:
                    dx1 = dw
                elif horz[j].stretchable:
                    hstretch += float(horz[j].length * horz_mul)
                    s = floor(hstretch)
                    hstretch -= s
                    dx1 += int(s)
                else:
                    dx1 += horz[j].length
                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()


def createPixmapFromNinePatchImage(image, dw, dh):
    w = dw
    h = dh
    if w < image.width() or h < image.height():  # shrink
        w = max(image.width(), w)
        h = max(image.height(), h)
        pm1 = resize9patch(image, w, h)
        if pm1.isNull():
            return QPixmap()
        pm2 = QPixmap(dw, dh)
        pm2.fill(Qt.transparent)
        pr = QPainter(pm2)
        pr.setRenderHint(QPainter.Antialiasing)
        pr.setRenderHint(QPainter.SmoothPixmapTransform)
        pr.drawPixmap(0, 0, dw, dh, pm1, 0, 0, w, h)
        return pm2
    else:
        return resize9patch(image, dw, dh)