Menu

[8f66b6]: / qdarkstyle / images.py  Maximize  Restore  History

Download this file

286 lines (213 with data), 8.7 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Utilities to process and convert svg images to png using palette colors.
"""
# Standard library imports
from __future__ import absolute_import, division, print_function
import logging
import os
import re
import tempfile
# Third party imports
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication
# Local imports
from qdarkstyle import (IMAGES_PATH, STYLES_SCSS_FILEPATH, QRC_FILEPATH, RC_PATH, SVG_PATH)
from qdarkstyle.palette import DarkPalette
IMAGE_BLACKLIST = ['base_palette']
TEMPLATE_QRC_HEADER = '''
<RCC warning="File created programmatically. All changes made in this file will be lost!">
<qresource prefix="{resource_prefix}">
'''
TEMPLATE_QRC_FILE = ' <file>rc/{fname}</file>'
TEMPLATE_QRC_FOOTER = '''
</qresource>
<qresource prefix="{style_prefix}">
<file>style.qss</file>
</qresource>
</RCC>
'''
_logger = logging.getLogger(__name__)
def _get_file_color_map(fname, palette):
"""
Return map of files (i.e states) to color from given palette.
"""
color_disabled = palette.COLOR_BACKGROUND_NORMAL
color_focus = palette.COLOR_SELECTION_LIGHT
color_pressed = palette.COLOR_SELECTION_NORMAL
color_normal = palette.COLOR_FOREGROUND_DARK
name, ext = fname.split('.')
files_map = {
fname: {
fname: color_normal,
name + '_disabled.' + ext: color_disabled,
name + '_focus.' + ext: color_focus,
name + '_pressed.' + ext: color_pressed,
}
}
for f, file_colors in files_map.items():
if f == fname:
break
assert file_colors
return file_colors
def _create_colored_svg(svg_path, temp_svg_path, color):
"""
Replace base svg with fill color.
"""
with open(svg_path, 'r') as fh:
data = fh.read()
base_color = '#ff0000' # Hardcoded in base svg files
new_data = data.replace(base_color, color)
with open(temp_svg_path, 'w') as fh:
fh.write(new_data)
def convert_svg_to_png(svg_path, png_path, height, width):
"""
Convert svg files to png files using Qt.
"""
size = QSize(height, width)
icon = QIcon(svg_path)
pixmap = icon.pixmap(size)
img = pixmap.toImage()
img.save(png_path)
def create_palette_image(base_svg_path=SVG_PATH, path=IMAGES_PATH,
palette=DarkPalette):
"""
Create palette image svg and png image on specified path.
"""
# Needed to use QPixmap
_ = QApplication([])
base_palette_svg_path = os.path.join(base_svg_path, 'base_palette.svg')
palette_svg_path = os.path.join(path, 'palette.svg')
palette_png_path = os.path.join(path, 'palette.png')
_logger.info("Creating palette image ...")
_logger.info("Base SVG: %s" % base_palette_svg_path)
_logger.info("To SVG: %s" % palette_svg_path)
_logger.info("To PNG: %s" % palette_png_path)
with open(base_palette_svg_path, 'r') as fh:
data = fh.read()
color_palette = palette.color_palette()
for color_name, color_value in color_palette.items():
data = data.replace('{{ ' + color_name + ' }}', color_value.lower())
with open(palette_svg_path, 'w+') as fh:
fh.write(data)
convert_svg_to_png(palette_svg_path, palette_png_path, 4000, 4000)
return palette_svg_path, palette_png_path
def create_images(base_svg_path=SVG_PATH, rc_path=RC_PATH,
palette=DarkPalette):
"""Create resources `rc` png image files from base svg files and palette.
Search all SVG files in `base_svg_path` excluding IMAGE_BLACKLIST,
change its colors using `palette` creating temporary SVG files, for each
state generating PNG images for each size `heights`.
Args:
base_svg_path (str, optional): [description]. Defaults to SVG_PATH.
rc_path (str, optional): [description]. Defaults to RC_PATH.
palette (DarkPalette, optional): Palette . Defaults to DarkPalette.
"""
# Needed to use QPixmap
_ = QApplication([])
temp_dir = tempfile.mkdtemp()
svg_fnames = [f for f in os.listdir(base_svg_path) if f.endswith('.svg')]
base_height = 32
# See: https://doc.qt.io/qt-5/scalability.html
heights = {
32: '.png',
64: '@2x.png',
}
_logger.info("Creating images ...")
_logger.info("SVG folder: %s" % base_svg_path)
_logger.info("TMP folder: %s" % temp_dir)
_logger.info("PNG folder: %s" % rc_path)
num_svg = len(svg_fnames)
num_png = 0
num_ignored = 0
# Get rc links from scss to check matches
rc_list = get_rc_links_from_scss()
num_rc_list = len(rc_list)
for height, ext in heights.items():
width = height
_logger.debug(" Size HxW (px): %s X %s" % (height, width))
for svg_fname in svg_fnames:
svg_name = svg_fname.split('.')[0]
# Skip blacklist
if svg_name not in IMAGE_BLACKLIST:
svg_path = os.path.join(base_svg_path, svg_fname)
color_files = _get_file_color_map(svg_fname, palette=palette)
_logger.debug(" Working on: %s"
% os.path.basename(svg_fname))
# Replace colors and create all file for different states
for color_svg_name, color in color_files.items():
temp_svg_path = os.path.join(temp_dir, color_svg_name)
_create_colored_svg(svg_path, temp_svg_path, color)
png_fname = color_svg_name.replace('.svg', ext)
png_path = os.path.join(rc_path, png_fname)
convert_svg_to_png(temp_svg_path, png_path, height, width)
num_png += 1
_logger.debug(" Creating: %s"
% os.path.basename(png_fname))
# Check if the rc_name is in the rc_list from scss
# only for the base size
if height == base_height:
rc_base = os.path.basename(rc_path)
png_base = os.path.basename(png_fname)
rc_name = '/' + os.path.join(rc_base, png_base)
try:
rc_list.remove(rc_name)
except ValueError:
pass
else:
num_ignored += 1
_logger.debug(" Ignored blacklist: %s"
% os.path.basename(svg_fname))
_logger.info("# SVG files: %s" % num_svg)
_logger.info("# SVG ignored: %s" % num_ignored)
_logger.info("# PNG files: %s" % num_png)
_logger.info("# RC links: %s" % num_rc_list)
_logger.info("# RC links not in RC: %s" % len(rc_list))
_logger.info("RC links not in RC: %s" % rc_list)
def generate_qrc_file(resource_prefix='qss_icons', style_prefix='qdarkstyle'):
"""
Generate the QRC file programmaticaly.
Search all RC folder for PNG images and create a QRC file.
Args:
resource_prefix (str, optional): Prefix used in resources.
Defaults to 'qss_icons'.
style_prefix (str, optional): Prefix used to this style.
Defaults to 'qdarkstyle'.
"""
files = []
_logger.info("Generating QRC file ...")
_logger.info("Resource prefix: %s" % resource_prefix)
_logger.info("Style prefix: %s" % style_prefix)
_logger.info("Searching in: %s" % RC_PATH)
# Search by png images
for fname in sorted(os.listdir(RC_PATH)):
files.append(TEMPLATE_QRC_FILE.format(fname=fname))
# Join parts
qrc_content = (TEMPLATE_QRC_HEADER.format(resource_prefix=resource_prefix)
+ '\n'.join(files)
+ TEMPLATE_QRC_FOOTER.format(style_prefix=style_prefix))
_logger.info("Writing in: %s" % QRC_FILEPATH)
# Write qrc file
with open(QRC_FILEPATH, 'w') as fh:
fh.write(qrc_content)
def get_rc_links_from_scss(pattern=r"\/.*\.png"):
"""
Get all rc links from scss file returning the list of unique links.
Args:
pattern (str): regex pattern to find the links.
Returns:
list(str): list of unique links found.
"""
with open(STYLES_SCSS_FILEPATH, 'r') as fh:
data = fh.read()
lines = data.split("\n")
compiled_exp = re.compile('(' + pattern + ')')
rc_list = []
for line in lines:
match = re.search(compiled_exp, line)
if match:
rc_list.append(match.group(1))
rc_list = list(set(rc_list))
return rc_list
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.