mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	When saving multiple frames, convert to mode rather than raw mode
This commit is contained in:
		
							parent
							
								
									bbe1effd63
								
							
						
					
					
						commit
						f34360d1e3
					
				| 
						 | 
					@ -655,11 +655,12 @@ class TestFilePng:
 | 
				
			||||||
            png.call(cid, 0, 0)
 | 
					            png.call(cid, 0, 0)
 | 
				
			||||||
            ImageFile.LOAD_TRUNCATED_IMAGES = False
 | 
					            ImageFile.LOAD_TRUNCATED_IMAGES = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_specify_bits(self, tmp_path: Path) -> None:
 | 
					    @pytest.mark.parametrize("save_all", (True, False))
 | 
				
			||||||
 | 
					    def test_specify_bits(self, save_all: bool, tmp_path: Path) -> None:
 | 
				
			||||||
        im = hopper("P")
 | 
					        im = hopper("P")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = str(tmp_path / "temp.png")
 | 
					        out = str(tmp_path / "temp.png")
 | 
				
			||||||
        im.save(out, bits=4)
 | 
					        im.save(out, bits=4, save_all=save_all)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(out) as reloaded:
 | 
					        with Image.open(out) as reloaded:
 | 
				
			||||||
            assert len(reloaded.png.im_palette[1]) == 48
 | 
					            assert len(reloaded.png.im_palette[1]) == 48
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1104,7 +1104,7 @@ class _fdat:
 | 
				
			||||||
        self.seq_num += 1
 | 
					        self.seq_num += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images):
 | 
					def _write_multiple_frames(im, fp, chunk, mode, rawmode, default_image, append_images):
 | 
				
			||||||
    duration = im.encoderinfo.get("duration", im.info.get("duration", 0))
 | 
					    duration = im.encoderinfo.get("duration", im.info.get("duration", 0))
 | 
				
			||||||
    loop = im.encoderinfo.get("loop", im.info.get("loop", 0))
 | 
					    loop = im.encoderinfo.get("loop", im.info.get("loop", 0))
 | 
				
			||||||
    disposal = im.encoderinfo.get("disposal", im.info.get("disposal", Disposal.OP_NONE))
 | 
					    disposal = im.encoderinfo.get("disposal", im.info.get("disposal", Disposal.OP_NONE))
 | 
				
			||||||
| 
						 | 
					@ -1119,10 +1119,10 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
 | 
				
			||||||
    frame_count = 0
 | 
					    frame_count = 0
 | 
				
			||||||
    for im_seq in chain:
 | 
					    for im_seq in chain:
 | 
				
			||||||
        for im_frame in ImageSequence.Iterator(im_seq):
 | 
					        for im_frame in ImageSequence.Iterator(im_seq):
 | 
				
			||||||
            if im_frame.mode == rawmode:
 | 
					            if im_frame.mode == mode:
 | 
				
			||||||
                im_frame = im_frame.copy()
 | 
					                im_frame = im_frame.copy()
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                im_frame = im_frame.convert(rawmode)
 | 
					                im_frame = im_frame.convert(mode)
 | 
				
			||||||
            encoderinfo = im.encoderinfo.copy()
 | 
					            encoderinfo = im.encoderinfo.copy()
 | 
				
			||||||
            if isinstance(duration, (list, tuple)):
 | 
					            if isinstance(duration, (list, tuple)):
 | 
				
			||||||
                encoderinfo["duration"] = duration[frame_count]
 | 
					                encoderinfo["duration"] = duration[frame_count]
 | 
				
			||||||
| 
						 | 
					@ -1184,8 +1184,8 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # default image IDAT (if it exists)
 | 
					    # default image IDAT (if it exists)
 | 
				
			||||||
    if default_image:
 | 
					    if default_image:
 | 
				
			||||||
        if im.mode != rawmode:
 | 
					        if im.mode != mode:
 | 
				
			||||||
            im = im.convert(rawmode)
 | 
					            im = im.convert(mode)
 | 
				
			||||||
        ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
 | 
					        ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    seq_num = 0
 | 
					    seq_num = 0
 | 
				
			||||||
| 
						 | 
					@ -1262,6 +1262,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
 | 
				
			||||||
        size = im.size
 | 
					        size = im.size
 | 
				
			||||||
        mode = im.mode
 | 
					        mode = im.mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    outmode = mode
 | 
				
			||||||
    if mode == "P":
 | 
					    if mode == "P":
 | 
				
			||||||
        #
 | 
					        #
 | 
				
			||||||
        # attempt to minimize storage requirements for palette images
 | 
					        # attempt to minimize storage requirements for palette images
 | 
				
			||||||
| 
						 | 
					@ -1282,7 +1283,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
 | 
				
			||||||
                bits = 2
 | 
					                bits = 2
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                bits = 4
 | 
					                bits = 4
 | 
				
			||||||
            mode = f"{mode};{bits}"
 | 
					            outmode += f";{bits}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # encoder options
 | 
					    # encoder options
 | 
				
			||||||
    im.encoderconfig = (
 | 
					    im.encoderconfig = (
 | 
				
			||||||
| 
						 | 
					@ -1294,7 +1295,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # get the corresponding PNG mode
 | 
					    # get the corresponding PNG mode
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        rawmode, bit_depth, color_type = _OUTMODES[mode]
 | 
					        rawmode, bit_depth, color_type = _OUTMODES[outmode]
 | 
				
			||||||
    except KeyError as e:
 | 
					    except KeyError as e:
 | 
				
			||||||
        msg = f"cannot write mode {mode} as PNG"
 | 
					        msg = f"cannot write mode {mode} as PNG"
 | 
				
			||||||
        raise OSError(msg) from e
 | 
					        raise OSError(msg) from e
 | 
				
			||||||
| 
						 | 
					@ -1415,7 +1416,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save_all:
 | 
					    if save_all:
 | 
				
			||||||
        im = _write_multiple_frames(
 | 
					        im = _write_multiple_frames(
 | 
				
			||||||
            im, fp, chunk, rawmode, default_image, append_images
 | 
					            im, fp, chunk, mode, rawmode, default_image, append_images
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    if im:
 | 
					    if im:
 | 
				
			||||||
        ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
 | 
					        ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user