diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index c8711afb3e5..50155991d82 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -691,50 +691,26 @@ def callback(state): out, "PNG", save_all=True, append_images=[im, im2], progress=callback ) - assert progress == [ - { - "image_index": 0, - "image_filename": "Tests/images/apng/single_frame.png", - "completed_frames": 1, - "total_frames": 7, - }, - { - "image_index": 1, - "image_filename": "Tests/images/apng/single_frame.png", - "completed_frames": 2, - "total_frames": 7, - }, - { - "image_index": 2, - "image_filename": "Tests/images/apng/delay.png", - "completed_frames": 3, - "total_frames": 7, - }, - { - "image_index": 2, - "image_filename": "Tests/images/apng/delay.png", - "completed_frames": 4, - "total_frames": 7, - }, - { - "image_index": 2, - "image_filename": "Tests/images/apng/delay.png", - "completed_frames": 5, - "total_frames": 7, - }, - { - "image_index": 2, - "image_filename": "Tests/images/apng/delay.png", - "completed_frames": 6, - "total_frames": 7, - }, - { - "image_index": 2, - "image_filename": "Tests/images/apng/delay.png", - "completed_frames": 7, - "total_frames": 7, - }, - ] + expected = [] + for i in range(2): + expected.append( + { + "image_index": i, + "image_filename": "Tests/images/apng/single_frame.png", + "completed_frames": i + 1, + "total_frames": 7, + } + ) + for i in range(5): + expected.append( + { + "image_index": 2, + "image_filename": "Tests/images/apng/delay.png", + "completed_frames": i + 3, + "total_frames": 7, + } + ) + assert progress == expected def test_seek_after_close(): diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index 8330506373f..f45076bc15f 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -304,29 +304,17 @@ def callback(state): with Image.open("Tests/images/frozenpond.mpo") as im2: im.save(out, "MPO", save_all=True, append_images=[im2], progress=callback) - assert progress == [ - { - "image_index": 0, - "image_filename": "Tests/images/sugarshack.mpo", - "completed_frames": 1, - "total_frames": 4, - }, - { - "image_index": 0, - "image_filename": "Tests/images/sugarshack.mpo", - "completed_frames": 2, - "total_frames": 4, - }, - { - "image_index": 1, - "image_filename": "Tests/images/frozenpond.mpo", - "completed_frames": 3, - "total_frames": 4, - }, - { - "image_index": 1, - "image_filename": "Tests/images/frozenpond.mpo", - "completed_frames": 4, - "total_frames": 4, - }, - ] + expected = [] + for i, filename in enumerate( + ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"] + ): + for j in range(2): + expected.append( + { + "image_index": i, + "image_filename": filename, + "completed_frames": i * 2 + j + 1, + "total_frames": 4, + } + ) + assert progress == expected diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index 178c0193fed..c5b2bc45cc4 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -193,32 +193,20 @@ def callback(state): with Image.open("Tests/images/frozenpond.mpo") as im2: im.save(out, "PDF", save_all=True, append_images=[im2], progress=callback) - assert progress == [ - { - "image_index": 0, - "image_filename": "Tests/images/sugarshack.mpo", - "completed_frames": 1, - "total_frames": 4, - }, - { - "image_index": 0, - "image_filename": "Tests/images/sugarshack.mpo", - "completed_frames": 2, - "total_frames": 4, - }, - { - "image_index": 1, - "image_filename": "Tests/images/frozenpond.mpo", - "completed_frames": 3, - "total_frames": 4, - }, - { - "image_index": 1, - "image_filename": "Tests/images/frozenpond.mpo", - "completed_frames": 4, - "total_frames": 4, - }, - ] + expected = [] + for i, filename in enumerate( + ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"] + ): + for j in range(2): + expected.append( + { + "image_index": i, + "image_filename": filename, + "completed_frames": i * 2 + j + 1, + "total_frames": 4, + } + ) + assert progress == expected def test_multiframe_normal_save(tmp_path): diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 6cc4afc70bd..d4b545d7b60 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -714,32 +714,24 @@ def callback(state): out, "TIFF", save_all=True, append_images=[im2], progress=callback ) - assert progress == [ + expected = [ { "image_index": 0, "image_filename": "Tests/images/hopper.tif", "completed_frames": 1, "total_frames": 4, - }, - { - "image_index": 1, - "image_filename": "Tests/images/multipage.tiff", - "completed_frames": 2, - "total_frames": 4, - }, - { - "image_index": 1, - "image_filename": "Tests/images/multipage.tiff", - "completed_frames": 3, - "total_frames": 4, - }, - { - "image_index": 1, - "image_filename": "Tests/images/multipage.tiff", - "completed_frames": 4, - "total_frames": 4, - }, + } ] + for i in range(3): + expected.append( + { + "image_index": 1, + "image_filename": "Tests/images/multipage.tiff", + "completed_frames": i + 2, + "total_frames": 4, + } + ) + assert progress == expected def test_saving_icc_profile(self, tmp_path): # Tests saving TIFF with icc_profile set. diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 56cfec4e4d3..f3a55c2feb1 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -577,12 +577,12 @@ def _write_multiple_frames(im, fp, palette): duration = im.encoderinfo.get("duration") disposal = im.encoderinfo.get("disposal", im.info.get("disposal")) - progress = im.encoderinfo.get("progress") imSequences = [im] + list(im.encoderinfo.get("append_images", [])) + progress = im.encoderinfo.get("progress") if progress: - n_frames = 0 + total = 0 for imSequence in imSequences: - n_frames += getattr(imSequence, "n_frames", 1) + total += getattr(imSequence, "n_frames", 1) im_frames = [] frame_count = 0 @@ -618,14 +618,7 @@ def _write_multiple_frames(im, fp, palette): if encoderinfo.get("duration"): previous["encoderinfo"]["duration"] += encoderinfo["duration"] if progress: - progress( - { - "image_index": i, - "image_filename": getattr(imSequence, "filename", None), - "completed_frames": frame_count, - "total_frames": n_frames, - } - ) + im._save_all_progress(imSequence, i, frame_count, total) continue if encoderinfo.get("disposal") == 2: if background_im is None: @@ -640,14 +633,7 @@ def _write_multiple_frames(im, fp, palette): bbox = None im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo}) if progress: - progress( - { - "image_index": i, - "image_filename": getattr(imSequence, "filename", None), - "completed_frames": frame_count, - "total_frames": n_frames, - } - ) + im._save_all_progress(imSequence, i, frame_count, total) if len(im_frames) > 1: for frame_data in im_frames: diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 244d2e43520..c413486804d 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2446,6 +2446,23 @@ def save(self, fp, format=None, **params): if open_fp: fp.close() + def _save_all_progress( + self, im=None, im_index=0, completed=1, total=1, progress=None + ): + if not progress: + progress = self.encoderinfo.get("progress") + if not progress: + return + + progress( + { + "image_index": im_index, + "image_filename": getattr(im or self, "filename", None), + "completed_frames": completed, + "total_frames": total, + } + ) + def seek(self, frame): """ Seeks to the given frame in this sequence file. If you seek diff --git a/src/PIL/MpoImagePlugin.py b/src/PIL/MpoImagePlugin.py index 509ec340a06..c36dc9b953a 100644 --- a/src/PIL/MpoImagePlugin.py +++ b/src/PIL/MpoImagePlugin.py @@ -41,7 +41,6 @@ def _save(im, fp, filename): def _save_all(im, fp, filename): - progress = im.encoderinfo.get("progress") append_images = im.encoderinfo.get("append_images", []) if not append_images: try: @@ -50,25 +49,18 @@ def _save_all(im, fp, filename): animated = False if not animated: _save(im, fp, filename) - if progress: - progress( - { - "image_index": 0, - "image_filename": getattr(im, "filename", None), - "completed_frames": 1, - "total_frames": 1, - } - ) + im._save_all_progress() return mpf_offset = 28 offsets = [] imSequences = [im] + list(append_images) + progress = im.encoderinfo.get("progress") if progress: - frame_number = 0 - n_frames = 0 + completed = 0 + total = 0 for imSequence in imSequences: - n_frames += getattr(imSequence, "n_frames", 1) + total += getattr(imSequence, "n_frames", 1) for i, imSequence in enumerate(imSequences): for im_frame in ImageSequence.Iterator(imSequence): if not offsets: @@ -89,15 +81,8 @@ def _save_all(im, fp, filename): im_frame.save(fp, "JPEG") offsets.append(fp.tell() - offsets[-1]) if progress: - frame_number += 1 - progress( - { - "image_index": i, - "image_filename": getattr(imSequence, "filename", None), - "completed_frames": frame_number, - "total_frames": n_frames, - } - ) + completed += 1 + im._save_all_progress(imSequence, i, completed, total, progress) ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd[0xB000] = b"0100" diff --git a/src/PIL/PdfImagePlugin.py b/src/PIL/PdfImagePlugin.py index 9b87f30ce17..7c24c00fe5f 100644 --- a/src/PIL/PdfImagePlugin.py +++ b/src/PIL/PdfImagePlugin.py @@ -246,7 +246,6 @@ def _save(im, fp, filename, save_all=False): # catalog and list of pages existing_pdf.write_catalog() - progress = im.encoderinfo.get("progress") page_number = 0 for i, im_sequence in enumerate(ims): im_pages = ImageSequence.Iterator(im_sequence) if save_all else [im_sequence] @@ -282,15 +281,7 @@ def _save(im, fp, filename, save_all=False): existing_pdf.write_obj(contents_refs[page_number], stream=page_contents) page_number += 1 - if progress: - progress( - { - "image_index": i, - "image_filename": getattr(im_sequence, "filename", None), - "completed_frames": page_number, - "total_frames": number_of_pages, - } - ) + im._save_all_progress(im_sequence, i, page_number, number_of_pages) # # trailer diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 6a44f1b6ef9..395601b997d 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -1098,9 +1098,9 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images) imSequences.append(im) imSequences += append_images if progress: - n_frames = 0 + total = 0 for imSequence in imSequences: - n_frames += getattr(imSequence, "n_frames", 1) + total += getattr(imSequence, "n_frames", 1) im_frames = [] frame_count = 0 @@ -1155,14 +1155,7 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images) "duration", duration ) if progress: - progress( - { - "image_index": i, - "image_filename": getattr(imSequence, "filename", None), - "completed_frames": frame_count, - "total_frames": n_frames, - } - ) + im._save_all_progress(imSequence, i, frame_count, total) continue else: bbox = None @@ -1170,14 +1163,7 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images) encoderinfo["duration"] = duration im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo}) if progress: - progress( - { - "image_index": i, - "image_filename": getattr(imSequence, "filename", None), - "completed_frames": frame_count, - "total_frames": n_frames, - } - ) + im._save_all_progress(imSequence, i, frame_count, total) # animation control chunk( diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 29968de285c..921992cca35 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -2117,28 +2117,20 @@ def fixOffsets(self, count, isShort=False, isLong=False): def _save_all(im, fp, filename): encoderinfo = im.encoderinfo.copy() encoderconfig = im.encoderconfig - progress = encoderinfo.get("progress") append_images = list(encoderinfo.get("append_images", [])) if not hasattr(im, "n_frames") and not append_images: _save(im, fp, filename) - if progress: - progress( - { - "image_index": 0, - "image_filename": getattr(im, "filename", None), - "completed_frames": 1, - "total_frames": 1, - } - ) + im._save_all_progress() return cur_idx = im.tell() imSequences = [im] + append_images + progress = encoderinfo.get("progress") if progress: - frame_number = 0 - n_frames = 0 + completed = 0 + total = 0 for ims in imSequences: - n_frames += getattr(ims, "n_frames", 1) + total += getattr(ims, "n_frames", 1) try: with AppendingTiffWriter(fp) as tf: for i, ims in enumerate(imSequences): @@ -2154,15 +2146,8 @@ def _save_all(im, fp, filename): ims.load() _save(ims, tf, filename) if progress: - frame_number += 1 - progress( - { - "image_index": i, - "image_filename": getattr(ims, "filename", None), - "completed_frames": frame_number, - "total_frames": n_frames, - } - ) + completed += 1 + im._save_all_progress(ims, i, completed, total) tf.newFrame() finally: diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py index ba92bb30453..c35350a75aa 100644 --- a/src/PIL/WebPImagePlugin.py +++ b/src/PIL/WebPImagePlugin.py @@ -177,7 +177,6 @@ def tell(self): def _save_all(im, fp, filename): encoderinfo = im.encoderinfo.copy() - progress = encoderinfo.get("progress") append_images = list(encoderinfo.get("append_images", [])) # If total frame count is 1, then save using the legacy API, which @@ -187,15 +186,7 @@ def _save_all(im, fp, filename): total += getattr(ims, "n_frames", 1) if total == 1: _save(im, fp, filename) - if progress: - progress( - { - "image_index": 0, - "image_filename": getattr(im, "filename", None), - "completed_frames": 1, - "total_frames": 1, - } - ) + im._save_all_progress() return background = (0, 0, 0, 0) @@ -310,15 +301,7 @@ def _save_all(im, fp, filename): else: timestamp += duration frame_idx += 1 - if progress: - progress( - { - "image_index": i, - "image_filename": getattr(ims, "filename", None), - "completed_frames": frame_idx, - "total_frames": total, - } - ) + im._save_all_progress(ims, i, frame_idx, total) finally: im.seek(cur_idx)