kopia lustrzana https://github.com/EmbroidePy/pyembroidery
Porównaj commity
2 Commity
2c2c1a77b6
...
db3874907a
Autor | SHA1 | Data |
---|---|---|
Tatarize | db3874907a | |
Tatarize | 7ed9a1270b |
|
@ -1,5 +1,6 @@
|
|||
import struct
|
||||
import zlib
|
||||
from math import sqrt
|
||||
|
||||
from .EmbConstant import *
|
||||
from .EmbThread import EmbThread
|
||||
|
@ -7,6 +8,7 @@ from .EmbThread import EmbThread
|
|||
SEQUIN_CONTINGENCY = CONTINGENCY_SEQUIN_STITCH
|
||||
FULL_JUMP = True
|
||||
|
||||
# Static characters for writing to image.
|
||||
characters = {
|
||||
"0": [
|
||||
[9, 9, 4, 1, 0, 1, 5, 9, 9],
|
||||
|
@ -192,6 +194,9 @@ characters = {
|
|||
|
||||
|
||||
def write_png(buf, width, height):
|
||||
"""
|
||||
Writes PNG file to disk. Buffer must be RGBA * width * height
|
||||
"""
|
||||
width_byte_4 = width * 4
|
||||
raw_data = b"".join(
|
||||
b"\x00" + buf[span : span + width_byte_4]
|
||||
|
@ -220,29 +225,91 @@ class PngBuffer:
|
|||
def __init__(self, width, height):
|
||||
self.width = int(width + 3)
|
||||
self.height = int(height + 3)
|
||||
self.buf = [0] * (4 * self.width * self.height)
|
||||
self.red = 0
|
||||
self.green = 0
|
||||
self.blue = 0
|
||||
self.alpha = 0
|
||||
self.buf = bytearray(4 * self.width * self.height)
|
||||
self.line_width = 3
|
||||
self.fancy = True
|
||||
self.fancy_stops = (0, 0.05, 0.5, 0.95, 0)
|
||||
self.values = (-120, 0, -120, 0, -120)
|
||||
self._red = 0
|
||||
self._green = 0
|
||||
self._blue = 0
|
||||
self._alpha = 0
|
||||
self._distance_from_black = 0
|
||||
self._gradient_shade_ends = 0.65
|
||||
self._gradient_shade_edge = 1.1
|
||||
self._gradient_shade_center = 1.55
|
||||
self._gradient_color_position1 = 0.40
|
||||
self._gradient_color_position2 = 0.50
|
||||
self._gradient_color_position3 = 0.70
|
||||
|
||||
def set_color(self, r, g, b):
|
||||
self.red = r
|
||||
self.green = g
|
||||
self.blue = b
|
||||
def modify_gradient(
|
||||
self,
|
||||
gradient_shade_ends=0.65,
|
||||
gradient_shade_edge=1.1,
|
||||
gradient_shade_center=1.55,
|
||||
gradient_color_position1=0.40,
|
||||
gradient_color_position2=0.50,
|
||||
gradient_color_position3=0.70,
|
||||
):
|
||||
self._gradient_shade_ends = gradient_shade_ends
|
||||
self._gradient_shade_edge = gradient_shade_edge
|
||||
self._gradient_shade_center = gradient_shade_center
|
||||
self._gradient_color_position1 = gradient_color_position1
|
||||
self._gradient_color_position2 = gradient_color_position2
|
||||
self._gradient_color_position3 = gradient_color_position3
|
||||
|
||||
def gradient(self, v):
|
||||
if v <= 0.05:
|
||||
return ((v - 0) * (1/0.05)) * (1.0 - 0.5) + 0.5
|
||||
if v <= 0.5:
|
||||
return ((v - 0.05) * (1/0.45)) * (0.5 - 1.0) + 1.0
|
||||
if v <= 0.9:
|
||||
return ((v - 0.5) * (1 / 0.40)) * (1.0 - 0.5) + 0.5
|
||||
return ((v - .9) * (1 / 0.1)) * (0.5 - 1.0) + 1.0
|
||||
def set_color(self, r, g, b, a=255):
|
||||
self._red = r
|
||||
self._green = g
|
||||
self._blue = b
|
||||
self._alpha = a
|
||||
rmean = int(r / 2)
|
||||
self._distance_from_black = sqrt(
|
||||
(((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8)
|
||||
)
|
||||
|
||||
def gradient(self, position_in_line):
|
||||
"""
|
||||
This function gives different value scales between 0 and 1 which are used to multiply
|
||||
all the components of the color to create a darker value. This generally works save for
|
||||
black which is already (0,0,0) and can't increase value.
|
||||
"""
|
||||
if (
|
||||
position_in_line <= self._gradient_color_position1
|
||||
): # start_of_grdient -> Position 1
|
||||
from_shade = self._gradient_shade_ends
|
||||
to_shade = self._gradient_shade_edge
|
||||
range = self._gradient_color_position1 - 0 # Range of transition
|
||||
amount = (position_in_line - 0) * (1 / range)
|
||||
|
||||
# light to extra_light
|
||||
elif (
|
||||
position_in_line <= self._gradient_color_position2
|
||||
): # Position 1 -> Position 2.
|
||||
from_shade = self._gradient_shade_edge
|
||||
to_shade = self._gradient_shade_center
|
||||
range = self._gradient_color_position2 - self._gradient_color_position1
|
||||
amount = (position_in_line - self._gradient_color_position1) * (1 / range)
|
||||
|
||||
# center of gradient
|
||||
|
||||
# extra_light to light
|
||||
elif (
|
||||
position_in_line <= self._gradient_color_position3
|
||||
): # Position 2 -> Position 3
|
||||
from_shade = self._gradient_shade_center
|
||||
to_shade = self._gradient_shade_edge
|
||||
range = self._gradient_color_position3 - self._gradient_color_position2
|
||||
amount = (position_in_line - self._gradient_color_position2) * (1 / range)
|
||||
|
||||
# light to dark
|
||||
elif position_in_line <= 1: # Position 3 -> end_of_gradient
|
||||
from_shade = self._gradient_shade_edge
|
||||
to_shade = self._gradient_shade_ends
|
||||
range = 1 - self._gradient_color_position3
|
||||
amount = (position_in_line - self._gradient_color_position3) * (1 / range)
|
||||
else:
|
||||
raise ValueError("Did not occur within line.")
|
||||
v = amount * (to_shade - from_shade) + from_shade
|
||||
return max(min(v, 1.0), 0.0)
|
||||
|
||||
def background(self, red, green, blue, alpha):
|
||||
for i in range(0, len(self.buf), 4):
|
||||
|
@ -251,23 +318,69 @@ class PngBuffer:
|
|||
self.buf[i + 2] = blue
|
||||
self.buf[i + 3] = alpha
|
||||
|
||||
def plot(self, x, y, v=None):
|
||||
def plot(self, x, y, v=None, a=None):
|
||||
"""
|
||||
Plot a particular point in the canvas.
|
||||
:param x: x position to plot
|
||||
:param y: y position to plot
|
||||
:param v: value scale of particular color (0-1)
|
||||
:param a: alpha to set for this particular plot if not self.alpha
|
||||
:return:
|
||||
"""
|
||||
a = int(a) if a is not None else self._alpha
|
||||
if v is None:
|
||||
v = 1.0
|
||||
try:
|
||||
x += 1
|
||||
y += 1
|
||||
pos = (self.width * y) + x
|
||||
idx = pos * 4
|
||||
r = self.red
|
||||
g = self.green
|
||||
b = self.blue
|
||||
if v is not None:
|
||||
r = int(r * v)
|
||||
g = int(g * v)
|
||||
b = int(b * v)
|
||||
self.buf[idx] = r
|
||||
self.buf[idx + 1] = g
|
||||
self.buf[idx + 2] = b
|
||||
self.buf[idx + 3] = self.alpha
|
||||
background_a = self.buf[idx + 3]
|
||||
|
||||
# get rgb and check if close to black and make off dark gray
|
||||
# this makes black have highlights
|
||||
if self._distance_from_black < 15:
|
||||
r = 35
|
||||
g = 35
|
||||
b = 35
|
||||
r = r * v
|
||||
g = g * v
|
||||
b = b * v
|
||||
# end of check and make gray
|
||||
else:
|
||||
r = self._red * v
|
||||
g = self._green * v
|
||||
b = self._blue * v
|
||||
if 0 > r:
|
||||
r = 0
|
||||
if 0 > g:
|
||||
g = 0
|
||||
if 0 > b:
|
||||
b = 0
|
||||
if r > 255:
|
||||
r = 255
|
||||
if g > 255:
|
||||
g = 255
|
||||
if b > 255:
|
||||
b = 255
|
||||
if background_a != 0 and a != 255:
|
||||
s_alpha = a / 255.0
|
||||
s_background_a = background_a / 255.0
|
||||
one_minus_salpha = 1 - s_alpha
|
||||
|
||||
background_r = self.buf[idx]
|
||||
background_g = self.buf[idx + 1]
|
||||
background_b = self.buf[idx + 2]
|
||||
r = r * s_alpha + one_minus_salpha * background_r
|
||||
g = g * s_alpha + one_minus_salpha * background_g
|
||||
b = b * s_alpha + one_minus_salpha * background_b
|
||||
a = (s_alpha + one_minus_salpha * s_background_a) * 255
|
||||
self.buf[idx] = int(r)
|
||||
self.buf[idx + 1] = int(g)
|
||||
self.buf[idx + 2] = int(b)
|
||||
self.buf[idx + 3] = (
|
||||
int(a) - 4
|
||||
) # remove just a little opacity for background color tint show thru
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
|
@ -320,8 +433,10 @@ class PngBuffer:
|
|||
w = self.line_width
|
||||
left = w >> 1
|
||||
right = w - left
|
||||
v = self.gradient(index/max_pos)
|
||||
|
||||
if self.fancy:
|
||||
v = self.gradient(index / max_pos)
|
||||
else:
|
||||
v = 1.0
|
||||
if dy:
|
||||
for pos in range(-left, right):
|
||||
self.plot(x + pos, y, v)
|
||||
|
@ -364,6 +479,27 @@ class PngBuffer:
|
|||
x += 11
|
||||
|
||||
|
||||
def draw_guides(draw_buff, extends):
|
||||
width = int(extends[2] - extends[0])
|
||||
height = int(extends[3] - extends[1])
|
||||
draw_buff.set_color(0, 0, 0, 255)
|
||||
draw_buff.line_width = 1
|
||||
min_x = int(extends[0])
|
||||
min_y = int(extends[1])
|
||||
points = 50
|
||||
draw_buff.draw_text(0, 0, "mm")
|
||||
for x in range(points - (min_x % points), width - 30, points):
|
||||
if x < 30:
|
||||
continue
|
||||
draw_buff.draw_text(x, 0, str(int((x + min_x) / 10)), rotate=True)
|
||||
draw_buff.draw_line(x, 0, x, 30)
|
||||
for y in range(points - (min_y % points), height - 30, points):
|
||||
if y < 30:
|
||||
continue
|
||||
draw_buff.draw_text(0, y, str(int((y + min_y) / 10)))
|
||||
draw_buff.draw_line(0, y, 30, y)
|
||||
|
||||
|
||||
def write(pattern, f, settings=None):
|
||||
guides = settings.get("guides", False)
|
||||
extends = pattern.bounds()
|
||||
|
@ -371,23 +507,23 @@ def write(pattern, f, settings=None):
|
|||
width = int(extends[2] - extends[0])
|
||||
height = int(extends[3] - extends[1])
|
||||
draw_buff = PngBuffer(width, height)
|
||||
draw_buff.fancy = settings.get("fancy", False)
|
||||
if settings is not None:
|
||||
background = settings.get("background", None)
|
||||
linewidth = settings.get("linewidth", None)
|
||||
background = settings.get("background")
|
||||
if background is not None:
|
||||
b = EmbThread()
|
||||
b.set(background)
|
||||
draw_buff.background(b.get_red(), b.get_green(), b.get_blue(), 0xFF)
|
||||
linewidth = settings.get("linewidth")
|
||||
if linewidth is not None and isinstance(linewidth, int):
|
||||
draw_buff.line_width = linewidth
|
||||
|
||||
for stitchblock in pattern.get_as_stitchblock():
|
||||
block = stitchblock[0]
|
||||
thread = stitchblock[1]
|
||||
draw_buff.red = thread.get_red()
|
||||
draw_buff.green = thread.get_green()
|
||||
draw_buff.blue = thread.get_blue()
|
||||
draw_buff.alpha = 255
|
||||
draw_buff.set_color(
|
||||
thread.get_red(), thread.get_green(), thread.get_blue(), 255
|
||||
)
|
||||
last_x = None
|
||||
last_y = None
|
||||
for stitch in block:
|
||||
|
@ -399,26 +535,6 @@ def write(pattern, f, settings=None):
|
|||
last_y = y
|
||||
|
||||
if guides:
|
||||
draw_buff.red = 0
|
||||
draw_buff.green = 0
|
||||
draw_buff.blue = 0
|
||||
draw_buff.alpha = 255
|
||||
draw_buff.line_width = 1
|
||||
min_x = extends[0]
|
||||
min_y = extends[1]
|
||||
points = 50
|
||||
draw_buff.draw_text(0, 0, "mm")
|
||||
for x in range(points - (min_x % points), width - 30, points):
|
||||
if x < 30:
|
||||
continue
|
||||
draw_buff.draw_text(x, 0, str(int((x + min_x) / 10)), rotate=True)
|
||||
draw_buff.draw_line(x, 0, x, 30)
|
||||
for y in range(points - (min_y % points), height - 30, points):
|
||||
if y < 30:
|
||||
continue
|
||||
draw_buff.draw_text(0, y, str(int((y + min_y) / 10)))
|
||||
draw_buff.draw_line(0, y, 30, y)
|
||||
draw_guides(draw_buff, extends)
|
||||
|
||||
f.write(
|
||||
write_png(bytes(bytearray(draw_buff.buf)), draw_buff.width, draw_buff.height)
|
||||
)
|
||||
f.write(write_png(draw_buff.buf, draw_buff.width, draw_buff.height))
|
||||
|
|
|
@ -16,6 +16,21 @@ class TestWrites(unittest.TestCase):
|
|||
write_png(get_shift_pattern(), file1, {"background": "#F00", "linewidth": 5})
|
||||
self.addCleanup(os.remove, file1)
|
||||
|
||||
def test_write_fancy_png(self):
|
||||
file1 = "file-fancy.png"
|
||||
write_png(get_shift_pattern(), file1, {"background": "#F00", "linewidth": 5, "fancy": True})
|
||||
self.addCleanup(os.remove, file1)
|
||||
|
||||
def test_write_guides_png(self):
|
||||
file1 = "file-guides.png"
|
||||
write_png(get_shift_pattern(), file1, {"background": "#F00", "linewidth": 5, "guides": True})
|
||||
self.addCleanup(os.remove, file1)
|
||||
|
||||
def test_write_fancy_guides_png(self):
|
||||
file1 = "file-fancy-guides.png"
|
||||
write_png(get_shift_pattern(), file1, {"background": "#F00", "linewidth": 5, "fancy": True, "guides": True})
|
||||
self.addCleanup(os.remove, file1)
|
||||
|
||||
def test_write_dst_read_dst(self):
|
||||
file1 = "file.dst"
|
||||
write_dst(get_big_pattern(), file1)
|
||||
|
|
Ładowanie…
Reference in New Issue