mirror of
https://github.com/google/pebble.git
synced 2025-03-26 13:09:06 +00:00
151 lines
7.6 KiB
Python
151 lines
7.6 KiB
Python
# Copyright 2024 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from resources.types.resource_object import ResourceObject
|
|
from resources.resource_map.resource_generator import ResourceGenerator
|
|
|
|
from pebble_sdk_platform import pebble_platforms
|
|
|
|
import bitmapgen
|
|
import png2pblpng
|
|
import re
|
|
|
|
PNG_MIN_APP_MEMORY = 0x8000 # 32k, fairly arbitrarily
|
|
|
|
class BitmapResourceGenerator(ResourceGenerator):
|
|
type = 'bitmap'
|
|
|
|
@staticmethod
|
|
def definitions_from_dict(bld, definition_dict, resource_source_path):
|
|
definitions = ResourceGenerator.definitions_from_dict(bld, definition_dict,
|
|
resource_source_path)
|
|
for d in definitions:
|
|
d.memory_format = definition_dict.get('memoryFormat', 'smallest')
|
|
d.space_optimization = definition_dict.get('spaceOptimization', None)
|
|
d.storage_format = definition_dict.get('storageFormat', None)
|
|
return definitions
|
|
|
|
@classmethod
|
|
def generate_object(cls, task, definition):
|
|
env = task.generator.env
|
|
|
|
memory_format = definition.memory_format.lower()
|
|
# Some options are mutually exclusive.
|
|
if definition.space_optimization == 'memory' and definition.storage_format == 'png':
|
|
task.generator.bld.fatal("{}: spaceOptimization: memory and storageFormat: "
|
|
"png are mutually exclusive.".format(definition.name))
|
|
if definition.space_optimization == 'storage' and definition.storage_format == 'pbi':
|
|
task.generator.bld.fatal("{}: spaceOptimization: storage and storageFormat: "
|
|
"pbi are mutually exclusive.".format(definition.name))
|
|
if definition.storage_format == 'png' and memory_format == '1bit':
|
|
task.generator.bld.fatal("{}: PNG storage does not support non-palettised 1-bit images."
|
|
.format(definition.name))
|
|
|
|
# If storage_format is not specified, it is completely determined by space_optimization.
|
|
if definition.storage_format is None and definition.space_optimization is not None:
|
|
format_mapping = {
|
|
'storage': 'png',
|
|
'memory': 'pbi',
|
|
}
|
|
try:
|
|
definition.storage_format = format_mapping[definition.space_optimization]
|
|
except KeyError:
|
|
task.generator.bld.fatal("{}: Invalid spaceOptimization '{}'. Use one of {}."
|
|
.format(definition.name, definition.space_optimization,
|
|
', '.join(format_mapping.keys())))
|
|
|
|
if definition.storage_format is None:
|
|
if pebble_platforms[env.PLATFORM_NAME]['MAX_APP_MEMORY_SIZE'] < PNG_MIN_APP_MEMORY:
|
|
definition.storage_format = 'pbi'
|
|
else:
|
|
definition.storage_format = 'png'
|
|
|
|
# At this point, what we want to do should be completely determined (though, depending on
|
|
# image content, not necessarily actually possible); begin figuring out what to actually do.
|
|
|
|
is_color = 'color' in pebble_platforms[env.PLATFORM_NAME]['TAGS']
|
|
palette_name = png2pblpng.get_ideal_palette(is_color)
|
|
_, _, bitdepth, _ = png2pblpng.get_palette_for_png(task.inputs[0].abspath(), palette_name,
|
|
png2pblpng.DEFAULT_COLOR_REDUCTION)
|
|
|
|
formats = {
|
|
'1bit',
|
|
'8bit',
|
|
'smallest',
|
|
'smallestpalette',
|
|
'1bitpalette',
|
|
'2bitpalette',
|
|
'4bitpalette',
|
|
}
|
|
if memory_format not in formats:
|
|
task.generator.bld.fatal("{}: Invalid memoryFormat {} (pick one of {})."
|
|
.format(definition.name, definition.memory_format,
|
|
', '.join(formats)))
|
|
|
|
# "smallest" is always palettised, unless the image has too many colours, in which case it
|
|
# cannot be.
|
|
if memory_format == 'smallest':
|
|
if bitdepth <= 4:
|
|
memory_format = 'smallestpalette'
|
|
else:
|
|
memory_format = '8bit'
|
|
|
|
if 'palette' in memory_format:
|
|
if memory_format == 'smallestpalette':
|
|
# If they asked for "smallestpalette", replace that with its actual value.
|
|
if bitdepth > 4:
|
|
task.generator.bld.fatal("{} has too many colours for a palettised image"
|
|
"(max 16), but 'SmallestPalette' specified."
|
|
.format(definition.name))
|
|
else:
|
|
memory_format = '{}bitpalette'.format(bitdepth)
|
|
|
|
# Pull out however many bits we're supposed to use (which is exact, not a min or max)
|
|
bits = int(re.match(r'^(\d+)bitpalette$', memory_format).group(1))
|
|
if bits < bitdepth:
|
|
task.generator.bld.fatal("{}: requires at least {} bits.".format(definition.name,
|
|
bitdepth))
|
|
if bits > 2 and not is_color:
|
|
task.generator.bld.fatal("{}: can't use more than two bits on a black-and-white"
|
|
"platform." .format(definition.name))
|
|
|
|
if definition.storage_format == 'pbi':
|
|
pb = bitmapgen.PebbleBitmap(task.inputs[0].abspath(), bitmap_format='color',
|
|
bitdepth=bits, crop=False, palette_name=palette_name)
|
|
return ResourceObject(definition, pb.convert_to_pbi())
|
|
else:
|
|
image_bytes = png2pblpng.convert_png_to_pebble_png_bytes(task.inputs[0].abspath(),
|
|
palette_name,
|
|
bitdepth=bits)
|
|
return ResourceObject(definition, image_bytes)
|
|
else:
|
|
if memory_format == '1bit':
|
|
pb = bitmapgen.PebbleBitmap(task.inputs[0].abspath(), bitmap_format='bw',
|
|
crop=False)
|
|
return ResourceObject(definition, pb.convert_to_pbi())
|
|
elif memory_format == '8bit':
|
|
if not is_color:
|
|
task.generator.bld.fatal("{}: can't use more than two bits on a black-and-white"
|
|
"platform.".format(definition.name))
|
|
# generate an 8-bit pbi or png, as appropriate.
|
|
if definition.storage_format == 'pbi':
|
|
pb = bitmapgen.PebbleBitmap(task.inputs[0].abspath(), bitmap_format='color_raw',
|
|
crop=False, palette_name=palette_name)
|
|
return ResourceObject(definition, pb.convert_to_pbi())
|
|
else:
|
|
image_bytes = png2pblpng.convert_png_to_pebble_png_bytes(
|
|
task.inputs[0].abspath(), palette_name, bitdepth=8)
|
|
return ResourceObject(definition, image_bytes)
|
|
|
|
raise Exception("Got to the end without doing anything?")
|