mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-08-17 00:20:42 +03:00
add drawing border
This commit is contained in:
parent
1dcf13c580
commit
97d78d1205
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
*.pyc
|
||||
*.egg-info
|
||||
.coverage
|
||||
weasy/tests/test_web/website/static/*result*
|
||||
|
||||
|
171
weasy/draw.py
171
weasy/draw.py
@ -23,6 +23,7 @@ import pangocairo
|
||||
from .css.computed_values import LENGTHS_TO_PIXELS
|
||||
from .formatting_structure import boxes
|
||||
from . import text
|
||||
import math
|
||||
|
||||
class CairoContext(cairo.Context):
|
||||
"""
|
||||
@ -39,6 +40,111 @@ class CairoContext(cairo.Context):
|
||||
color.red / 255., color.green / 255., color.blue / 255.,
|
||||
color.alpha)
|
||||
|
||||
class Point(object):
|
||||
def __init__(self, x, y):
|
||||
self.x = round(x)
|
||||
self.y = round(y)
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s (%d, %d)>' % (type(self).__name__, self.x, self.y)
|
||||
|
||||
def move_to(self, x, y):
|
||||
self.x +=x
|
||||
self.y +=y
|
||||
|
||||
def copy(self):
|
||||
"""Return copy of the point."""
|
||||
cls = type(self)
|
||||
return cls(self.x, self.y)
|
||||
|
||||
class Line(object):
|
||||
def __init__(self, point1, point2):
|
||||
self.first_point = point1
|
||||
self.second_point = point2
|
||||
self.type = "solid"
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s (%s, %s)>' % (type(self).__name__, self.first_point,
|
||||
self.second_point)
|
||||
|
||||
def translate(self, x, y):
|
||||
self.first_point.move(x, y)
|
||||
self.second_point.move(x, y)
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
diff_x = self.second_point.x - self.first_point.x
|
||||
diff_y = self.second_point.y - self.first_point.y
|
||||
return math.sqrt(math.pow(diff_x, 2) + math.pow(diff_y, 2))
|
||||
|
||||
def draw_path(self, context):
|
||||
context.move_to(self.first_point.x, self.first_point.y)
|
||||
context.line_to(self.second_point.x, self.second_point.y)
|
||||
|
||||
def copy(self):
|
||||
"""Return copy of the line."""
|
||||
cls = type(self)
|
||||
return cls(self.first_point.copy(), self.second_point.copy())
|
||||
|
||||
|
||||
class Trapezoid(object):
|
||||
def __init__(self, line1, line2):
|
||||
if line1.length > line2.length:
|
||||
self.long_base = line1
|
||||
self.small_base = line2
|
||||
else:
|
||||
self.long_base = line2
|
||||
self.small_base = line1
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s (%s, %s)>' % (type(self).__name__, self.small_base,
|
||||
self.small_base)
|
||||
|
||||
def get_points(self):
|
||||
return [self.long_base.first_point, self.small_base.first_point,
|
||||
self.small_base.second_point, self.long_base.second_point]
|
||||
|
||||
def get_all_lines(self):
|
||||
points = list(self.get_points())
|
||||
n = len (points)
|
||||
for i, point in enumerate(points):
|
||||
yield Line(points[i], points[(i+1)%n])
|
||||
|
||||
def get_side_lines(self):
|
||||
points = list(self.get_points())
|
||||
n = len (points)
|
||||
for i, point in enumerate(points):
|
||||
if i % 2 == 0:
|
||||
yield Line(points[i], points[(i+1)%n])
|
||||
|
||||
def get_middle_line(self):
|
||||
if self.long_base.first_point.x != self.long_base.second_point.x:
|
||||
x1 = self.long_base.first_point.x
|
||||
x2 = self.long_base.second_point.x
|
||||
else:
|
||||
x1 = (self.long_base.first_point.x + self.small_base.first_point.x)
|
||||
x1 = x1 / 2.
|
||||
x2 = x1
|
||||
if self.long_base.first_point.y != self.long_base.second_point.y:
|
||||
y1 = self.long_base.first_point.y
|
||||
y2 = self.long_base.second_point.y
|
||||
else:
|
||||
y1 = (self.long_base.first_point.y + self.small_base.first_point.y)
|
||||
y1 = y1 / 2.
|
||||
y2 = y1
|
||||
return Line(Point(x1,y1), Point(x2, y2))
|
||||
|
||||
def draw_path(self, context):
|
||||
for i, line in enumerate(self.get_all_lines()):
|
||||
if i == 0:
|
||||
context.move_to(line.first_point.x, line.first_point.y)
|
||||
context.line_to(line.second_point.x, line.second_point.y)
|
||||
|
||||
def translate(self, x, y):
|
||||
self.first_point.translate(x, y)
|
||||
self.second_point.translate(x, y)
|
||||
|
||||
|
||||
def draw_background(context, box):
|
||||
bg_color = box.style['background-color'][0]
|
||||
if bg_color.alpha > 0:
|
||||
@ -50,6 +156,68 @@ def draw_background(context, box):
|
||||
context.set_source_colorvalue(bg_color)
|
||||
context.fill()
|
||||
|
||||
|
||||
def draw_border(context, box):
|
||||
"""
|
||||
Draw the box border to a Cairo context.
|
||||
"""
|
||||
# TODO: implement border-spacing, border-collapse and the other border style
|
||||
|
||||
def get_edge(x, y, width, height):
|
||||
return (Point(x,y), Point(x+width,y), Point(x+width, y+height),
|
||||
Point(x, y+height))
|
||||
|
||||
def get_border_area():
|
||||
# border area
|
||||
x = box.position_x + box.margin_left
|
||||
y = box.position_y + box.margin_top
|
||||
border_edge = get_edge(x, y, box.border_width(), box.border_height())
|
||||
# padding area
|
||||
x = x + box.border_left_width
|
||||
y = y + box.border_top_width
|
||||
padding_edge = get_edge(x, y, box.padding_width(), box.padding_height())
|
||||
return border_edge, padding_edge
|
||||
|
||||
def get_lines(rectangle):
|
||||
n = len (rectangle)
|
||||
for i, point in enumerate(rectangle):
|
||||
yield Line(rectangle[i], rectangle[(i+1) % n])
|
||||
|
||||
def get_trapezoids():
|
||||
border_edge, padding_edge = get_border_area()
|
||||
for line1,line2 in zip(get_lines(border_edge), get_lines(padding_edge)):
|
||||
yield Trapezoid(line1, line2)
|
||||
|
||||
def draw_border_side(side, trapezoid):
|
||||
width = float(box.style['border-%s-width'%side][0].value)
|
||||
if box.style['border-%s-width'%side] == 0:
|
||||
return
|
||||
color = box.style['border-%s-color'%side][0]
|
||||
style = box.style['border-%s-style'%side][0].value
|
||||
if color.alpha > 0:
|
||||
context.save()
|
||||
if not style in ["dotted", "dashed"]:
|
||||
trapezoid.draw_path(context)
|
||||
context.clip()
|
||||
elif style == "dotted":
|
||||
#TODO:Find a way to make a dotted border
|
||||
context.set_dash([width], 0)
|
||||
elif style == "dashed":
|
||||
#TODO:Find a way to make a dashed border
|
||||
context.set_dash([4*width], 0)
|
||||
line = trapezoid.get_middle_line()
|
||||
line.draw_path(context)
|
||||
context.set_source_colorvalue(color)
|
||||
context.set_line_width(width)
|
||||
context.stroke()
|
||||
context.restore()
|
||||
|
||||
trapezoids_side = zip(["top", "right", "bottom", "left"], get_trapezoids())
|
||||
|
||||
for side, trapezoid in trapezoids_side:
|
||||
draw_border_side(side, trapezoid)
|
||||
|
||||
|
||||
def draw_text(context, textbox):
|
||||
"""
|
||||
Draw the given TextBox to a Cairo context from Pangocairo Context
|
||||
@ -67,6 +235,8 @@ def draw_box(context, box):
|
||||
|
||||
for child in box.children:
|
||||
draw_box(context, child)
|
||||
if box.border_left_width > 0:
|
||||
draw_border(context, box)
|
||||
|
||||
def draw_page(page, context):
|
||||
"""
|
||||
@ -74,6 +244,7 @@ def draw_page(page, context):
|
||||
"""
|
||||
draw_box(context, page.root_box)
|
||||
|
||||
|
||||
def draw_page_to_png(page, surface):
|
||||
"""
|
||||
Draw the given PageBox to a PNG file.
|
||||
|
@ -36,16 +36,10 @@ compute_dimensions.register(boxes.BlockBox)(
|
||||
|
||||
@compute_dimensions.register(boxes.LineBox)
|
||||
def line_dimensions(box):
|
||||
# TODO: real line box height
|
||||
# box.height = box.style.line_height
|
||||
# box.height = 0
|
||||
resolve_percentages(box)
|
||||
|
||||
@compute_dimensions.register(boxes.InlineBox)
|
||||
def inlinebox_dimensions(box):
|
||||
# TODO: real line box height
|
||||
# box.height = box.style.line_height
|
||||
# box.height = 0
|
||||
resolve_percentages(box)
|
||||
|
||||
def page_dimensions(box):
|
||||
|
@ -339,7 +339,16 @@ class LineBoxFormatting(object):
|
||||
|
||||
def compute_dimensions(self, box):
|
||||
"""Add the width and height in the linebox."""
|
||||
if isinstance(box, boxes.InlineBox) or isinstance(box, boxes.LineBox):
|
||||
if isinstance(box, boxes.LineBox):
|
||||
widths = []
|
||||
heights = []
|
||||
for child in box.children:
|
||||
self.compute_dimensions(child)
|
||||
widths.append(child.width)
|
||||
heights.append(child.height)
|
||||
box.width = sum(widths)
|
||||
box.height = max(heights)
|
||||
elif isinstance(box, boxes.InlineBox):
|
||||
widths = []
|
||||
heights = []
|
||||
for child in box.children:
|
||||
@ -413,12 +422,8 @@ class LineBoxFormatting(object):
|
||||
for child in self.flatten_tree(child, depth):
|
||||
resolve_percentages(child)
|
||||
yield child
|
||||
elif isinstance(child, boxes.TextBox):
|
||||
else:
|
||||
child.depth = depth
|
||||
resolve_percentages(child)
|
||||
yield child
|
||||
elif isinstance(child, boxes.InlineBlockBox):
|
||||
raise NotImplementedError
|
||||
elif isinstance(child, boxes.InlineLevelReplacedBox):
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -15,6 +15,13 @@ def index():
|
||||
@app.route('/', methods=("POST",))
|
||||
def post():
|
||||
content = request.values.get("content", "").strip("\r\n").strip(" ")
|
||||
|
||||
# Save the input HTML
|
||||
item = g.kalamar.open('files',{"name":"input.html"})
|
||||
item['data'].write(content)
|
||||
item.save()
|
||||
|
||||
|
||||
pdf_document = PDFDocument.from_string(content)
|
||||
pdf_document.do_layout()
|
||||
pdf_document.draw()
|
||||
@ -33,12 +40,7 @@ def post():
|
||||
item['data'].write(pdf_document.output.getvalue())
|
||||
item.save()
|
||||
|
||||
# Save the input HTML
|
||||
item = g.kalamar.open('files',{"name":"input.html"})
|
||||
item['data'].write(content)
|
||||
item.save()
|
||||
|
||||
image = png_document.get_png_data()
|
||||
|
||||
return render_template('index.html.jinja2', content=content, image=image)
|
||||
|
||||
|
@ -1,21 +1,17 @@
|
||||
<style>
|
||||
html {
|
||||
background-color:#CACACA;
|
||||
background-color:gray;
|
||||
font-family: DejaVu Sans Mono;
|
||||
font-size:15px;
|
||||
}
|
||||
|
||||
p {
|
||||
width:600px;
|
||||
margin:auto;
|
||||
}
|
||||
|
||||
.salem {
|
||||
color:blue;
|
||||
}
|
||||
|
||||
.melinda {
|
||||
color:#FF4500;
|
||||
width:480px;
|
||||
margin:40px;
|
||||
padding: 10px;
|
||||
border-width:20px;
|
||||
vertical-align:middle;
|
||||
border-width:1px;
|
||||
border-style:solid;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@ -23,13 +19,5 @@ h1 {
|
||||
}
|
||||
</style>
|
||||
<h1>Avancement de weasyprint</h1>
|
||||
<span style="font-size:200px; background-color:red;">R</span>
|
||||
<p><em>WeasyPrint</em> is very <strong>coooll !!!</strong> </p>
|
||||
|
||||
<p class="salem">Salem : Bon je teste avec une seule page, et de "weasyprinter" en png.La page est générée par weasyprint. Trop cool non?</p>
|
||||
<p class="salem" style="text-decoration : line-through;">Bon il y a pas les retours à la ligne, mais avec ca serait parfait pour cette semaine xD.</p>
|
||||
|
||||
|
||||
<p class="melinda">Mélinda : Cette semaine ou celle d'après, t'as le temps xD</p>
|
||||
|
||||
<p class="salem">Salem : Ben non, j'ai promis pour midi, j'ai tenu promesse. MOUAHAHAHHA !!!</p>
|
||||
<p>test test <img src="http://img41.xooimage.com/files/5/f/5/477876-2877733.jpg" border="1" alt=""/></p>
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 51 KiB |
Loading…
Reference in New Issue
Block a user