diff --git a/.pydevproject b/.pydevproject
index 0f52659..a5ee231 100644
--- a/.pydevproject
+++ b/.pydevproject
@@ -1,8 +1,8 @@
-
-
-Default
-python 3.0
-
-/${PROJECT_DIR_NAME}
-
-
+
+
+Python34
+python 3.0
+
+/${PROJECT_DIR_NAME}
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
index bed5cda..29a0b31 100644
--- a/.settings/org.eclipse.core.resources.prefs
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -35,6 +35,12 @@ encoding//\u5206\u5272\u7A97\u53E3\u7684\u5206\u5272\u6761\u91CD\u5199/Splitter.
encoding//\u52A8\u753B\u7279\u6548/\u53F3\u952E\u83DC\u5355\u52A8\u753B.py=utf-8
encoding//\u52A8\u753B\u7279\u6548/\u6DE1\u5165\u6DE1\u51FA.py=utf-8
encoding//\u53F3\u4E0B\u89D2\u5F39\u51FA\u6846/WindowNotify.py=utf-8
+encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/pyd\u7248\u672C/QtNinePatch/sip/configure.py=utf-8
+encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/pyd\u7248\u672C/QtNinePatch/sip/testQtNinePatch.py=utf-8
+encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/\u7EAFpython\u7248\u672C1/NinePatch.py=utf-8
+encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/\u7EAFpython\u7248\u672C1/testNinePatch.py=utf-8
+encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/\u7EAFpython\u7248\u672C2/QtNinePatch.py=utf-8
+encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/\u7EAFpython\u7248\u672C2/testQtNinePatch.py=utf-8
encoding//\u56FE\u7247\u52A0\u8F7D/LoadImage.py=utf-8
encoding//\u56FE\u7247\u52A0\u8F7D/SlippedImgWidget.py=utf-8
encoding//\u56FE\u7247\u52A0\u8F7D/res_rc.py=utf-8
diff --git a/图片/显示.9格式图片/README.md b/图片/显示.9格式图片/README.md
new file mode 100644
index 0000000..2d5b461
--- /dev/null
+++ b/图片/显示.9格式图片/README.md
@@ -0,0 +1,53 @@
+# .9格式图片显示(气泡)
+
+什么叫.9.PNG呢,这是安卓开发里面的一种特殊的图片
+这种格式的图片在android 环境下具有自适应调节大小的能力。
+
+
+(1)允许开发人员定义可扩展区域,当需要延伸图片以填充比图片本身更大区域时,可扩展区的内容被延展。
+
+(2)允许开发人员定义内容显示区,用于显示文字或其他内容
+
+目前手机QQ中很多漂亮的的聊天气泡就是.9格式的png图片
+
+在Github开源库中搜索到两个C++版本的
+
+1.一个是NinePatchQt https://github.com/Roninsc2/NinePatchQt
+
+2.一个是QtNinePatch https://github.com/soramimi/QtNinePatch
+
+### For PyQt
+1、目前针对第一个库在2年前用[纯python版本1](纯python版本1/)参考源码重新写一个见
+
+2、这次针对第二个写了[纯python版本2](纯python版本2/)的和[pyd编译好的](pyd版本)两个版本
+
+### 说明
+1、建议优先使用pyd版本的(后续提供Python3.4 3.5 3.6 3.7 编译好的32为库文件),也可以自行编译,编译步骤见下文。
+
+2、其次可以使用纯python版本2的(个人觉得方便调用)
+
+3、最后再考虑纯python版本1的吧
+
+4、以上为个人意见,两个C++版本的写法不一样,但是核心算法应该是类似的。
+
+### 自行编译
+
+1、首先要安装好PyQt5、编译安装对应的sip、对应的VC++编译工具
+
+2、用Qt Creator 打开pro文件进行编译
+
+3、进入源码中的sip文件夹
+
+4、修改configure.py文件
+
+```python
+# 这里是你的VC版本和对应的Qt目录中的文件夹
+config.platform = "win32-msvc2010"
+qt_path = 'D:/soft/Qt/Qt5.5.1/5.5/msvc2010'
+```
+
+5、python configure.py
+
+# 截图
+
+![截图1](ScreenShot/1.gif)
diff --git a/图片/显示.9格式图片/ScreenShot/1.gif b/图片/显示.9格式图片/ScreenShot/1.gif
new file mode 100644
index 0000000..0c3a73d
Binary files /dev/null and b/图片/显示.9格式图片/ScreenShot/1.gif differ
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.cpp b/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.cpp
new file mode 100644
index 0000000..6bda869
--- /dev/null
+++ b/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.cpp
@@ -0,0 +1,136 @@
+#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 horz;
+ std::vector 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);
+ }
+}
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.h b/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.h
new file mode 100644
index 0000000..782e4fa
--- /dev/null
+++ b/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.h
@@ -0,0 +1,26 @@
+#ifndef QTNINEPATCH_H
+#define QTNINEPATCH_H
+
+#include
+
+#if defined(QTNINEPATCHLIB_LIBRARY)
+# define QTNINEPATCHLIBSHARED_EXPORT Q_DECL_EXPORT
+#else
+# define QTNINEPATCHLIBSHARED_EXPORT Q_DECL_IMPORT
+#endif
+
+#include
+#include
+#include
+#include
+
+class QtNinePatch;
+
+class QTNINEPATCHLIBSHARED_EXPORT QtNinePatch
+{
+
+public:
+ static QPixmap createPixmapFromNinePatchImage(const QImage &, int, int);
+};
+
+#endif // QTNINEPATCH_H
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.pro b/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.pro
new file mode 100644
index 0000000..2910b39
--- /dev/null
+++ b/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.pro
@@ -0,0 +1,38 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2018-10-25T14:12:10
+#
+#-------------------------------------------------
+
+QT += core axcontainer gui
+
+#greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = QtNinePatch
+TEMPLATE = lib
+CONFIG += release
+CONFIG += warn_off exceptions_off hide_symbols
+
+#CONFIG += staticlib
+#CONFIG += dll static release
+
+DESTDIR = build
+DLLDESTDIR = build
+
+DEFINES += QTNINEPATCHLIB_LIBRARY
+
+SOURCES += QtNinePatch.cpp
+
+HEADERS += QtNinePatch.h
+
+unix {
+ target.path = /usr/lib
+ INSTALLS += target
+}
+
+DEFINES += _XKEYCHECK_H
+
+INCLUDEPATH += .
+INCLUDEPATH += $$[QT_INSTALL_HEADERS]
+
+LIBS += -L$$[QT_INSTALL_LIBS]
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.pro.user b/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.pro.user
new file mode 100644
index 0000000..70ed833
--- /dev/null
+++ b/图片/显示.9格式图片/pyd版本/QtNinePatch/QtNinePatch.pro.user
@@ -0,0 +1,202 @@
+
+
+
+
+
+ EnvironmentId
+ {52a31565-4664-45f3-a98d-2ef2ad3b26ae}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ false
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop Qt 5.5.1 MSVC2010 32bit
+ Desktop Qt 5.5.1 MSVC2010 32bit
+ qt.55.win32_msvc2010_kit
+ 0
+ 0
+ 0
+
+ F:/Python/PyhtonTest/PyQt/QtNinePatch/build
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+ true
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+
+ 2
+ 构建
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+
+ 1
+ 清理
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release
+
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+ 1
+
+
+ 0
+ 部署
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ 在本地部署
+
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ 2
+
+
+
+ %{buildDir}
+ 自定义执行档
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+ 3768
+ false
+ true
+ false
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 18
+
+
+ Version
+ 18
+
+
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.dll b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.dll
new file mode 100644
index 0000000..4ac6d92
Binary files /dev/null and b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.dll differ
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.pyd b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.pyd
new file mode 100644
index 0000000..73d7dc3
Binary files /dev/null and b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.pyd differ
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.sip b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.sip
new file mode 100644
index 0000000..a5a56d2
--- /dev/null
+++ b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/QtNinePatch.sip
@@ -0,0 +1,14 @@
+%Module QtNinePatch
+%Import QtCore/QtCoremod.sip
+%Import QtGui/QtGuimod.sip
+
+class QtNinePatch
+{
+%TypeHeaderCode
+#include "../QtNinePatch.h"
+%End
+
+public:
+ static QPixmap createPixmapFromNinePatchImage(const QImage &, int, int);
+
+};
\ No newline at end of file
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/configure.py b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/configure.py
new file mode 100644
index 0000000..eae22a5
--- /dev/null
+++ b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/configure.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# -*- encoding:utf-8 -*-
+
+import os
+import shutil
+
+import PyQt5
+from PyQt5.QtCore import PYQT_CONFIGURATION
+import sipconfig
+
+
+# 模块名
+moduleName = 'QtNinePatch'
+
+# The name of the SIP build file generated by SIP and used by the build
+# system.
+build_file = '%s.sbf' % moduleName
+
+# Get the SIP configuration information.
+config = sipconfig.Configuration()
+# pyqt5.5 + python34 + msvc 2010
+config.platform = "win32-msvc2010"
+qt_path = 'D:/soft/Qt/Qt5.5.1/5.5/msvc2010'
+print('QT_DIR: %s' % qt_path)
+
+pyqtpath = os.path.dirname(PyQt5.__file__)
+print('PyQt5 path: ', pyqtpath)
+
+config.sip_bin = os.path.join(pyqtpath, 'sip.exe')
+config.default_sip_dir = os.path.join(pyqtpath, 'sip')
+
+sip_cmd = ' '.join([
+ config.sip_bin,
+ '-c', "build",
+ '-b', "build/" + build_file,
+ '-I', config.default_sip_dir + '/PyQt5',
+ PYQT_CONFIGURATION.get('sip_flags', ''),
+ '%s.sip' % moduleName,
+])
+
+os.makedirs('build', exist_ok=True)
+print(sip_cmd)
+os.system(sip_cmd)
+
+
+# Create the Makefile.
+makefile = sipconfig.SIPModuleMakefile(
+ config, build_file, dir='build'
+)
+
+# Add the library we are wrapping. The name doesn't include any platform
+# specific prefixes or extensions (e.g. the 'lib' prefix on UNIX, or the
+# '.dll' extension on Windows).
+
+# 添加头文件路径
+makefile.extra_include_dirs = [
+ '../', '.',
+ os.path.join(qt_path, 'include'),
+ os.path.join(qt_path, 'include', 'QtCore'),
+ os.path.join(qt_path, 'include', 'QtGui')
+]
+
+# 添加用C++编译的库文件路径
+makefile.extra_lib_dirs = [
+ os.path.abspath('../build'),
+ os.path.join(qt_path, 'lib'),
+]
+print(makefile.extra_lib_dirs)
+
+makefile.extra_libs = [
+ moduleName,
+ 'Qt5Core',
+ 'Qt5Gui'
+]
+print(makefile.extra_libs)
+
+# Generate the Makefile itself.
+makefile.generate()
+
+shutil.copy('../build/%s.dll' % moduleName, '%s.dll' % moduleName)
+
+os.chdir('build')
+os.system('nmake')
+
+os.chdir('../')
+shutil.copy('build/%s.pyd' % moduleName, '%s.pyd' % moduleName)
+print('ok')
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/skin_aio_friend_bubble_pressed.9.png b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/skin_aio_friend_bubble_pressed.9.png
new file mode 100644
index 0000000..9fc0aeb
Binary files /dev/null and b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/skin_aio_friend_bubble_pressed.9.png differ
diff --git a/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/testQtNinePatch.py b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/testQtNinePatch.py
new file mode 100644
index 0000000..35584c5
--- /dev/null
+++ b/图片/显示.9格式图片/pyd版本/QtNinePatch/sip/testQtNinePatch.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Created on 2018年10月25日
+@author: Irony
+@site: https://pyqt5.com https://github.com/892768447
+@email: 892768447@qq.com
+@file: testQtNinePatch
+@description:
+"""
+
+
+__Author__ = """By: Irony
+QQ: 892768447
+Email: 892768447@qq.com"""
+__Copyright__ = "Copyright (c) 2018 Irony"
+__Version__ = "Version 1.0"
+
+import sys
+
+from PyQt5.QtGui import QImage
+from PyQt5.QtWidgets import QApplication, QLabel
+
+from QtNinePatch import QtNinePatch
+
+
+class Label(QLabel):
+
+ def __init__(self, *args, **kwargs):
+ super(Label, self).__init__(*args, **kwargs)
+ #.9 格式的图片
+ self.image = QImage('skin_aio_friend_bubble_pressed.9.png')
+
+ def showEvent(self, event):
+ super(Label, self).showEvent(event)
+ pixmap = QtNinePatch.createPixmapFromNinePatchImage(
+ self.image, self.width(), self.height())
+ self.setPixmap(pixmap)
+
+ def resizeEvent(self, event):
+ super(Label, self).resizeEvent(event)
+ pixmap = QtNinePatch.createPixmapFromNinePatchImage(
+ self.image, self.width(), self.height())
+ self.setPixmap(pixmap)
+
+
+app = QApplication(sys.argv)
+w = Label()
+w.resize(400, 200)
+w.show()
+
+sys.exit(app.exec_())
diff --git a/图片/显示.9格式图片/纯python版本1/NinePatch.py b/图片/显示.9格式图片/纯python版本1/NinePatch.py
new file mode 100644
index 0000000..d2703af
--- /dev/null
+++ b/图片/显示.9格式图片/纯python版本1/NinePatch.py
@@ -0,0 +1,361 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Created on 2018年10月25日
+@author: Irony
+@site: https://pyqt5.com https://github.com/892768447
+@email: 892768447@qq.com
+@file: NinePatch
+@description:
+"""
+from math import fabs
+
+from PyQt5.QtCore import QRect
+from PyQt5.QtGui import QImage, QColor, QPainter, qRed, qGreen, qBlue, qAlpha
+
+
+__Author__ = """By: Irony
+QQ: 892768447
+Email: 892768447@qq.com"""
+__Copyright__ = "Copyright (c) 2018 Irony"
+__Version__ = "Version 1.0"
+
+
+class _Exception(Exception):
+
+ def __init__(self, imgW, imgH):
+ self.imgW = imgW
+ self.imgH = imgH
+
+
+class NinePatchException(Exception):
+
+ def __str__(self):
+ return "Nine patch error"
+
+
+class ExceptionIncorrectWidth(_Exception):
+
+ def __str__(self):
+ return "Input incorrect width. Mimimum width = :{imgW}".format(imgW=self.imgW)
+
+
+class ExceptionIncorrectWidthAndHeight(_Exception):
+
+ def __str__(self):
+ return "Input incorrect width width and height. Minimum width = :{imgW} . Minimum height = :{imgH}".format(imgW=self.imgW, imgH=self.imgH)
+
+
+class ExceptionIncorrectHeight(_Exception):
+
+ def __str__(self):
+ return "Input incorrect height. Minimum height = :{imgW}".format(imgW=self.imgW)
+
+
+class ExceptionNot9Patch(Exception):
+
+ def __str__(self):
+ return "It is not nine patch image"
+
+
+class NinePatch:
+
+ def __init__(self, fileName):
+ self.CachedImage = None # 缓存图片
+ self.OldWidth = -1
+ self.OldHeight = -1
+ self.ResizeDistancesX = []
+ self.ResizeDistancesY = [] # [(int,int)]数组
+ self.setImage(fileName)
+
+ def width(self):
+ return self.Image.width()
+
+ def height(self):
+ return self.Image.height()
+
+ def setImage(self, fileName):
+ self.Image = QImage(fileName)
+ if self.Image.isNull():
+ return
+
+ self.ContentArea = self.GetContentArea()
+ self.GetResizeArea()
+ if not self.ResizeDistancesX or not self.ResizeDistancesY:
+ raise ExceptionNot9Patch
+
+ def __del__(self):
+ if hasattr(self, "CachedImage"):
+ del self.CachedImage
+ if hasattr(self, "Image"):
+ del self.Image
+
+ def Draw(self, painter, x, y):
+ painter.drawImage(x, y, self.CachedImage)
+
+ def SetImageSize(self, width, height):
+ resizeWidth = 0
+ resizeHeight = 0
+ for i in range(len(self.ResizeDistancesX)):
+ resizeWidth += self.ResizeDistancesX[i][1]
+
+ for i in range(len(self.ResizeDistancesY)):
+ resizeHeight += self.ResizeDistancesY[i][1]
+
+ if (width < (self.Image.width() - 2 - resizeWidth) and height < (self.Image.height() - 2 - resizeHeight)):
+ raise ExceptionIncorrectWidthAndHeight(
+ self.Image.width() - 2, self.Image.height() - 2)
+
+ if (width < (self.Image.width() - 2 - resizeWidth)):
+ raise ExceptionIncorrectWidth(
+ self.Image.width() - 2, self.Image.height() - 2)
+
+ if (height < (self.Image.height() - 2 - resizeHeight)):
+ raise ExceptionIncorrectHeight(
+ self.Image.width() - 2, self.Image.height() - 2)
+
+ if (width != self.OldWidth or height != self.OldHeight):
+ self.OldWidth = width
+ self.OldHeight = height
+ self.UpdateCachedImage(width, height)
+
+ @classmethod
+ def GetContentAreaRect(self, width, height):
+ # print("GetContentAreaRect : width:%d height:%d" % (width, height))
+ return (QRect(self.ContentArea.x(), self.ContentArea.y(), (width - (self.Image.width() - 2 - self.ContentArea.width())),
+ (height - (self.Image.height() - 2 - self.ContentArea.height()))))
+
+ def DrawScaledPart(self, oldRect, newRect, painter):
+ if (newRect.width() and newRect.height()):
+ # print("DrawScaledPart newRect.width:%d newRect.height:%d" % (newRect.width() , newRect.height()))
+ img = self.Image.copy(oldRect)
+ img = img.scaled(newRect.width(), newRect.height())
+ painter.drawImage(newRect.x(), newRect.y(), img,
+ 0, 0, newRect.width(), newRect.height())
+
+ def DrawConstPart(self, oldRect, newRect, painter):
+ # print("DrawConstPart oldRect:{oldRect} newRect:{newRect}".format(oldRect = oldRect, newRect = newRect))
+ img = self.Image.copy(oldRect)
+ painter.drawImage(newRect.x(), newRect.y(), img, 0,
+ 0, newRect.width(), newRect.height())
+
+ def IsColorBlack(self, color):
+ r = qRed(color)
+ g = qGreen(color)
+ b = qBlue(color)
+ a = qAlpha(color)
+ if a < 128:
+ return False
+ return r < 128 and g < 128 and b < 128
+
+ def GetContentArea(self):
+ j = self.Image.height() - 1
+ left = 0
+ right = 0
+ for i in range(self.Image.width()):
+ if (self.IsColorBlack(self.Image.pixel(i, j)) and left == 0):
+ left = i
+ else:
+ if (left != 0 and self.IsColorBlack(self.Image.pixel(i, j))):
+ right = i
+
+ if (left and not right):
+ right = left
+
+ left -= 1
+ i = self.Image.width() - 1
+ top = 0
+ bot = 0
+
+ for j in range(self.Image.height()):
+ if (self.IsColorBlack(self.Image.pixel(i, j)) and top == 0):
+ top = j
+ else:
+ if (top and self.IsColorBlack(self.Image.pixel(i, j))):
+ bot = j
+
+ if (top and not bot):
+ bot = top
+ top -= 1
+ # print("GetContentArea left: %d top:%d %d %d" % (left, top, right - left, bot - top))
+ return (QRect(left, top, right - left, bot - top))
+
+ def GetResizeArea(self):
+ j = 0
+ left = 0
+ right = 0
+
+ for i in range(self.Image.width()):
+ if (self.IsColorBlack(self.Image.pixel(i, j)) and left == 0):
+ left = i
+ if (left and self.IsColorBlack(self.Image.pixel(i, j)) and not self.IsColorBlack(self.Image.pixel(i + 1, j))):
+ right = i
+ left -= 1
+ # print("ResizeDistancesX.append ", left, " ", right - left)
+ self.ResizeDistancesX.append((left, right - left))
+ right = 0
+ left = 0
+ i = 0
+ top = 0
+ bot = 0
+
+ for j in range(self.Image.height()):
+ if (self.IsColorBlack(self.Image.pixel(i, j)) and top == 0):
+ top = j
+
+ if (top and self.IsColorBlack(self.Image.pixel(i, j)) and not self.IsColorBlack(self.Image.pixel(i, j + 1))):
+ bot = j
+ top -= 1
+ # print("ResizeDistancesY.append ", top, " ", bot - top)
+ self.ResizeDistancesY.append((top, bot - top))
+ top = 0
+ bot = 0
+ # print(self.ResizeDistancesX, len(self.ResizeDistancesX))
+ # print(self.ResizeDistancesY, len(self.ResizeDistancesY))
+
+ def GetFactor(self, width, height, factorX, factorY):
+ topResize = width - (self.Image.width() - 2)
+ leftResize = height - (self.Image.height() - 2)
+ for i in range(len(self.ResizeDistancesX)):
+ topResize += self.ResizeDistancesX[i][1]
+ factorX += self.ResizeDistancesX[i][1]
+
+ for i in range(len(self.ResizeDistancesY)):
+ leftResize += self.ResizeDistancesY[i][1]
+ factorY += self.ResizeDistancesY[i][1]
+
+ factorX = float(topResize) / factorX
+ factorY = float(leftResize) / factorY
+ return factorX, factorY
+
+ def UpdateCachedImage(self, width, height):
+ # print("UpdateCachedImage: ", width, " " , height)
+ self.CachedImage = QImage(
+ width, height, QImage.Format_ARGB32_Premultiplied)
+ self.CachedImage.fill(QColor(0, 0, 0, 0))
+ painter = QPainter(self.CachedImage)
+ factorX = 0.0
+ factorY = 0.0
+ factorX, factorY = self.GetFactor(width, height, factorX, factorY)
+ # print("after GetFactor: ", width, height, factorX, factorY)
+ lostX = 0.0
+ lostY = 0.0
+ x1 = 0 # for image parts X
+ y1 = 0 # for image parts Y
+# widthResize # width for image parts
+# heightResize # height for image parts
+ resizeX = 0
+ resizeY = 0
+ offsetX = 0
+ offsetY = 0
+ for i in range(len(self.ResizeDistancesX)):
+ y1 = 0
+ offsetY = 0
+ lostY = 0.0
+ for j in range(len(self.ResizeDistancesY)):
+ widthResize = self.ResizeDistancesX[i][0] - x1
+ heightResize = self.ResizeDistancesY[j][0] - y1
+
+ self.DrawConstPart(QRect(x1 + 1, y1 + 1, widthResize, heightResize),
+ QRect(x1 + offsetX, y1 + offsetY, widthResize, heightResize), painter)
+
+ y2 = self.ResizeDistancesY[j][0]
+ heightResize = self.ResizeDistancesY[j][1]
+ resizeY = round(float(heightResize) * factorY)
+ lostY += resizeY - (float(heightResize) * factorY)
+ if (fabs(lostY) >= 1.0):
+ if (lostY < 0):
+ resizeY += 1
+ lostY += 1.0
+ else:
+ resizeY -= 1
+ lostY -= 1.0
+
+ self.DrawScaledPart(QRect(x1 + 1, y2 + 1, widthResize, heightResize),
+ QRect(x1 + offsetX, y2 + offsetY, widthResize, resizeY), painter)
+
+ x2 = self.ResizeDistancesX[i][0]
+ widthResize = self.ResizeDistancesX[i][1]
+ heightResize = self.ResizeDistancesY[j][0] - y1
+ resizeX = round(float(widthResize) * factorX)
+ lostX += resizeX - (float(widthResize) * factorX)
+ if (fabs(lostX) >= 1.0):
+ if (lostX < 0):
+ resizeX += 1
+ lostX += 1.0
+ else:
+ resizeX -= 1
+ lostX -= 1.0
+
+ self.DrawScaledPart(QRect(x2 + 1, y1 + 1, widthResize, heightResize),
+ QRect(x2 + offsetX, y1 + offsetY, resizeX, heightResize), painter)
+
+ heightResize = self.ResizeDistancesY[j][1]
+ self.DrawScaledPart(QRect(x2 + 1, y2 + 1, widthResize, heightResize),
+ QRect(x2 + offsetX, y2 + offsetY, resizeX, resizeY), painter)
+
+ y1 = self.ResizeDistancesY[j][0] + self.ResizeDistancesY[j][1]
+ offsetY += resizeY - self.ResizeDistancesY[j][1]
+
+ x1 = self.ResizeDistancesX[i][0] + self.ResizeDistancesX[i][1]
+ offsetX += resizeX - self.ResizeDistancesX[i][1]
+
+ x1 = self.ResizeDistancesX[len(
+ self.ResizeDistancesX) - 1][0] + self.ResizeDistancesX[len(self.ResizeDistancesX) - 1][1]
+ widthResize = self.Image.width() - x1 - 2
+ y1 = 0
+ lostX = 0.0
+ lostY = 0.0
+ offsetY = 0
+ for i in range(len(self.ResizeDistancesY)):
+ self.DrawConstPart(QRect(x1 + 1, y1 + 1, widthResize, self.ResizeDistancesY[i][0] - y1),
+ QRect(x1 + offsetX, y1 + offsetY, widthResize, self.ResizeDistancesY[i][0] - y1), painter)
+ y1 = self.ResizeDistancesY[i][0]
+ resizeY = round(float(self.ResizeDistancesY[i][1]) * factorY)
+ lostY += resizeY - (float(self.ResizeDistancesY[i][1]) * factorY)
+ if (fabs(lostY) >= 1.0):
+ if (lostY < 0):
+ resizeY += 1
+ lostY += 1.0
+ else:
+ resizeY -= 1
+ lostY -= 1.0
+
+ self.DrawScaledPart(QRect(x1 + 1, y1 + 1, widthResize, self.ResizeDistancesY[i][1]),
+ QRect(x1 + offsetX, y1 + offsetY, widthResize, resizeY), painter)
+ y1 = self.ResizeDistancesY[i][0] + self.ResizeDistancesY[i][1]
+ offsetY += resizeY - self.ResizeDistancesY[i][1]
+
+ y1 = self.ResizeDistancesY[len(
+ self.ResizeDistancesY) - 1][0] + self.ResizeDistancesY[len(self.ResizeDistancesY) - 1][1]
+ heightResize = self.Image.height() - y1 - 2
+ x1 = 0
+ offsetX = 0
+ for i in range(len(self.ResizeDistancesX)):
+ self.DrawConstPart(QRect(x1 + 1, y1 + 1, self.ResizeDistancesX[i][0] - x1, heightResize),
+ QRect(x1 + offsetX, y1 + offsetY, self.ResizeDistancesX[i][0] - x1, heightResize), painter)
+ x1 = self.ResizeDistancesX[i][0]
+ resizeX = round(float(self.ResizeDistancesX[i][1]) * factorX)
+ lostX += resizeX - (float(self.ResizeDistancesX[i][1]) * factorX)
+ if (fabs(lostX) >= 1.0):
+ if (lostX < 0):
+ resizeX += 1
+ lostX += 1.0
+ else:
+ resizeX -= 1
+ lostX += 1.0
+
+ self.DrawScaledPart(QRect(x1 + 1, y1 + 1, self.ResizeDistancesX[i][1], heightResize),
+ QRect(x1 + offsetX, y1 + offsetY, resizeX, heightResize), painter)
+ x1 = self.ResizeDistancesX[i][0] + self.ResizeDistancesX[i][1]
+ offsetX += resizeX - self.ResizeDistancesX[i][1]
+
+ x1 = self.ResizeDistancesX[len(
+ self.ResizeDistancesX) - 1][0] + self.ResizeDistancesX[len(self.ResizeDistancesX) - 1][1]
+ widthResize = self.Image.width() - x1 - 2
+ y1 = self.ResizeDistancesY[len(
+ self.ResizeDistancesY) - 1][0] + self.ResizeDistancesY[len(self.ResizeDistancesY) - 1][1]
+ heightResize = self.Image.height() - y1 - 2
+ self.DrawConstPart(QRect(x1 + 1, y1 + 1, widthResize, heightResize),
+ QRect(x1 + offsetX, y1 + offsetY, widthResize, heightResize), painter)
diff --git a/图片/显示.9格式图片/纯python版本1/skin_aio_friend_bubble_pressed.9.png b/图片/显示.9格式图片/纯python版本1/skin_aio_friend_bubble_pressed.9.png
new file mode 100644
index 0000000..9fc0aeb
Binary files /dev/null and b/图片/显示.9格式图片/纯python版本1/skin_aio_friend_bubble_pressed.9.png differ
diff --git a/图片/显示.9格式图片/纯python版本1/testNinePatch.py b/图片/显示.9格式图片/纯python版本1/testNinePatch.py
new file mode 100644
index 0000000..016f50c
--- /dev/null
+++ b/图片/显示.9格式图片/纯python版本1/testNinePatch.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Created on 2018年10月25日
+@author: Irony
+@site: https://pyqt5.com https://github.com/892768447
+@email: 892768447@qq.com
+@file: testNinePatch
+@description:
+"""
+
+
+__Author__ = """By: Irony
+QQ: 892768447
+Email: 892768447@qq.com"""
+__Copyright__ = "Copyright (c) 2018 Irony"
+__Version__ = "Version 1.0"
+
+import sys
+
+from PyQt5.QtGui import QImage, QPainter
+from PyQt5.QtWidgets import QApplication, QLabel, QWidget
+
+from NinePatch import NinePatch
+
+
+class Label(QWidget):
+
+ def __init__(self, *args, **kwargs):
+ super(Label, self).__init__(*args, **kwargs)
+ #.9 格式的图片
+ self.image = NinePatch('skin_aio_friend_bubble_pressed.9.png')
+
+ def paintEvent(self, event):
+ super(Label, self).paintEvent(event)
+ painter = QPainter(self)
+ painter.setRenderHint(QPainter.Antialiasing)
+ painter.setRenderHint(QPainter.SmoothPixmapTransform)
+ try:
+ self.image.SetImageSize(self.width(), self.height())
+ self.image.Draw(painter, 0, 0)
+ except Exception as e:
+ print(e)
+
+
+app = QApplication(sys.argv)
+w = Label()
+w.resize(400, 200)
+w.show()
+
+sys.exit(app.exec_())
diff --git a/图片/显示.9格式图片/纯python版本2/QtNinePatch.py b/图片/显示.9格式图片/纯python版本2/QtNinePatch.py
new file mode 100644
index 0000000..8131b9e
--- /dev/null
+++ b/图片/显示.9格式图片/纯python版本2/QtNinePatch.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Created on 2018年10月25日
+@author: Irony
+@site: https://pyqt5.com https://github.com/892768447
+@email: 892768447@qq.com
+@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: 892768447@qq.com"""
+__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)
diff --git a/图片/显示.9格式图片/纯python版本2/skin_aio_friend_bubble_pressed.9.png b/图片/显示.9格式图片/纯python版本2/skin_aio_friend_bubble_pressed.9.png
new file mode 100644
index 0000000..9fc0aeb
Binary files /dev/null and b/图片/显示.9格式图片/纯python版本2/skin_aio_friend_bubble_pressed.9.png differ
diff --git a/图片/显示.9格式图片/纯python版本2/testQtNinePatch.py b/图片/显示.9格式图片/纯python版本2/testQtNinePatch.py
new file mode 100644
index 0000000..3d1622c
--- /dev/null
+++ b/图片/显示.9格式图片/纯python版本2/testQtNinePatch.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Created on 2018年10月25日
+@author: Irony
+@site: https://pyqt5.com https://github.com/892768447
+@email: 892768447@qq.com
+@file: testQtNinePatch
+@description:
+"""
+
+
+__Author__ = """By: Irony
+QQ: 892768447
+Email: 892768447@qq.com"""
+__Copyright__ = "Copyright (c) 2018 Irony"
+__Version__ = "Version 1.0"
+
+import sys
+
+from PyQt5.QtGui import QImage
+from PyQt5.QtWidgets import QApplication, QLabel
+
+import QtNinePatch
+
+
+class Label(QLabel):
+
+ def __init__(self, *args, **kwargs):
+ super(Label, self).__init__(*args, **kwargs)
+ #.9 格式的图片
+ self.image = QImage('skin_aio_friend_bubble_pressed.9.png')
+
+ def showEvent(self, event):
+ super(Label, self).showEvent(event)
+ pixmap = QtNinePatch.createPixmapFromNinePatchImage(
+ self.image, self.width(), self.height())
+ self.setPixmap(pixmap)
+
+ def resizeEvent(self, event):
+ super(Label, self).resizeEvent(event)
+ pixmap = QtNinePatch.createPixmapFromNinePatchImage(
+ self.image, self.width(), self.height())
+ self.setPixmap(pixmap)
+
+
+app = QApplication(sys.argv)
+w = Label()
+w.resize(400, 200)
+w.show()
+
+sys.exit(app.exec_())