1*e7c364b6SAndroid Build Coastguard Worker#!/usr/bin/env python 2*e7c364b6SAndroid Build Coastguard Worker# Copyright (C) 2014 The Android Open Source Project 3*e7c364b6SAndroid Build Coastguard Worker# 4*e7c364b6SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*e7c364b6SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*e7c364b6SAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*e7c364b6SAndroid Build Coastguard Worker# 8*e7c364b6SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*e7c364b6SAndroid Build Coastguard Worker# 10*e7c364b6SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*e7c364b6SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*e7c364b6SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*e7c364b6SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*e7c364b6SAndroid Build Coastguard Worker# limitations under the License. 15*e7c364b6SAndroid Build Coastguard Worker 16*e7c364b6SAndroid Build Coastguard Worker""" 17*e7c364b6SAndroid Build Coastguard WorkerScript to take a set of frames (PNG files) for a recovery animation 18*e7c364b6SAndroid Build Coastguard Workerand turn it into a single output image which contains the input frames 19*e7c364b6SAndroid Build Coastguard Workerinterlaced by row. Run with the names of all the input frames on the 20*e7c364b6SAndroid Build Coastguard Workercommand line, in order, followed by the name of the output file. 21*e7c364b6SAndroid Build Coastguard Worker""" 22*e7c364b6SAndroid Build Coastguard Worker 23*e7c364b6SAndroid Build Coastguard Workerfrom __future__ import print_function 24*e7c364b6SAndroid Build Coastguard Worker 25*e7c364b6SAndroid Build Coastguard Workerimport argparse 26*e7c364b6SAndroid Build Coastguard Workerimport os.path 27*e7c364b6SAndroid Build Coastguard Workerimport sys 28*e7c364b6SAndroid Build Coastguard Workertry: 29*e7c364b6SAndroid Build Coastguard Worker import Image 30*e7c364b6SAndroid Build Coastguard Worker import PngImagePlugin 31*e7c364b6SAndroid Build Coastguard Workerexcept ImportError: 32*e7c364b6SAndroid Build Coastguard Worker print("This script requires the Python Imaging Library to be installed.") 33*e7c364b6SAndroid Build Coastguard Worker sys.exit(1) 34*e7c364b6SAndroid Build Coastguard Worker 35*e7c364b6SAndroid Build Coastguard Worker 36*e7c364b6SAndroid Build Coastguard Workerdef interlace(output, inputs): 37*e7c364b6SAndroid Build Coastguard Worker frames = [Image.open(fn).convert("RGB") for fn in inputs] 38*e7c364b6SAndroid Build Coastguard Worker assert len(frames) > 0, "Must have at least one input frame." 39*e7c364b6SAndroid Build Coastguard Worker sizes = set() 40*e7c364b6SAndroid Build Coastguard Worker for fr in frames: 41*e7c364b6SAndroid Build Coastguard Worker sizes.add(fr.size) 42*e7c364b6SAndroid Build Coastguard Worker 43*e7c364b6SAndroid Build Coastguard Worker assert len(sizes) == 1, "All input images must have the same size." 44*e7c364b6SAndroid Build Coastguard Worker w, h = sizes.pop() 45*e7c364b6SAndroid Build Coastguard Worker N = len(frames) 46*e7c364b6SAndroid Build Coastguard Worker 47*e7c364b6SAndroid Build Coastguard Worker out = Image.new("RGB", (w, h*N)) 48*e7c364b6SAndroid Build Coastguard Worker for j in range(h): 49*e7c364b6SAndroid Build Coastguard Worker for i in range(w): 50*e7c364b6SAndroid Build Coastguard Worker for fn, f in enumerate(frames): 51*e7c364b6SAndroid Build Coastguard Worker out.putpixel((i, j*N+fn), f.getpixel((i, j))) 52*e7c364b6SAndroid Build Coastguard Worker 53*e7c364b6SAndroid Build Coastguard Worker # When loading this image, the graphics library expects to find a text 54*e7c364b6SAndroid Build Coastguard Worker # chunk that specifies how many frames this animation represents. If 55*e7c364b6SAndroid Build Coastguard Worker # you post-process the output of this script with some kind of 56*e7c364b6SAndroid Build Coastguard Worker # optimizer tool (eg pngcrush or zopflipng) make sure that your 57*e7c364b6SAndroid Build Coastguard Worker # optimizer preserves this text chunk. 58*e7c364b6SAndroid Build Coastguard Worker 59*e7c364b6SAndroid Build Coastguard Worker meta = PngImagePlugin.PngInfo() 60*e7c364b6SAndroid Build Coastguard Worker meta.add_text("Frames", str(N)) 61*e7c364b6SAndroid Build Coastguard Worker 62*e7c364b6SAndroid Build Coastguard Worker out.save(output, pnginfo=meta) 63*e7c364b6SAndroid Build Coastguard Worker 64*e7c364b6SAndroid Build Coastguard Worker 65*e7c364b6SAndroid Build Coastguard Workerdef deinterlace(output, input): 66*e7c364b6SAndroid Build Coastguard Worker # Truncate the output filename extension if it's '.png'. 67*e7c364b6SAndroid Build Coastguard Worker if os.path.splitext(output)[1].lower() == '.png': 68*e7c364b6SAndroid Build Coastguard Worker output = output[:-4] 69*e7c364b6SAndroid Build Coastguard Worker 70*e7c364b6SAndroid Build Coastguard Worker img2 = Image.open(input) 71*e7c364b6SAndroid Build Coastguard Worker print(img2.mode) 72*e7c364b6SAndroid Build Coastguard Worker palette = img2.getpalette() 73*e7c364b6SAndroid Build Coastguard Worker img = img2.convert("RGB") 74*e7c364b6SAndroid Build Coastguard Worker num_frames = int(img.info.get('Frames', 1)) 75*e7c364b6SAndroid Build Coastguard Worker print('Found %d frames in %s.' % (num_frames, input)) 76*e7c364b6SAndroid Build Coastguard Worker assert num_frames > 0, 'Invalid Frames meta.' 77*e7c364b6SAndroid Build Coastguard Worker 78*e7c364b6SAndroid Build Coastguard Worker # palette = img.getpalette() 79*e7c364b6SAndroid Build Coastguard Worker print(palette) 80*e7c364b6SAndroid Build Coastguard Worker 81*e7c364b6SAndroid Build Coastguard Worker width, height = img.size 82*e7c364b6SAndroid Build Coastguard Worker height /= num_frames 83*e7c364b6SAndroid Build Coastguard Worker for k in range(num_frames): 84*e7c364b6SAndroid Build Coastguard Worker out = Image.new('RGB', (width, height)) 85*e7c364b6SAndroid Build Coastguard Worker out.info = img.info 86*e7c364b6SAndroid Build Coastguard Worker for i in range(width): 87*e7c364b6SAndroid Build Coastguard Worker for j in range(height): 88*e7c364b6SAndroid Build Coastguard Worker out.putpixel((i, j), img.getpixel((i, j * num_frames + k))) 89*e7c364b6SAndroid Build Coastguard Worker # out.putpalette(img.getpalette(), rawmode='RGB') 90*e7c364b6SAndroid Build Coastguard Worker out2 = out.convert(mode='P', palette=palette) 91*e7c364b6SAndroid Build Coastguard Worker #out2 = out 92*e7c364b6SAndroid Build Coastguard Worker print(out2.mode) 93*e7c364b6SAndroid Build Coastguard Worker # out2.putpalette(palette) 94*e7c364b6SAndroid Build Coastguard Worker filename = '%s%02d.png' % (output, k) 95*e7c364b6SAndroid Build Coastguard Worker out2.save(filename) 96*e7c364b6SAndroid Build Coastguard Worker print('Frame %d written to %s.' % (k, filename)) 97*e7c364b6SAndroid Build Coastguard Worker 98*e7c364b6SAndroid Build Coastguard Worker 99*e7c364b6SAndroid Build Coastguard Workerdef main(argv): 100*e7c364b6SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description='Parse') 101*e7c364b6SAndroid Build Coastguard Worker parser.add_argument('--deinterlace', '-d', action='store_true') 102*e7c364b6SAndroid Build Coastguard Worker parser.add_argument('--output', '-o', required=True) 103*e7c364b6SAndroid Build Coastguard Worker parser.add_argument('input', nargs='+') 104*e7c364b6SAndroid Build Coastguard Worker args = parser.parse_args(argv) 105*e7c364b6SAndroid Build Coastguard Worker 106*e7c364b6SAndroid Build Coastguard Worker if args.deinterlace: 107*e7c364b6SAndroid Build Coastguard Worker # args.input is a list, and we only process the first when deinterlacing. 108*e7c364b6SAndroid Build Coastguard Worker deinterlace(args.output, args.input[0]) 109*e7c364b6SAndroid Build Coastguard Worker else: 110*e7c364b6SAndroid Build Coastguard Worker interlace(args.output, args.input) 111*e7c364b6SAndroid Build Coastguard Worker 112*e7c364b6SAndroid Build Coastguard Worker 113*e7c364b6SAndroid Build Coastguard Workerif __name__ == '__main__': 114*e7c364b6SAndroid Build Coastguard Worker main(sys.argv[1:]) 115