Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Markdown labels #209

Merged
merged 7 commits into from
Jun 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 139 additions & 34 deletions omero_figure/scripts/omero/figure_scripts/Figure_To_Pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@

try:
from reportlab.pdfgen import canvas
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import Paragraph
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
reportlab_installed = True
except ImportError:
reportlab_installed = False
Expand Down Expand Up @@ -1338,25 +1339,53 @@ def save_figure(self):

def draw_text(self, text, x, y, fontsize, rgb, align="center"):
""" Adds text to PDF. Overwritten for TIFF below """
ly = y + fontsize
ly = self.page_height - ly + 5
if markdown_imported:
# convert markdown to html
text = markdown.markdown(text)

y = self.page_height - y
c = self.figure_canvas
# Needs to be wide enough to avoid wrapping
para_width = self.page_width

red, green, blue = rgb
red = float(red)/255
green = float(green)/255
blue = float(blue)/255
c.setFont("Helvetica", fontsize)
c.setFillColorRGB(red, green, blue)

alignment = TA_LEFT
if (align == "center"):
c.drawCentredString(x, ly, text)
alignment = TA_CENTER
x = x - (para_width/2)
elif (align == "right"):
c.drawRightString(x, ly, text)
alignment = TA_RIGHT
x = x - para_width
elif (align == "left"):
c.drawString(x, ly, text)
pass
elif align == 'vertical':
# Switch axes
c.rotate(90)
c.drawCentredString(self.page_height - y, -(x + fontsize), text)
px = x
x = y
y = -px
# Align center
alignment = TA_CENTER
x = x - (para_width/2)

style_n = getSampleStyleSheet()['Normal']
style = ParagraphStyle(
'label',
parent=style_n,
alignment=alignment,
textColor=(red, green, blue),
fontSize=fontsize)

para = Paragraph(text, style)
w, h = para.wrap(para_width, y) # find required space
para.drawOn(c, x, y - h + int(fontsize * 0.25))

# Rotate back again
if align == 'vertical':
c.rotate(-90)

def draw_line(self, x, y, x2, y2, width, rgb):
Expand Down Expand Up @@ -1425,7 +1454,6 @@ def __init__(self, conn, script_params, export_images=None):

from omero.gateway import THISPATH
self.GATEWAYPATH = THISPATH
self.font_path = os.path.join(THISPATH, "pilfonts", "FreeSans.ttf")

self.ns = "omero.web.figure.tiff"
self.mimetype = "image/tiff"
Expand All @@ -1434,10 +1462,18 @@ def add_rois(self, panel, page):
""" TIFF export doesn't add ROIs to page (does it to panel)"""
pass

def get_font(self, fontsize):
def get_font(self, fontsize, bold=False, italics=False):
""" Try to load font from known location in OMERO """
font_name = "FreeSans.ttf"
if bold and italics:
font_name = "FreeSansBoldOblique.ttf"
elif bold:
font_name = "FreeSansBold.ttf"
elif italics:
font_name = "FreeSansOblique.ttf"
path_to_font = os.path.join(self.GATEWAYPATH, "pilfonts", font_name)
try:
font = ImageFont.truetype(self.font_path, fontsize)
font = ImageFont.truetype(path_to_font, fontsize)
except:
font = ImageFont.load(
'%s/pilfonts/B%0.2d.pil' % (self.GATEWAYPATH, 24))
Expand Down Expand Up @@ -1521,35 +1557,104 @@ def draw_line(self, x, y, x2, y2, width, rgb):
y += 1
y2 += 1

def draw_temp_label(self, text, fontsize, rgb):
"""Returns a new PIL image with text. Handles html."""
tokens = self.parse_html(text)

widths = []
heights = []
for t in tokens:
font = self.get_font(fontsize, t['bold'], t['italics'])
txt_w, txt_h = font.getsize(t['text'])
widths.append(txt_w)
heights.append(txt_h)

label_w = sum(widths)
label_h = max(heights)

temp_label = Image.new('RGBA', (label_w, label_h), (255, 255, 255, 0))
textdraw = ImageDraw.Draw(temp_label)

w = 0
for t in tokens:
font = self.get_font(fontsize, t['bold'], t['italics'])
txt_w, txt_h = font.getsize(t['text'])
textdraw.text((w, 0), t['text'], font=font, fill=rgb)
w += txt_w
return temp_label

def parse_html(self, html):
"""
Parse html to give list of tokens with bold or italics

Returns list of [{'text': txt, 'bold': true, 'italics': false}]
"""
in_bold = False
in_italics = False

# Remove any <p> tags
html = html.replace('<p>', '')
html = html.replace('</p>', '')

tokens = []
token = ""
i = 0
while i < len(html):
# look for start / end of b or i elements
start_bold = html[i:].startswith("<strong>")
end_bold = html[i:].startswith("</strong>")
start_ital = html[i:].startswith("<em>")
end_ital = html[i:].startswith("</em>")

if start_bold:
i += len("<strong>")
elif end_bold:
i += len("</strong>")
elif start_ital:
i += len("<em>")
elif end_ital:
i += len("</em>")

# if style has changed:
if start_bold or end_bold or start_ital or end_ital:
# save token with previous style
tokens.append({'text': token, 'bold': in_bold,
'italics': in_italics})
token = ""
if start_bold or end_bold:
in_bold = start_bold
elif start_ital or end_ital:
in_italics = start_ital
else:
token = token + html[i]
i += 1
tokens.append({'text': token, 'bold': in_bold, 'italics': in_italics})
return tokens

def draw_text(self, text, x, y, fontsize, rgb, align="center"):
""" Add text to the current figure page """
x = self.scale_coords(x)
y = y - 5 # seems to help, but would be nice to fix this!
y = self.scale_coords(y)
fontsize = self.scale_coords(fontsize)

font = self.get_font(fontsize)
txt_w, txt_h = font.getsize(text)
if markdown_imported:
# convert markdown to html
text = markdown.markdown(text)

temp_label = self.draw_temp_label(text, fontsize, rgb)

if align == "vertical":
# write text on temp image (transparent)
y = self.scale_coords(y)
x = int(round(x))
y = int(round(y))
temp_label = Image.new('RGBA', (txt_w, txt_h), (255, 255, 255, 0))
textdraw = ImageDraw.Draw(temp_label)
textdraw.text((0, 0), text, font=font, fill=rgb)
w = temp_label.rotate(90, expand=True)
# Use label as mask, so transparent part is not pasted
y = y - (w.size[1]/2)
self.tiff_figure.paste(w, (x, y), mask=w)
else:
y = y - 5 # seems to help, but would be nice to fix this!
y = self.scale_coords(y)
textdraw = ImageDraw.Draw(self.tiff_figure)
if align == "center":
x = x - (txt_w / 2)
elif align == "right":
x = x - txt_w
textdraw.text((x, y), text, font=font, fill=rgb)
temp_label = temp_label.rotate(90, expand=True)
y = y - (temp_label.size[1]/2)
elif align == "center":
x = x - (temp_label.size[0] / 2)
elif align == "right":
x = x - temp_label.size[0]
x = int(round(x))
y = int(round(y))
# Use label as mask, so transparent part is not pasted
self.tiff_figure.paste(temp_label, (x, y), mask=temp_label)

def save_page(self):
"""
Expand Down
26 changes: 20 additions & 6 deletions omero_figure/static/figure/css/figure.css
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,26 @@
.markdown-info {
padding: 3px 12px;
color: #aaa;
display: none;
text-align: right;
padding-left: 40px;
background: url(../images/markdown_light32x20.png) 0% center no-repeat;
}
.markdown-info:hover {
background: url(../images/markdown_dark32x20.png) 0% center no-repeat;
}
.editing .markdown-info {
.legend-container .markdown-info {
display: none;
}
.legend-container .editing .markdown-info {
display: block;
}

#labelsTab .markdown-info {
height: 18px;
margin: 9px 9px 0;
float: left"
}

/* hide appropriate collapse/hide button */
.legend-collapsed .collapse-legend{
display: none;
Expand Down Expand Up @@ -313,6 +321,9 @@
.label_layout {
position:absolute;
}
.label_layout p {
margin: 0;
}
.left_vlabels>div {
margin-bottom: 5px;
}
Expand All @@ -326,9 +337,10 @@

.left_vlabels{
position: absolute;
height: 100%;
right: 100%;
width:400px;
height: 300%;
top: -100%;
width: 300%;
text-align: center;
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
Expand All @@ -348,13 +360,15 @@
/* Classes here are generated in templates from 'top' etc See labelicon classes below */
.label_top {
bottom: 100%;
width: 100%;
width: 300%;
left: -100%;
text-align: center;
margin-bottom: 3px;
}
.label_bottom {
top: 100%;
width: 100%;
width: 300%;
left: -100%;
text-align:center;
}
.label_left {
Expand Down
12 changes: 8 additions & 4 deletions omero_figure/templates/figure/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -455,12 +455,13 @@ <h4 class="modal-title" id="addImagesLabel">Import from json</h4>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Legend Formatting</h4>
<h4 class="modal-title">Markdown Formatting</h4>
</div>
<div class="modal-body">
<p>
You can use "Markdown" syntax to add formatting to plain text. For example,
**this text will be bold** and this *word* will be italic.
**this text will be bold** and this *word* will be italic. NB: Links are not
supported for panel labels.
</p>

<table class="table">
Expand Down Expand Up @@ -876,9 +877,12 @@ <h5>Scalebar</h5>

<hr />

<h5>Add Labels</h5>
<form class="new-label-form form-inline" role="form">
<h5 style="float: left">Add Labels</h5>

<button type="button" class="btn btn-link markdown-info"
title="Use Markdown formatting. Click for more info..."></button>
<div class="clearfix"></div>
<form class="new-label-form form-inline" role="form">
</form>

<h5>Edit Labels</h5>
Expand Down
8 changes: 4 additions & 4 deletions src/js/views/panel_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
'height': h +'px'});

// container needs to be square for rotation to vertical
$('.left_vlabels', this.$el).css('width', h + 'px');
$('.left_vlabels', this.$el).css('width', 3 * h + 'px');

// update the img within the panel
var zoom = this.model.get('zoom'),
Expand Down Expand Up @@ -146,8 +146,8 @@
if (typeof ljson.text == 'undefined' && ljson.time) {
ljson.text = self.model.get_time_label_text(ljson.time);
} else {
// Escape all labels so they are safe
ljson.text = _.escape(ljson.text);
// Markdown also escapes all labels so they are safe
ljson.text = markdown.toHTML(ljson.text);
}
positions[l.position].push(ljson);
});
Expand All @@ -168,7 +168,7 @@
self.$el.append(html);

// need to force update of vertical labels layout
$('.left_vlabels', self.$el).css('width', self.$el.height() + 'px');
$('.left_vlabels', self.$el).css('width', 3 * self.$el.height() + 'px');

return this;
},
Expand Down
6 changes: 6 additions & 0 deletions src/js/views/right_panel_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,12 @@
events: {
"submit .new-label-form": "handle_new_label",
"click .dropdown-menu a": "select_dropdown_option",
"click .markdown-info": "markdownInfo",
},

markdownInfo: function(event) {
event.preventDefault();
$("#markdownInfoModal").modal('show');
},

// Handles all the various drop-down menus in the 'New' AND 'Edit Label' forms
Expand Down