import os
from kivy import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Line
class MyPaintWidget(Widget): def on_touch_down(self, touch): color = (0,0,0) with self.canvas: Color(*color) d = 30. touch.ud['line'] = Line(points=(touch.x, touch.y), width=1.4) def on_touch_move(self, touch): touch.ud['line'].points += [touch.x, touch.y] #res = self.spline(touch.ud['line'].points, [touch.x, touch.y]) #for point in res: # touch.ud['line'].points += point def _exportImage(self): dirname = App.get_running_app().user_data_dir self.export_to_png(os.path.join(dirname, 'firma.png'))
BoxLayout: orientation:'vertical' size_hint_y: None StackLayout: MDRaisedButton: text: 'Borrar' on_press: _painter_id.canvas.clear() size: '49dp', '40dp' MDRaisedButton: text: 'Grabar' on_press: _painter_id._exportImage() size: '49dp', '40dp' MyPaintWidget: id: _painter_id size:'300dp','300dp'
class MyPaintWidget(Widget): def on_touch_down(self, touch): color = (0,0,0) with self.canvas: Color(*color) d = 30.
if self.__valid(touch.x, touch.y):
touch.ud['line'] = Line(points=(touch.x, touch.y), width=1.4)
else: touch.ud['line'] = Line( width=1.4) def __valid(self, x,y): x0, y0 = self.pos# please change x1 = x0 + self.width y1 = y0 + self.height if x < x0: return False elif x > x1: return False if y < y0: return False elif y > y1: return False return True def on_touch_move(self, touch): x, y = touch.x, touch.y if self.__valid(x,y): touch.ud['line'].points += [x,y]
<widget>:
canvas.before:
Color:
rgba:(1,1,1,1)
Rectangle:
pos:self.pos
size: self.size
from kivy.core.image import Image
def remove_background_color(self, filename):
im = Image(filename) for x in range(im.width): for y in range(im.height): if im.read_pixel((x,y)) == (1,1,1,1): im.set_pixel((x,y), (1,1,1,0)) ### the im hasn't set_pixel method im.save()
# studentdb.py
from kivy.uix.widget import Widget
from kivy.graphics import Color, Line
from PIL import Image as ImagePil
class BezierBuilder: def binomialCoeff(self, n, k): C = [[0 for x in range(k+1)] for x in range(n+1)] # Calculate value of Binomial Coefficient in bottom up manner for i in range(n+1): for j in range(min(i, k)+1): # Base Cases if j == 0 or j == i: C[i][j] = 1 # Calculate value using previosly stored values else: C[i][j] = C[i-1][j-1] + C[i-1][j] return C[n][k] def Bernstein(self, n, k): "Bernstein polynomial" coeff = self.binomialCoeff(n, k) def _bpoly(x): return [coeff*xi**k*(1 - xi)**(n - k) for xi in x] return _bpoly def linspace(self, init=0, fin=1, num=200): delta = (fin-init)/float(num) lista= [init+pos*delta for pos, val in enumerate(range(num+1))] lista[-1] = fin return lista def outer(self, vecX, vecY): data = vecX[:] for pos, x in enumerate(vecX): data[pos] = (x*vecY[0], x*vecY[1]) return data def bezier(self, points, num=10): # points = [[x1,y1],[x2,y2], ... [xn, yn]] "Build Bézier curve from points." N = len(points) t = self.linspace(0, 1, num=num) #allocating space curve = [(0, 0) for i in range(num+1)] for ii in range(N): res = self.outer(self.Bernstein(N - 1, ii)(t), points[ii]) #print('=========') #print('{},{}'.format(len(curve),len(res))) for pos, rowcontent in enumerate(res): curve[pos] = (curve[pos][0]+rowcontent[0], curve[pos][1]+rowcontent[1]) return curve
class MyPaintWidget(Widget): has_border = False _line_border = None _bezier = BezierBuilder()
def on_touch_down(self, touch): color = (0,0,0) with self.canvas: Color(*color) d = 30. if self.__valid(touch.x, touch.y):
touch.ud['line'] = Line(points=(touch.x, touch.y), width=1.5)
else: touch.ud['line'] = Line( width=1.4)
if not self.has_border: self.__draw_border() def clear(self): self.canvas.clear() with self.canvas: Color(1,1,1) self.__draw_border()
def __valid(self, x,y): x0, y0 = self.pos
x1 = x0 + self.width y1 = y0 + self.height
if x < x0 or x > x1: return False if y < y0 or y > y1: return False return True def __draw_border(self): x0, y0 = self.pos
x1 = x0 + self.width y1 = y0 + self.height
Punto = namedtuple('Punto', ['x','y']) p1 = Punto(x0,y0) p2 = Punto(x0,y1) p3 = Punto(x1,y1) p4 = Punto(x1,y0) with self.canvas: Color(1,1,1) self._line_border = Line(points=(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, p1.x, p1.y), width=2)
def on_touch_move(self, touch): x, y = touch.x, touch.y if self.__valid(x,y):
point = self.spline(touch.ud['line'].points, (x,y)) for p in point: touch.ud['line'].points += p def _exportImage(self): # se borra el borde #if not(self._line_border is None): # lin = self._line_border.points = [] # del(lin) dirname = App.get_running_app().user_data_dir filename = os.path.join(dirname, 'firma.png') self.export_to_png(filename) self.remove_background_color(filename) def remove_background_color(self, filename): #return im = Imagepil.open(filename) im = im.convert('RGBA') pixdata = im.load() for y in range(im.size[1]): for x in range(im.size[0]): if pixdata[x,y] == (255,255,255,255): pixdata[x,y] = (255,255,255,0) im.save(filename,'PNG') def spline(self, points, newPoints): if len(points) < 4: return [newPoints] n = min([14, len(points)]) # 7 points puntos = points[-n:] points[-n:] = [] pt = list() while len(puntos) >1: pt.append((puntos.pop(0), puntos.pop(0))) pt.append(newPoints) return self._bezier.bezier(pt, num=20)
# studentdb.kv
MyPaintWidget: id: _painter_id size_hint: None, None size:'500dp','300dp' # this should be changed depending on your requirements
canvas.before: Color: rgba: 1, 1, 1, 1
Rectangle: pos: self.pos size: self.size
# buildozer.spec
...
requirements= pillow, <library_name_1>, <library_name_2>
...
#save_texture.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Line
from kivy.utils import get_color_from_hex
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from kivy.interactive import InteractiveLauncher
from PIL import Image as ImagePil
from collections import namedtuple
import base64
import os
class BezierBuilder:
def binomialCoeff(self, n, k):
# http://www.geeksforgeeks.org/dynamic-programming-set-9-binomial-coefficient/
C = [[0 for x in range(k + 1)] for x in range(n + 1)]
# Calculate value of Binomial Coefficient in bottom up manner
for i in range(n + 1):
for j in range(min(i, k) + 1):
# Base Cases
if j == 0 or j == i:
C[i][j] = 1
# Calculate value using previosly stored values
else:
C[i][j] = C[i - 1][j - 1] + C[i - 1][j]
return C[n][k]
def Bernstein(self, n, k):
"Bernstein polynomial"
coeff = self.binomialCoeff(n, k)
def _bpoly(x):
return [coeff * xi ** k * (1 - xi) ** (n - k) for xi in x]
return _bpoly
def linspace(self, init=0, fin=1, num=200):
delta = (fin - init) / float(num)
lista = [init + pos * delta for pos, val in enumerate(range(num + 1))]
lista[-1] = fin
return lista
def outer(self, vecX, vecY):
data = vecX[:]
for pos, x in enumerate(vecX):
data[pos] = (x * vecY[0], x * vecY[1])
return data
def bezier(self, points, num=10):
# points = [[x1,y1],[x2,y2], ... [xn, yn]]
"Build Bézier curve from points."
N = len(points)
t = self.linspace(0, 1, num=num)
# allocating space
curve = [(0, 0) for i in range(num + 1)]
for ii in range(N):
res = self.outer(self.Bernstein(N - 1, ii)(t), points[ii])
for pos, rowcontent in enumerate(res):
curve[pos] = (curve[pos][0] + rowcontent[0], curve[pos][1] + rowcontent[1])
return curve
class MyPaintWidget(Widget):
has_border = False
_line_border = None
_bezier = BezierBuilder()
def on_touch_down(self, touch):
color = (0, 0, 0)
with self.canvas:
Color(*color)
d = 30.
if self.collide_point(*touch.pos):
touch.ud['line'] = Line(points=(touch.x, touch.y), width=1.5)
else:
touch.ud['line'] = Line(width=1.4)
if not self.has_border:
self.__draw_border()
def clear(self):
self.canvas.clear()
with self.canvas:
Color(1, 1, 1)
self.__draw_border()
def __draw_border(self):
return True
x0, y0 = self.pos
x1 = x0 + self.width
y1 = y0 + self.height
Punto = namedtuple('Punto', ['x', 'y'])
p1 = Punto(x0, y0)
p2 = Punto(x0, y1)
p3 = Punto(x1, y1)
p4 = Punto(x1, y0)
with self.canvas:
Color(1, 1, 1)
self._line_border = Line(points=(p1.x, p1.y,
p2.x, p2.y, p3.x, p3.y, p4.x, p4.y,
p1.x, p1.y), width=2)
def on_touch_move(self, touch):
if self.collide_point(*touch.pos):
point = self.spline(touch.ud['line'].points, (touch.pos))
for p in point:
touch.ud['line'].points +=
p
def exportImage(self, filename=r"firma.png"):
dirname = App.get_running_app().user_data_dir
absolute_path = os.path.join(dirname, filename)
print(absolute_path)
self.export_to_png(absolute_path)
# self.remove_background_color(absolute_path)
# print encoded string
print (self.image_encode64(absolute_path))
def remove_background_color(self, filename):
# return
im = ImagePil.open(filename)
im = im.convert('RGBA')
pixdata = im.load()
for y in range(im.size[1]):
for x in range(im.size[0]):
if pixdata[x, y] == (255, 255, 255, 255):
pixdata[x, y] = (255, 255, 255, 0)
im.save(filename)
def image_encode64(self,filename):
"""
:param filename: image to encode in
:return: image as encoded string, eg. for saving into db or transport
over network
"""
with open(filename, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
def spline(self, points, newPoints):
if len(points) < 4:
return [newPoints]
n = min([14, len(points)]) # 7 points
puntos = points[-n:]
points[-n:] = []
pt = list()
while len(puntos) > 1:
pt.append((puntos.pop(0), puntos.pop(0)))
pt.append(newPoints)
return self._bezier.bezier(pt, num=20)
def set_color(self, new_color):
self.last_color = new_color
self.canvas.add(Color(*new_color))
class SaveTextureApp(App):
pass
if __name__ == '__main__':
#Window.clearcolor = get_color_from_hex('#ffffff')
SaveTextureApp().run()
#save_texture.kv
#:import C kivy.utils.get_color_from_hex
#:import MyPaintWidget save_texture
BoxLayout:
orientation:"vertical"
MyPaintWidget:
id: painter_id
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.
size
BoxLayout:
size_hint_y:0.3
Button:
text:"clear"
on_press: app.root.ids.painter_id.clear()
Button:
text:"OK"
on_press: app.root.ids.painter_id.exportImage()