mirror of
https://github.com/iluvcapra/ptulsconv.git
synced 2025-12-31 17:00:46 +00:00
Added page count footer implementation
Added another validation
This commit is contained in:
@@ -15,6 +15,7 @@ from .validations import *
|
||||
from ptulsconv.pdf.supervisor_1pg import output_report as output_supervisor_1pg
|
||||
from ptulsconv.pdf.line_count import output_report as output_line_count
|
||||
from ptulsconv.pdf.talent_sides import output_report as output_talent_sides
|
||||
from ptulsconv.pdf.summary_log import output_report as output_summary
|
||||
|
||||
# field_map maps tags in the text export to fields in FMPXMLRESULT
|
||||
# - tuple field 0 is a list of tags, the first tag with contents will be used as source
|
||||
@@ -208,10 +209,14 @@ def convert(input_file, output_format='fmpxml', start=None, end=None, select_ree
|
||||
validate_non_empty_field(parsed, field='QN'),
|
||||
validate_non_empty_field(parsed, field='CN'),
|
||||
validate_non_empty_field(parsed, field='Char'),
|
||||
validate_non_empty_field(parsed, field='Title'),
|
||||
validate_dependent_value(parsed, key_field='CN',
|
||||
dependent_field='Char'),
|
||||
validate_dependent_value(parsed, key_field='CN',
|
||||
dependent_field='Actor'),):
|
||||
dependent_field='Actor'),
|
||||
validate_unique_count(parsed, field='Title', count=1),
|
||||
validate_unique_count(parsed, field='Spotting', count=1),
|
||||
validate_unique_count(parsed, field='Supervisor', count=1)):
|
||||
|
||||
print_warning(warning.report_message())
|
||||
|
||||
@@ -220,9 +225,12 @@ def convert(input_file, output_format='fmpxml', start=None, end=None, select_ree
|
||||
elif output_format == 'full':
|
||||
print("Sorry, the `full` output type is not yet supported.")
|
||||
normalized_records = normalize_record_keys(parsed)
|
||||
|
||||
output_supervisor_1pg(normalized_records)
|
||||
output_talent_sides(normalized_records)
|
||||
output_line_count(normalized_records)
|
||||
output_summary(normalized_records)
|
||||
|
||||
elif output_format == 'fmpxml':
|
||||
if xsl is None:
|
||||
fmp_dump(parsed, input_file, output)
|
||||
|
||||
@@ -1,6 +1,51 @@
|
||||
from reportlab.pdfbase.pdfmetrics import (getAscent, getDescent)
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.pdfgen import canvas
|
||||
import datetime
|
||||
|
||||
# This is from https://code.activestate.com/recipes/576832/ for
|
||||
# generating page count messages
|
||||
class NumberedCanvas(canvas.Canvas):
|
||||
def __init__(self, *args, **kwargs):
|
||||
canvas.Canvas.__init__(self, *args, **kwargs)
|
||||
self._saved_page_states = []
|
||||
self._report_date = datetime.datetime.now()
|
||||
|
||||
def showPage(self):
|
||||
self._saved_page_states.append(dict(self.__dict__))
|
||||
self._startPage()
|
||||
|
||||
def save(self):
|
||||
"""add page info to each page (page x of y)"""
|
||||
num_pages = len(self._saved_page_states)
|
||||
for state in self._saved_page_states:
|
||||
self.__dict__.update(state)
|
||||
self.draw_page_number(num_pages)
|
||||
canvas.Canvas.showPage(self)
|
||||
canvas.Canvas.save(self)
|
||||
|
||||
def draw_page_number(self, page_count):
|
||||
self.saveState()
|
||||
self.setFont("Futura", 10)
|
||||
self.drawString(0.5 * inch, 0.5 * inch, "Page %d of %d" % (self._pageNumber, page_count))
|
||||
right_edge = self._pagesize[0] - 0.5 * inch
|
||||
self.drawRightString(right_edge, 0.5 * inch, self._report_date.strftime("%c"))
|
||||
topline = self.beginPath()
|
||||
topline.moveTo(0.5 * inch, 0.75 * inch)
|
||||
topline.lineTo(right_edge, 0.75 * inch)
|
||||
self.setLineWidth(0.5)
|
||||
self.drawPath(topline)
|
||||
self.restoreState()
|
||||
|
||||
def time_format(mins):
|
||||
if mins < 60.:
|
||||
return "%im" % round(mins)
|
||||
else:
|
||||
m = round(mins)
|
||||
hh, mm = divmod(m, 60)
|
||||
return "%ih%im" % (hh, mm)
|
||||
|
||||
## draws the title block inside the given rect
|
||||
def draw_title_block(canvas, rect, record):
|
||||
(supervisor, client,), title = rect.divide_y([16., 16., ])
|
||||
title.draw_text_cell(canvas, record['Title'], "Futura", 18, inset_y=2.)
|
||||
@@ -56,8 +101,12 @@ class GRect:
|
||||
elif at <= 0:
|
||||
return self, None
|
||||
else:
|
||||
return (GRect(self.min_x, self.min_y, at, self.height),
|
||||
GRect(self.min_x + at, self.y, self.width - at, self.height))
|
||||
if direction == 'l':
|
||||
return (GRect(self.min_x, self.min_y, at, self.height),
|
||||
GRect(self.min_x + at, self.y, self.width - at, self.height))
|
||||
else:
|
||||
return (GRect(self.max_x - at, self.y, at, self.height),
|
||||
GRect(self.min_x, self.y, self.width - at, self.height))
|
||||
|
||||
def split_y(self, at, direction='u'):
|
||||
if at >= self.height:
|
||||
|
||||
@@ -10,7 +10,7 @@ from reportlab.lib import colors
|
||||
from reportlab.lib.styles import getSampleStyleSheet
|
||||
from reportlab.platypus import Paragraph, Table, TableStyle
|
||||
|
||||
from .common import GRect
|
||||
from .common import GRect, time_format, NumberedCanvas
|
||||
|
||||
import datetime
|
||||
|
||||
@@ -26,14 +26,6 @@ def build_columns(records, show_priorities = False):
|
||||
else:
|
||||
return str(l)
|
||||
|
||||
def time_format(mins):
|
||||
if mins < 60.:
|
||||
return "%im" % round(mins)
|
||||
else:
|
||||
m = round(mins)
|
||||
hh, mm = divmod(m, 60)
|
||||
return "%ih%im" % (hh, mm)
|
||||
|
||||
columns.append({
|
||||
'heading': '#',
|
||||
'value_getter': lambda recs: recs[0]['Character Number'],
|
||||
@@ -180,7 +172,7 @@ def output_report(records):
|
||||
page = page.inset(inch * 0.5)
|
||||
title_box, table_box = page.split_y(inch, 'd')
|
||||
|
||||
c = Canvas('Line Count.pdf', pagesize=(letter[1], letter[0]))
|
||||
c = NumberedCanvas('Line Count.pdf', pagesize=(letter[1], letter[0]))
|
||||
c.setFont('Futura', 18.)
|
||||
c.drawCentredString(title_box.center_x, title_box.center_y, "Line Count")
|
||||
|
||||
|
||||
114
ptulsconv/pdf/summary_log.py
Normal file
114
ptulsconv/pdf/summary_log.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .common import GRect, draw_title_block, time_format, NumberedCanvas
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.pagesizes import letter, landscape, portrait
|
||||
|
||||
from reportlab.platypus import BaseDocTemplate, Paragraph, Spacer, \
|
||||
KeepTogether, Table, HRFlowable, PageTemplate, Frame
|
||||
from reportlab.lib.styles import getSampleStyleSheet
|
||||
from reportlab.lib import colors
|
||||
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.ttfonts import TTFont
|
||||
|
||||
|
||||
def build_aux_data_field(line):
|
||||
entries = list()
|
||||
if 'Reason' in line.keys():
|
||||
entries.append("Reason: " + line["Reason"])
|
||||
if 'Note' in line.keys():
|
||||
entries.append("Note: " + line["Note"])
|
||||
if 'Requested by' in line.keys():
|
||||
entries.append("Requested by: " + line["Requested by"])
|
||||
if 'Shot' in line.keys():
|
||||
entries.append("Shot: " + line["Shot"])
|
||||
|
||||
tag_field = ""
|
||||
for tag in line.keys():
|
||||
if line[tag] == tag and tag != 'ADR':
|
||||
tag_field += "<font backColor=black textColor=white>" + tag + "</font> "
|
||||
|
||||
entries.append(tag_field)
|
||||
|
||||
return "<br />".join(entries)
|
||||
|
||||
|
||||
def build_story(lines):
|
||||
story = list()
|
||||
|
||||
this_scene = None
|
||||
scene_style = getSampleStyleSheet()['Normal']
|
||||
scene_style.fontName = 'Futura'
|
||||
scene_style.leftIndent = 0.
|
||||
line_style = getSampleStyleSheet()['Normal']
|
||||
line_style.fontName = 'Futura'
|
||||
|
||||
for line in lines:
|
||||
table_style = [('VALIGN', (0, 0), (-1, -1), 'TOP'), ('LEFTPADDING', (0, 0), (0, 0), 0.0)]
|
||||
|
||||
if 'Omitted' in line.keys():
|
||||
cue_number_field = "<s>" + line['Cue Number'] + "</s><br /><font fontSize=9>" + \
|
||||
line['Character Name'] + "</font>"
|
||||
table_style.append(('BACKGROUND', (0, 0), (-1, 0), colors.lightpink))
|
||||
else:
|
||||
cue_number_field = line['Cue Number'] + "<br /><font fontSize=9>" + line['Character Name'] + "</font>"
|
||||
|
||||
time_data = time_format(line.get('Time Budget Mins', 0.))
|
||||
|
||||
if 'Priority' in line.keys():
|
||||
time_data = time_data + "<br />" + "P:" + int(line['Priority'])
|
||||
|
||||
aux_data_field = build_aux_data_field(line)
|
||||
|
||||
line_table_data = [[Paragraph(cue_number_field, line_style),
|
||||
Paragraph(line['PT.Clip.Start'] + "<br />" + line['PT.Clip.Finish'], line_style),
|
||||
Paragraph(line['Line'], line_style),
|
||||
Paragraph(time_data, line_style),
|
||||
Paragraph(aux_data_field, line_style)
|
||||
]]
|
||||
|
||||
line_table = Table(data=line_table_data,
|
||||
colWidths=[inch, inch, inch * 3., 0.5 * inch, inch * 2.],
|
||||
style=table_style)
|
||||
|
||||
if line['Scene'] != this_scene:
|
||||
this_scene = line['Scene']
|
||||
story.append(KeepTogether([
|
||||
Spacer(1., 0.25 * inch),
|
||||
Paragraph("<u>" + this_scene + "</u>", scene_style),
|
||||
line_table]))
|
||||
else:
|
||||
line_table.setStyle(table_style + [('LINEABOVE', (0, 0), (-1,0), .5, colors.gray)])
|
||||
story.append(KeepTogether([line_table]))
|
||||
|
||||
return story
|
||||
|
||||
|
||||
|
||||
def output_report(records):
|
||||
page_size = portrait(letter)
|
||||
page_box = GRect(inch * 0.5, inch * 0.5, page_size[0] - inch, page_size[1] - inch)
|
||||
title_box, page_box = page_box.split_y(0.875 * inch, 'd')
|
||||
footer_box, page_box = page_box.split_y(0.25 * inch, 'u')
|
||||
|
||||
title_block, header_block = title_box.split_x(inch * 4., direction='r')
|
||||
|
||||
pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc'))
|
||||
|
||||
page_template = PageTemplate(id="Main",
|
||||
frames=[Frame(page_box.min_x, page_box.min_y, page_box.width, page_box.height)],
|
||||
onPage=lambda canvas, _: draw_title_block(canvas, title_block, lines[0]))
|
||||
|
||||
lines = sorted(records['events'], key=lambda line: line['PT.Clip.Start_Seconds'])
|
||||
|
||||
doc = BaseDocTemplate("Summary.pdf",
|
||||
pagesize=page_size, leftMargin=0.5 * inch,
|
||||
rightMargin=0.5 * inch, topMargin=0.5 * inch,
|
||||
bottomMargin=0.5 * inch)
|
||||
|
||||
doc.addPageTemplates([page_template])
|
||||
|
||||
story = build_story(lines)
|
||||
|
||||
doc.build(story, canvasmaker=NumberedCanvas)
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .common import GRect, draw_title_block
|
||||
from .common import GRect, draw_title_block, NumberedCanvas
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.pagesizes import letter
|
||||
|
||||
@@ -69,4 +69,4 @@ def output_report(records):
|
||||
)
|
||||
)
|
||||
|
||||
doc.build(story)
|
||||
doc.build(story, canvasmaker=NumberedCanvas)
|
||||
|
||||
@@ -10,6 +10,11 @@ class ValidationError:
|
||||
def report_message(self):
|
||||
return f"{self.message}: event at {self.event['PT.Clip.Start']} on track {self.event['PT.Track.Name']}"
|
||||
|
||||
def validate_unique_count(input_dict, field='Title', count=1):
|
||||
values = set(list(map(lambda e: e[field], input_dict['events'])))
|
||||
if len(values) > count:
|
||||
yield ValidationError(message="Field {} has too many values (max={}): {}".format(field, count, values))
|
||||
|
||||
def validate_value(input_dict, key_field, predicate):
|
||||
for event in input_dict['events']:
|
||||
val = event[key_field]
|
||||
|
||||
Reference in New Issue
Block a user