77
88import platform
99import warnings
10+ import glob
1011import os
1112import shutil
1213import subprocess
1617
1718from partitura .io .importmusicxml import load_musicxml
1819from partitura .io .exportmusicxml import save_musicxml
19- from partitura .score import Score
20+ from partitura .score import Score , ScoreLike
2021
2122from partitura .utils .misc import (
2223 deprecated_alias ,
2324 deprecated_parameter ,
2425 PathLike ,
26+ concatenate_images ,
27+ PIL_EXISTS ,
2528)
2629
2730
@@ -61,7 +64,7 @@ def find_musescore3():
6164 result = shutil .which ("/Applications/MuseScore 3.app/Contents/MacOS/mscore" )
6265
6366 elif platform .system () == "Windows" :
64- result = shutil .which (r"C:\Program Files\MuseScore 3\bin\MuseScore .exe" )
67+ result = shutil .which (r"C:\Program Files\MuseScore 3\bin\MuseScore3 .exe" )
6568
6669 return result
6770
@@ -108,52 +111,67 @@ def load_via_musescore(
108111
109112 raise MuseScoreNotFoundException ()
110113
111- with NamedTemporaryFile ( suffix = ".musicxml" ) as xml_fh :
114+ xml_fh = os . path . splitext ( os . path . basename ( filename ))[ 0 ] + ".musicxml"
112115
113- cmd = [mscore_exec , "-o" , xml_fh . name , filename ]
116+ cmd = [mscore_exec , "-o" , xml_fh , filename ]
114117
115- try :
118+ try :
116119
117- ps = subprocess .run (cmd , stdout = subprocess .DEVNULL , stderr = subprocess .PIPE )
120+ ps = subprocess .run (cmd , stdout = subprocess .DEVNULL , stderr = subprocess .PIPE )
118121
119- if ps .returncode != 0 :
120-
121- raise FileImportException (
122- (
123- "Command {} failed with code {}. MuseScore "
124- "error messages:\n {}"
125- ).format (cmd , ps .returncode , ps .stderr .decode ("UTF-8" ))
126- )
127- except FileNotFoundError as f :
122+ if ps .returncode != 0 :
128123
129124 raise FileImportException (
130- 'Executing "{}" returned {}.' .format (" " .join (cmd ), f )
125+ (
126+ "Command {} failed with code {}. MuseScore "
127+ "error messages:\n {}"
128+ ).format (cmd , ps .returncode , ps .stderr .decode ("UTF-8" ))
131129 )
130+ except FileNotFoundError as f :
132131
133- return load_musicxml (
134- filename = xml_fh .name ,
135- validate = validate ,
136- force_note_ids = force_note_ids ,
132+ raise FileImportException (
133+ 'Executing "{}" returned {}.' .format (" " .join (cmd ), f )
137134 )
138135
139-
140- def render_musescore (part , fmt , out_fn = None , dpi = 90 ):
141- """Render a part using musescore.
136+ score = load_musicxml (
137+ filename = xml_fh ,
138+ validate = validate ,
139+ force_note_ids = force_note_ids ,
140+ )
141+
142+ os .remove (xml_fh )
143+
144+ return score
145+
146+
147+ @deprecated_alias (out_fn = "out" , part = "score_data" )
148+ def render_musescore (
149+ score_data : ScoreLike ,
150+ fmt : str ,
151+ out : Optional [PathLike ] = None ,
152+ dpi : Optional [int ] = 90 ,
153+ ) -> Optional [PathLike ]:
154+ """
155+ Render a score-like object using musescore.
142156
143157 Parameters
144158 ----------
145- part : Part
146- Part to be rendered
159+ score_data : ScoreLike
160+ Score-like object to be rendered
147161 fmt : {'png', 'pdf'}
148162 Output image format
149- out_fn : str or None, optional
163+ out : str or None, optional
150164 The path of the image output file, if not specified, the
151165 rendering will be saved to a temporary filename. Defaults to
152166 None.
153167 dpi : int, optional
154168 Image resolution. This option is ignored when `fmt` is
155169 'pdf'. Defaults to 90.
156170
171+ Returns
172+ -------
173+ out : Optional[PathLike]
174+ Path to the output generated image (or None if no image was generated)
157175 """
158176 mscore_exec = find_musescore3 ()
159177
@@ -172,14 +190,14 @@ def render_musescore(part, fmt, out_fn=None, dpi=90):
172190 xml_fh = Path (tmpdir ) / "score.musicxml"
173191 img_fh = Path (tmpdir ) / f"score.{ fmt } "
174192
175- save_musicxml (part , xml_fh )
193+ save_musicxml (score_data , xml_fh )
176194
177195 cmd = [
178196 mscore_exec ,
179197 "-T" ,
180198 "10" ,
181199 "-r" ,
182- "{}" .format (dpi ),
200+ "{}" .format (int ( dpi ) ),
183201 "-o" ,
184202 os .fspath (img_fh ),
185203 os .fspath (xml_fh ),
@@ -215,12 +233,27 @@ def render_musescore(part, fmt, out_fn=None, dpi=90):
215233 # ps.stderr.decode('UTF-8')))
216234
217235 if fmt == "png" :
218- img_fh = (img_fh .parent / (img_fh .stem + "-1" )).with_suffix (img_fh .suffix )
236+
237+ if PIL_EXISTS :
238+ # get all generated image files
239+ img_files = glob .glob (
240+ os .path .join (img_fh .parent , img_fh .stem + "-*.png" )
241+ )
242+ concatenate_images (
243+ filenames = img_files ,
244+ out = img_fh ,
245+ concat_mode = "vertical" ,
246+ )
247+ else :
248+ # The first image seems to be blank (MuseScore adds an empy page)
249+ img_fh = (img_fh .parent / (img_fh .stem + "-2" )).with_suffix (
250+ img_fh .suffix
251+ )
219252
220253 if img_fh .is_file ():
221- if out_fn is None :
222- out_fn = os .path .join (gettempdir (), "partitura_render_tmp.png" )
223- shutil .copy (img_fh , out_fn )
224- return out_fn
254+ if out is None :
255+ out = os .path .join (gettempdir (), "partitura_render_tmp.png" )
256+ shutil .copy (img_fh , out )
257+ return out
225258
226259 return None
0 commit comments