diff --git a/README.md b/README.md index fb62055..b4b3e5f 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,6 @@ IMPORTANT : FORMAT DES FICHIERS. La playlist en tant que telle est le fichier nommé 'playlist.bin', qui doit se trouver dans le dossier racine de la carte micro-SD de la Merlin. Les fichiers sons et images doivent aussi se trouver dans le même dossier. Les extensions des noms de fichiers doivent être '.mp3' pour les sons et '.jpg' pour les images. Pour s'afficher sur l'enceinte, une image doit avoir le même nom de fichier (à l'exception de l'extension) que le son correspondant. Les noms de fichiers sont limités à 64 octets en encodage utf-8 (compter un octet par caractère simple et deux par caractère accentué). -D'après mes observations, les fichiers images sont au format jpeg avec une résolution de 128x128, et les sons sont au format mp3 en stéréo à 128ko/s. Je sais pas si d'autres formats sont supportés. En revanche, il semblerait que les images au format "progressive JPEG" ne sont pas supportées. - Dans sa version actuelle, merlinator ne vérifie pas si les conditions mentionnée ci-dessus sont vérifiées. Il se contente de créer le fichier de playlist. - - +D'après mes observations, les fichiers images sont au format jpeg avec une résolution de 128x128, et les sons sont au format mp3 en stéréo à 128ko/s. Je sais pas si d'autres formats sont supportés. +En revanche, les images au format "progressive JPEG" ne sont pas supportées par toutes les versions de l'enceinte. + Dans sa version actuelle, merlinator crée le fichier de playlist, mais ne vérifie pas si toutes les conditions mentionnée ci-dessus sont remplies. diff --git a/src/io_utils.py b/src/io_utils.py index 7a5d391..c22146d 100644 --- a/src/io_utils.py +++ b/src/io_utils.py @@ -11,6 +11,7 @@ import zipfile import os.path import json +import struct bytezero = b'\x00' @@ -193,3 +194,28 @@ def export_merlin_to_zip(items, zfile): return files_not_found + +def IsImageProgressive(stream): + #with open(filename, "rb") as stream: + while True: + blockStart = struct.unpack('B', stream.read(1))[0] + if blockStart != 0xff: + raise ValueError('Invalid char code ' + blockStart + ' - not a JPEG file: ' + filename) + return False + + blockType = struct.unpack('B', stream.read(1))[0] + if blockType == 0xd8: # Start Of Image + continue + elif blockType == 0xc0: # Start of baseline frame + return False + elif blockType == 0xc2: # Start of progressive frame + return True + elif blockType >= 0xd0 and blockType <= 0xd7: # Restart + continue + elif blockType == 0xd9: # End Of Image + break + else: # Variable-size block, just skip it + blockSize = struct.unpack('2B', stream.read(2)) + blockSize = blockSize[0] * 256 + blockSize[1] - 2 + stream.seek(blockSize, 1) + return False \ No newline at end of file diff --git a/src/main_gui.py b/src/main_gui.py index 03487c5..52fbec0 100644 --- a/src/main_gui.py +++ b/src/main_gui.py @@ -223,6 +223,11 @@ def load_thumbnails(self, items, overwrite=True): if item['uuid'] in self.thumbnails: continue if os.path.exists(imagepath): + with open(imagepath, "rb") as imagestream: + if IsImageProgressive(imagestream): + tk.messagebox.showwarning(title="Problème de format", message=f"Le format de l'image '{imagepath}' est JPEG 'progressive'. Ce format n'est pas pris en charge par toutes les Merlin.") + self.thumbnails[item['uuid']] = '' + continue with Image.open(imagepath) as image: image_small = image.resize((40, 40), Image.ANTIALIAS) self.thumbnails[item['uuid']] = PhotoImage(image_small) @@ -239,6 +244,11 @@ def load_thumbnails_from_zip(self, items, zfile, overwrite=True): filename = item['uuid'] + '.jpg' zippath = zipfile.Path(zfile, at=filename) if zippath.exists(): + with zfile.open(filename, 'rb', pwd=info) as imagestream: + if IsImageProgressive(imagestream): + tk.messagebox.showwarning(title="Problème de format", message=f"Le format de l'image '{filename}' est JPEG 'progressive'. Ce format n'est pas pris en charge par toutes les Merlin.") + self.thumbnails[item['uuid']] = '' + continue with zfile.open(filename, 'r', pwd=info) as imagefile: with Image.open(imagefile) as image: image_small = image.resize((40, 40), Image.ANTIALIAS) diff --git a/src/treeviews.py b/src/treeviews.py index 92fd3db..5b600bb 100644 --- a/src/treeviews.py +++ b/src/treeviews.py @@ -407,6 +407,9 @@ def select_image(self): filepath = filedialog.askopenfilename(initialdir=playlist_dirname, initialfile=initfile, filetypes=[('images jpg', '*.jpg')]) if not filepath: return + with open(filepath, 'rb') as stream: + if IsImageProgressive(stream): + tk.messagebox.showwarning(title="Problème de format", message=f"Le format de l'image est JPEG 'progressive'. Ce format n'est pas pris en charge par toutes les Merlin.") dirname, basename = os.path.split(filepath) root, ext = os.path.splitext(basename) # check length