#!/usr/bin/env python3 import sys import subprocess import os import re import tempfile import shutil import math import locale import gettext try: translation = gettext.translation('fotoalbum',localedir='/usr/share/locale') if translation: translation.install() _ = translation.gettext except FileNotFoundError: print('No translation found!') _ = lambda x: x RESOURCE_DIR='/usr/lib/fotoalbum/resources/fotoalbum' mode='' text='' imgs=[] output_file='' dimensions='' curves=True def help(exitcode=0): print() print(f'{os.path.basename(sys.argv[0])} -m [-t "text or title"] file1 ... [fileN] [-o output.pdf]') print(f"{os.path.basename(sys.argv[0])} -h") print() t=[] t='|'.join(sorted(os.listdir(f'{RESOURCE_DIR}'))) print(f" = [{t}]") print(f" = ") print(f" = -d WIDTHxHEIGHT ") print(f" = -c [1|0] ") print() print('Notes:') print('=minilibro allow Libreoffice\'s ODT document with 8 pages or 8 images') print('') print() sys.exit(exitcode) def parse_parameters(): global mode, text, imgs, output_file, dimensions, curves try: narg = 0 while narg < len(sys.argv)-1: narg += 1 param = sys.argv[narg] if param == "-m": if narg+1 < len(sys.argv): mode = sys.argv[narg+1] narg += 1 else: raise Exception(_('No mode selected')) elif param == "-t": if narg+1 < len(sys.argv): text = sys.argv[narg+1] narg += 1 elif param == "-d": if narg+1 < len(sys.argv): dimensions = sys.argv[narg+1] narg += 1 elif param == "-c": if narg+1 < len(sys.argv): curves = sys.argv[narg+1] narg += 1 elif param == "-o": if narg+1 < len(sys.argv): output_file = sys.argv[narg+1] if not os.path.isabs(output_file): output_file=os.path.realpath(output_file) narg += 1 else: if param == '-h': help() param=os.path.realpath(param) if os.path.isfile(param): imgs.append(param) else: raise Exception('{} {}'.format(param,_('not exists'))) except Exception as e: print(f'{e}') help(1) def image_size(imgname): magic = subprocess.check_output(['/usr/bin/identify',imgname]).decode() size = magic.split(' ')[2] try: sizes = re.findall('(\d+)[ ]?x[ ]?(\d+)', size)[0] if size != '{}x{}'.format(sizes[0],sizes[1]): raise Exception(_('Unknown image size')) return (int(sizes[0]),int(sizes[1])) except Exception as e: print(f'{e}') sys.exit(1) def resize(imgname): os.chdir(os.path.dirname(imgname)) subprocess.check_call(['/usr/bin/convert',imgname,'-alpha','remove','-resize','400',imgname]) def rotate_image(imgname): os.chdir(os.path.dirname(imgname)) subprocess.check_call(['/usr/bin/convert',imgname,'-alpha','remove','-rotate','270',imgname]) def make_square(imgname): os.chdir(os.path.dirname(imgname)) subprocess.check_call(['/usr/bin/convert',imgname,'-background','white','-trim','+repage',imgname]) x,y=image_size(imgname) if x > y: subprocess.check_call(['/usr/bin/mogrify','-gravity','center','-background','white','-extent',f'{x}x{x}',imgname]) if y > x: subprocess.check_call(['/usr/bin/mogrify','-gravity','center','-background','white','-extent',f'{y}x{y}',imgname]) def replace_text(text,file): if not text: text='' os.chdir(os.path.dirname(file)) subprocess.check_call(['/usr/bin/sed','-r','-i','-e',f's|@@MMMM@@|{text}|g', file]) def replace_sizes(x,y,file): os.chdir(os.path.dirname(file)) subprocess.check_call(['/usr/bin/sed','-i','-r','-e',f's|@@ANCHO@@|{x}|g','-e',f's|@@ALTO@@|{y}|g', file]) pass def replace_stroke(stroke,file): os.chdir(os.path.dirname(file)) subprocess.check_call(['/usr/bin/sed','-i','-r','-e',f's|stroke-width:0.1|stroke-width:{stroke}|g', file]) pass def ask(default_name): try: if not default_name: return None return subprocess.check_output(['/usr/bin/kdialog','--getsavefilename',f'{default_name}','application/pdf']).decode().strip() except Exception as e: return None def ask_open(filename): try: subprocess.check_call(['/usr/bin/kdialog','--yesno',_(' Open {} ?').format(filename),'--title',os.path.basename(sys.argv[0])]) return True except: return False def ask_dimensions(): try: return subprocess.check_output(['/usr/bin/kdialog','--combobox',_(' Desired number of pieces ?'),'--title',os.path.basename(sys.argv[0]),'4x3','8x6','12x9','16x12','3x4','6x8','9x12','12x16']).decode().strip() except: return '' def ask_curves(): try: name = subprocess.check_output(['/usr/bin/kdialog','--yesno',_(' Make curves ?'),'--title',os.path.basename(sys.argv[0])]) return True except: return False def ask_text(): try: name = subprocess.check_output(['/usr/bin/kdialog','--inputbox',_(' Name for bookmark ?'),'--title',os.path.basename(sys.argv[0])]).decode().strip() return name except: return '' def concatenate_to_pdf(output,*args): os.chdir(os.path.dirname(output)) cmd=['/usr/bin/convert'] for filename in args: if os.path.isfile(filename): cmd.append(filename) cmd.append(output) subprocess.check_call(cmd) def fix_size(image,type): if type=='horizontal': size='972x549' os.chdir(os.path.dirname(image)) subprocess.check_call(['/usr/bin/convert',image,'-thumbnail',size,'-background','white','-gravity','center','-extent',size,image]) else: make_square(image) # MAIN PROGRAM if __name__ == "__main__": cwd=os.getcwd() parse_parameters() if not mode or not imgs: print(_('Wrong parameters')) help(1) orig_mode=mode directory = f'{RESOURCE_DIR}/{mode}' template_name = 'plantilla.svg' if not os.path.isdir(directory): print(_('Wrong mode')) help(1) if not os.path.isfile(f'{directory}/{template_name}'): print(_('Template {} not found!').format(template_name)) help(1) nimages=len(imgs) if mode == '1x1': maximages = 1 elif mode == '2x1': maximages = 2 elif mode == '2x2': maximages = 4 elif mode == '2x3': maximages = 6 elif mode == '3x5': maximages = 15 elif mode == 'minilibro': maximages = 8 elif mode == 'puzzle': maximages = 1 elif mode == 'mosaic': maximages = 1 groups = math.ceil(nimages/maximages) out_pdf='' out_png='' pdfs=[] if mode == '1x1' and not text: text = ask_text() with tempfile.TemporaryDirectory() as dirname: for ngroup in map(lambda x: x+1,range(groups)): os.mkdir(f'{dirname}/{ngroup}') file_template=f'{dirname}/{ngroup}/{template_name}' shutil.copy(f'{directory}/{template_name}',file_template) replace_text(text,f'{dirname}/{ngroup}/{template_name}') if mode == 'minilibro': odt_file=os.path.realpath(imgs[0]) if nimages == 1 and '.odt' == (odt_file[-4:]).lower(): os.chdir(os.path.dirname(odt_file)) subprocess.check_call(['/usr/bin/libreoffice','--nologo','--headless','--invisible','--print-to-file','--printer-name','PDF','--outdir',dirname,odt_file],shell=False) pdf=f'{dirname}/{os.path.basename(odt_file).replace(".odt",".pdf")}' os.chdir(dirname) subprocess.check_call(['/usr/bin/convert','-density','150','-quality','100',pdf,f'{dirname}/a.png']) imgs=[] for file in sorted(os.listdir(dirname)): if file[-4:] == '.png' and file[:2] == 'a-': imgs.append(os.path.realpath(file)) if mode == 'puzzle': if not dimensions: dimensions=ask_dimensions() if not curves: curves=ask_curves() if not dimensions: sys.exit(0) if curves: curves='0.5' else: curves='0' nx,ny=dimensions.split('x') radius='20' if mode == 'mosaic': if not dimensions: dimensions=ask_dimensions() if not dimensions: sys.exit(0) curves='0' nx,ny=dimensions.split('x') radius='0' mode = 'puzzle' n=0 for img in imgs: n+=1 ngroup = math.ceil(n/maximages) num=n while num > maximages: num = num - maximages newfile=f'{dirname}/{ngroup}/{num}' shutil.copy(img,newfile) if mode == '1x1': x,y=image_size(newfile) if x > y: fix_size(newfile,'horizontal') else: fix_size(newfile,'vertical') if mode=='puzzle': x,y=image_size(newfile) replace_sizes(x,y,f'{dirname}/{ngroup}/{template_name}') new_template=subprocess.check_output(['python3','/usr/share/inkscape/extensions/Lasercut_jigsaw.py','-u','px','-x',str(x),'-y',str(y),'-w',nx,'-z',ny,'-k',curves,'-r','0','-i',radius,f'{dirname}/{ngroup}/{template_name}'],shell=False).decode() with open(f'{dirname}/{ngroup}/{template_name}','w') as fp: fp.write(new_template) replace_stroke('0.5',f'{dirname}/{ngroup}/{template_name}') for ngroup in map(lambda x: x+1,range(groups)): file_template=f'{dirname}/{ngroup}/{template_name}' file_png=f'{dirname}/{ngroup}/{template_name.replace(".svg",".png")}' os.chdir(f'{dirname}/{ngroup}') subprocess.check_call(['/usr/bin/rsvg-convert',file_template,'-f','png','-b','white','-o',file_png]) pngs=[] for ngroup in map(lambda x: x+1,range(groups)): file_png=f'{dirname}/{ngroup}/{template_name.replace(".svg",".png")}' png_file=f'{dirname}/{ngroup}_{template_name.replace(".svg",".png")}' shutil.copy(file_png,png_file) pngs.append(png_file) pdf_file=f'{dirname}/{template_name.replace(".svg",".pdf")}' os.chdir(dirname) cmd=['convert'] cmd.extend(pngs) cmd.append(pdf_file) subprocess.check_call(cmd) if not output_file: if imgs: basepath = os.path.dirname(os.path.realpath(imgs[0])) output = ask(f'{basepath}/{os.path.basename(sys.argv[0])}_{orig_mode}.pdf') else: output = output_file if output: shutil.copy(pdf_file,output) pdfs.append(output) for pdf in pdfs: if os.path.isfile(pdf) and not output_file and ask_open(pdf): subprocess.Popen(['/usr/bin/okular',pdf],stderr=subprocess.DEVNULL) sys.exit(0)