2020-12-29 02:13:29 +01:00
#!/usr/bin/python3
2019-09-09 17:32:07 +02:00
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import csv
import random
2019-09-24 13:26:31 +02:00
import os
2020-12-17 01:31:57 +01:00
import json
2019-09-24 13:26:31 +02:00
fileDir = os . path . dirname ( os . path . abspath ( __file__ ) )
2019-09-09 17:32:07 +02:00
2020-12-17 01:31:57 +01:00
def replaceText ( text , config ) :
2019-09-24 13:26:31 +02:00
""" This function replace $WILDCARD with a word found in subs.csv
subs . csv definition is 1 st colum $ WILDCARD , subsequent columns , possible values ( chosen at random ) , delimiter is ; """
2020-12-17 20:09:34 +01:00
with open ( config [ " csvLocation " ] + " / " + config [ " csvSubs " ] ) as subs :
2020-12-02 02:14:20 +01:00
csvReader = csv . reader ( subs , delimiter = " ; " )
2019-09-17 17:52:21 +02:00
for row in csvReader :
if text . find ( row [ 0 ] ) != - 1 :
2019-10-28 23:56:31 +01:00
text = text . replace ( row [ 0 ] , row [ random . randint ( 1 , len ( row ) - 1 ) ] , 1 )
2019-09-17 17:52:21 +02:00
return text
2021-03-11 01:42:44 +01:00
print ( " Parsing error \" " + text + " \" not found " )
quit ( )
2019-09-17 17:52:21 +02:00
2020-12-17 01:31:57 +01:00
def fetchText ( indText , config ) :
2019-09-24 13:26:31 +02:00
""" This function fetch the text for the image with two characters
2020-12-02 02:14:20 +01:00
rtext . csv definition is : 1 st column the name of the file ( i . e . B001 . png ) , 2 nd number of actors ( at the moment
they are limited to two ; then a couple of columns or each actor with x and y coord of the strings ; after the coords the outcomes ,
one column for each actor
2019-09-24 13:26:31 +02:00
Delimiter is ; and line feeds @ , if there aren ' t any options, it returns 0 (no text)
2020-12-02 02:14:20 +01:00
It returns two arrays , coords is a tuple ( x , y ) and result is the outcome """
2020-12-17 20:09:34 +01:00
with open ( config [ " csvLocation " ] + " / " + config [ " csvSpeech " ] ) as rtext :
2019-09-24 13:26:31 +02:00
csvReader = csv . reader ( rtext , delimiter = ' ; ' )
for row in csvReader :
if row [ 0 ] == indText :
2020-12-02 02:14:20 +01:00
noActors = int ( row [ 1 ] )
if noActors == 0 :
2019-09-24 13:26:31 +02:00
return 0
2020-12-02 02:14:20 +01:00
else :
firstElement = 2 + ( noActors * 2 )
lastElement = len ( row ) - ( noActors - 1 )
randQuote = random . randrange ( firstElement , lastElement , noActors )
coords = [ ]
result = [ ]
for x in range ( 0 , noActors ) :
coords . append ( ( row [ 2 + x * 2 ] , row [ 3 + x * 2 ] ) )
result . append ( row [ randQuote + x ] )
return coords , result
2019-09-24 13:26:31 +02:00
2020-12-17 01:31:57 +01:00
def fetchVign ( config ) :
2019-09-24 13:26:31 +02:00
""" This functions fetch an image, randomly, chosen from a markov tree defined in ram.csv
ram . csv definition is : 1 st column the name of the image ( without extension ) , subsequent columns , possible outcomes chosen randomly
It returns an array with the file names """
2019-09-09 17:32:07 +02:00
starts = [ ]
startdest = [ ]
nvign = 0
currVign = " 000 "
story = [ ]
2020-12-17 20:09:34 +01:00
with open ( config [ " csvLocation " ] + " / " + config [ " csvTree " ] ) as ram :
2019-09-09 17:32:07 +02:00
csvReader = csv . reader ( ram )
for row in csvReader :
starts . append ( row [ 0 ] )
startdest . append ( row )
2020-06-29 23:48:05 +02:00
while nvign < 100 :
2019-09-09 17:32:07 +02:00
story . append ( startdest [ starts . index ( currVign ) ] [ random . randint ( 1 , len ( startdest [ starts . index ( currVign ) ] ) - 1 ) ] )
currVign = story [ nvign ]
2020-06-29 23:48:05 +02:00
if currVign == " END " :
return story
2019-09-17 00:20:30 +02:00
story [ nvign ] + = " .png "
2019-09-09 17:32:07 +02:00
nvign + = 1
2020-06-29 23:48:05 +02:00
print ( " tree with no END " )
quit ( )
2019-09-09 17:32:07 +02:00
2020-12-17 01:31:57 +01:00
def addThing ( indVign , config ) :
2019-09-24 13:26:31 +02:00
""" This function adds a small image (object) to a larger image
obj . csv definition is : name of the image ( i . e . A001 . png ) , x - coord , y - coord , subsequent columns possible outcomes
It returns a tuple ( object file name , x , y ) """
2020-12-17 20:09:34 +01:00
with open ( config [ " csvLocation " ] + " / " + config [ " csvObj " ] ) as obj :
2019-09-17 16:33:43 +02:00
csvReader = csv . reader ( obj )
for row in csvReader :
if row [ 0 ] == indVign :
return row [ random . randint ( 3 , len ( row ) - 1 ) ] , row [ 1 ] , row [ 2 ]
return 0
2019-09-13 16:08:09 +02:00
2021-03-13 18:57:12 +01:00
def writeStrip ( story , config ) :
2019-09-24 13:26:31 +02:00
""" This function creates the strip returning an image object that could be saved or viewed. It takes an array with filenames as parameter
2020-11-24 02:30:42 +01:00
The first image is always 000 , then appends to strip the files , then decorates it fetching text and adding objects . If the object is an R , then
repeats the last object . """
2019-09-17 00:20:30 +02:00
strip = [ ]
2019-09-12 19:53:57 +02:00
for indVign in story :
2020-06-29 23:48:05 +02:00
try :
2020-12-17 01:31:57 +01:00
vign = Image . open ( config [ " imagesLocation " ] + " / " + indVign ) . convert ( ' RGBA ' )
2019-09-12 19:53:57 +02:00
addtext = ImageDraw . Draw ( vign )
2021-03-13 18:57:12 +01:00
fnt = ImageFont . truetype ( config [ " font " ] , config [ " fontSize " ] )
2020-12-17 01:31:57 +01:00
textVign = fetchText ( indVign , config )
2019-10-28 23:56:31 +01:00
2020-12-02 02:14:20 +01:00
if textVign != 0 :
2020-12-29 01:29:51 +01:00
try :
for x in range ( len ( textVign [ 0 ] ) ) :
text_vign = textVign [ 1 ] [ x ]
try :
while text_vign . find ( ' $ ' ) != - 1 :
text_vign = replaceText ( text_vign , config )
2021-03-11 01:42:44 +01:00
except AttributeError as err :
2020-12-29 01:29:51 +01:00
print ( " Problem parsing: " )
print ( textVign )
2021-03-11 01:42:44 +01:00
print ( err )
2020-12-29 01:29:51 +01:00
quit ( )
text_vign = text_vign . replace ( ' @ ' , ' \n ' )
addtext . multiline_text ( ( int ( textVign [ 0 ] [ x ] [ 0 ] ) , int ( textVign [ 0 ] [ x ] [ 1 ] ) ) , text_vign , fill = " #000000 " , font = fnt , align = " center " )
except TypeError :
print ( " Problem finding text for: " )
print ( indVign )
quit ( )
2020-12-02 02:14:20 +01:00
2020-12-17 01:31:57 +01:00
obj = addThing ( indVign , config )
2019-09-17 16:33:43 +02:00
if obj != 0 :
2020-11-24 02:30:42 +01:00
if obj [ 0 ] == ' R ' :
2020-12-17 01:31:57 +01:00
objImg = Image . open ( config [ " imagesLocation " ] + " / " + prevObj [ 0 ] )
2020-11-24 02:30:42 +01:00
else :
prevObj = obj
2020-12-17 01:31:57 +01:00
objImg = Image . open ( config [ " imagesLocation " ] + " / " + obj [ 0 ] )
2019-09-17 16:33:43 +02:00
vign . paste ( objImg , ( int ( obj [ 1 ] ) , int ( obj [ 2 ] ) ) )
2019-09-17 00:20:30 +02:00
strip . append ( vign )
2020-06-29 23:48:05 +02:00
except FileNotFoundError :
pass
2020-12-17 02:48:30 +01:00
image = Image . new ( ' RGBA ' , ( config [ " xSize " ] , config [ " ySize " ] ) )
2019-09-17 00:20:30 +02:00
xshift = 0
for vign in strip :
image . paste ( vign , ( xshift , 0 ) )
2020-12-17 02:48:30 +01:00
xshift + = config [ " panelLength " ]
2021-05-11 15:03:02 +02:00
ImageDraw . Draw ( image ) . rectangle ( [ 0 , 0 , config [ " xSize " ] - 1 , config [ " ySize " ] - 1 ] , fill = None , outline = " black " , width = 1 )
2019-09-17 00:20:30 +02:00
return image
2019-09-09 17:32:07 +02:00
2021-03-13 18:57:12 +01:00
def createStrip ( config , specialPlatform = " " ) :
2019-09-24 13:26:31 +02:00
""" Create strip and save it
createStrip ( str path / filename ) """
2020-12-29 01:29:51 +01:00
2019-09-19 01:59:13 +02:00
try :
2020-12-17 01:31:57 +01:00
story = fetchVign ( config )
2021-03-13 18:57:12 +01:00
finalStrip = writeStrip ( story , config )
2020-12-17 01:31:57 +01:00
if specialPlatform == " android " :
2019-12-23 17:50:59 +01:00
return finalStrip
else :
2020-12-17 01:31:57 +01:00
finalStrip . save ( config [ " saveLocation " ] + config [ " filename " ] )
2019-12-23 17:50:59 +01:00
return 0
2019-09-19 01:59:13 +02:00
except Exception as err :
return err
2020-12-17 01:31:57 +01:00
def readConfig ( profile = False , platform = False ) :
""" Read configuration file """
try :
with open ( fileDir + " /config.json " ) as f :
config = json . load ( f )
except IOError :
print ( " config.json not found " )
return False
if not ( profile ) :
profile = config [ " defaultProfile " ]
else :
profile = profile [ 0 ]
try :
checkProfile = config [ profile ]
except KeyError :
2020-12-29 01:29:51 +01:00
print ( " Profile " + profile + " not found " )
2020-12-17 01:31:57 +01:00
quit ( )
saveLocation = checkLocal ( config [ profile ] [ " saveLocation " ] )
imagesLocation = checkLocal ( config [ profile ] [ " imagesLocation " ] )
csvLocation = checkLocal ( config [ profile ] [ " csvLocation " ] )
2020-12-17 20:09:34 +01:00
csvTree = config [ profile ] [ " csvTree " ]
csvSpeech = config [ profile ] [ " csvSpeech " ]
csvSubs = config [ profile ] [ " csvSubs " ]
csvObj = config [ profile ] [ " csvObj " ]
2020-12-17 01:31:57 +01:00
font = checkLocal ( config [ profile ] [ " font " ] )
2021-03-13 18:57:12 +01:00
fontSize = int ( ( config [ profile ] [ " fontSize " ] ) )
2020-12-17 02:48:30 +01:00
xSize = config [ profile ] [ " xSize " ]
ySize = config [ profile ] [ " ySize " ]
panelLength = config [ profile ] [ " panelLength " ]
2020-12-17 01:31:57 +01:00
if platform :
token = checkLocal ( config [ profile ] [ platform ] [ " token " ] )
filename = checkLocal ( config [ profile ] [ platform ] [ " filename " ] )
2020-12-29 02:13:29 +01:00
try :
text = config [ profile ] [ platform ] [ " text " ]
except KeyError :
2020-12-29 02:19:51 +01:00
text = False
2020-12-29 02:13:29 +01:00
2021-03-13 18:57:12 +01:00
return { " saveLocation " : saveLocation , " imagesLocation " : imagesLocation , " csvLocation " : csvLocation , " fontSize " : fontSize , " font " : font , " token " : token , " filename " : filename , " xSize " : xSize , " ySize " : ySize , " panelLength " : panelLength , " csvTree " : csvTree , " csvSpeech " : csvSpeech , " csvSubs " : csvSubs , " csvObj " : csvObj , " text " : text }
2020-12-17 01:31:57 +01:00
filename = config [ profile ] [ " filename " ]
2021-03-13 18:57:12 +01:00
return { " saveLocation " : saveLocation , " imagesLocation " : imagesLocation , " csvLocation " : csvLocation , " fontSize " : fontSize , " font " : font , " filename " : filename , " xSize " : xSize , " ySize " : ySize , " panelLength " : panelLength , " csvTree " : csvTree , " csvSpeech " : csvSpeech , " csvSubs " : csvSubs , " csvObj " : csvObj }
2020-12-17 01:31:57 +01:00
def checkLocal ( directory ) :
""" Checks if it ' s a relative or absolute path """
if directory [ 0 ] == " . " :
return fileDir + directory [ 1 : ]
else :
return directory
2019-09-09 17:32:07 +02:00
if __name__ == " __main__ " :
2020-02-28 17:34:49 +01:00
import argparse
2020-12-29 01:29:51 +01:00
2020-02-28 17:34:49 +01:00
parser = argparse . ArgumentParser ( )
parser . add_argument ( ' -s ' , ' --story ' , metavar = ' story ' , default = ' ' , nargs = 4 , help = ' name of the images ' )
2021-05-10 14:21:23 +02:00
parser . add_argument ( ' -a ' , ' --a4 ' , default = False , action = ' store_true ' , help = ' print on an A4 in PDF, needs -o output, disables -x xsize ' )
parser . add_argument ( ' -m ' , ' --multiple ' , metavar = ' multiple ' , default = [ 1 ] , nargs = 1 , type = int , help = ' multiple output (int >0), if no output -o specified, it just tests the stories ' )
2020-12-05 18:43:38 +01:00
parser . add_argument ( ' -x ' , ' --xsize ' , metavar = ' xsize ' , default = 0 , type = int , nargs = 1 , help = ' resize image x ' )
2020-12-17 01:31:57 +01:00
parser . add_argument ( ' -p ' , ' --profile ' , metavar = ' profile ' , default = " " , type = str , nargs = 1 , help = ' profile ' )
2020-12-29 01:29:51 +01:00
parser . add_argument ( ' -o ' , ' --output ' , metavar = ' output ' , const = True , default = False , nargs = " ? " , help = ' output file, if name not specified, default path will be used ' )
2020-02-28 17:34:49 +01:00
args = parser . parse_args ( )
2020-12-29 01:29:51 +01:00
if args . multiple [ 0 ] < = 0 : #Wrong multiple choice
2020-12-01 00:17:55 +01:00
quit ( )
2020-12-17 01:31:57 +01:00
config = readConfig ( profile = args . profile )
2021-05-10 14:21:23 +02:00
2020-12-29 01:29:51 +01:00
if args . output == True : #Output on but no filename specified
fileName = config [ " saveLocation " ] + config [ " filename " ]
elif type ( args . output ) == str : #Output specified
fileName = args . output
2021-05-10 14:21:23 +02:00
pdfs = list ( ) #Prepare a list for the PDF
2020-12-29 01:29:51 +01:00
for ist in range ( 0 , args . multiple [ 0 ] ) :
if ( args . story == ' ' ) : #No story specified
2020-12-17 01:31:57 +01:00
story = fetchVign ( config )
2020-12-01 00:17:55 +01:00
else :
2020-12-29 01:29:51 +01:00
story = [ ] #Story specified
2020-12-01 00:17:55 +01:00
for x in args . story :
story . append ( x )
2021-03-13 18:57:12 +01:00
finalStrip = writeStrip ( story , config )
2020-12-29 01:29:51 +01:00
2021-05-10 14:21:23 +02:00
if args . a4 : #Prints a PDF
finalStrip = finalStrip . resize ( ( 2249 , 516 ) )
pdfs . append ( finalStrip )
else :
if args . xsize != 0 : #Resize specified
finalStrip = finalStrip . resize ( ( args . xsize [ 0 ] , int ( args . xsize [ 0 ] / 2400 * 500 ) ) )
2020-12-29 01:29:51 +01:00
2021-05-10 14:21:23 +02:00
if args . multiple [ 0 ] == 1 : #No multiple selected
if args . output == False :
finalStrip . show ( )
else :
finalStrip . save ( fileName )
else : #Multiple selected
if args . output == False :
print ( story )
else :
2021-05-10 14:55:56 +02:00
finalStrip . save ( fileName + str ( ist ) . zfill ( 3 ) + " .png " )
2021-05-10 14:21:23 +02:00
if args . a4 :
ypos = 100
nopage = 0
if args . output == False :
print ( " Output not specified " )
quit ( )
2020-12-29 01:29:51 +01:00
2021-05-10 14:21:23 +02:00
pagePdf = list ( )
2021-05-11 15:00:32 +02:00
for pag in range ( 0 , int ( ( args . multiple [ 0 ] - 1 ) / 6 + 1 ) ) :
2021-05-10 14:21:23 +02:00
pagePdf . append ( Image . new ( ' RGB ' , ( 2479 , 3508 ) , ( 255 , 255 , 255 ) ) )
2020-12-29 01:29:51 +01:00
2021-05-10 14:21:23 +02:00
for ist , strip_num in enumerate ( range ( 0 , args . multiple [ 0 ] ) ) :
pagePdf [ nopage ] . paste ( pdfs [ strip_num ] , box = ( 110 , ypos ) )
2021-05-11 15:03:02 +02:00
ypos + = 516 + 20
2021-05-10 14:21:23 +02:00
if ypos > 3508 - 569 :
ypos = 100
nopage + = 1
if fileName [ len ( fileName ) - 4 : ] != " .pdf " :
fileName + = " .pdf "
pagePdf [ 0 ] . save ( fileName , save_all = True , append_images = pagePdf [ 1 : ] )