xref: /aosp_15_r20/bootable/recovery/interlace-frames.py (revision e7c364b630b241adcb6c7726a21055250b91fdac)
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