bootsplash: Add ImageMagick voodoo

The JPEG decoder, that was added many years ago to display a boot-
splash in coreboot, has a few quirks. People used to do some voodoo
with GIMP to convert images to the right format, but we can also
achieve the same with ImageMagick's `convert`. The currently known
constraints are:
* The framebuffer's color format is ignored,
* only YCC 4:2:0 color sampling is supported, and
* width and height have to be a multiple of 16 pixels.

Beside that, we can only display the bootsplash if it completely
fits into the framebuffer. As the latter's size is often decided
at runtime, we can't do much more than offering an option to set
a specific size.

Change-Id: I564e0d89fb46503ff4c11e095726616700009968
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/76564
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin L Roth <gaumless@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@mailbox.org>
diff --git a/Makefile.inc b/Makefile.inc
index 414ef76..b5665a7 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -357,6 +357,41 @@
 	$(eval DEPENDENCIES += $(2).d)
 
 #######################################################################
+# Convert image to YCC 4:2:0 JPEG
+#
+# In two steps:
+# 1. Convert to RGB colors, optionally resize and store as BMP.
+# 2. Round final size to multiples of 16, optionally swap colors,
+#    convert (back) to sRGB and store as JPEG.
+# The split is necessary because we don't know the exact, scaled
+# size due to aspect-ratio. Note: IM v7 would allow us to do the
+# calculations in one command using %[fx:...] syntax.
+#
+# arg1: image input file
+# arg2: output jpg
+cbfs-files-processor-jpg420= \
+	$(eval $(2): $(1) $(KCONFIG_AUTOCONFIG);				\
+		printf "    CONVERT    $$<\n";					\
+		res=$(CONFIG_BOOTSPLASH_CONVERT_RESOLUTION);			\
+		res=$$$$(convert $$<						\
+			-colorspace RGB						\
+			$$(BOOTSPLASH_RESIZE-y)					\
+			-format '%wx%h' -write info:				\
+			bmp:$$@);						\
+		convert $$@							\
+			$$(BOOTSPLASH_ROUND16)					\
+			$$(BOOTSPLASH_COLORSWAP-y)				\
+			-colorspace sRGB					\
+			-quality $$(CONFIG_BOOTSPLASH_CONVERT_QUALITY)%		\
+			-interlace none -colorspace YCC -sampling-factor 4:2:0	\
+			jpg:$$@)
+BOOTSPLASH_FLOOR = $$(($${res%%x*} & ~15))x$$(($${res\#\#*x} & ~15))
+BOOTSPLASH_RESIZE-$(CONFIG_BOOTSPLASH_CONVERT_RESIZE) = -resize $(BOOTSPLASH_FLOOR)
+BOOTSPLASH_CEIL = $$((($${res%%x*} + 15) & ~15))x$$((($${res\#\#*x} + 15) & ~15))
+BOOTSPLASH_ROUND16 = -background black -gravity center -extent $(BOOTSPLASH_CEIL)
+BOOTSPLASH_COLORSWAP-$(CONFIG_BOOTSPLASH_CONVERT_COLORSWAP) := -channel-fx 'red<=>blue'
+
+#######################################################################
 # Add handler for arbitrary files in CBFS
 $(call add-special-class,cbfs-files)
 cbfs-files-handler= \
@@ -1281,10 +1316,19 @@
 build_info-file := $(obj)/build_info
 build_info-type := raw
 
+ifeq ($(CONFIG_BOOTSPLASH_CONVERT),y)
+ifeq ($(shell command -v convert),)
+$(error CONFIG_BOOTSPLASH_CONVERT requires the convert program (part of ImageMagick))
+endif
+cbfs-files-$(CONFIG_BOOTSPLASH_IMAGE) += bootsplash.jpg
+bootsplash.jpg-file := $(call strip_quotes,$(CONFIG_BOOTSPLASH_FILE)):jpg420
+bootsplash.jpg-type := bootsplash
+else
 BOOTSPLASH_SUFFIX=$(suffix $(call strip_quotes,$(CONFIG_BOOTSPLASH_FILE)))
 cbfs-files-$(CONFIG_BOOTSPLASH_IMAGE) += bootsplash$(BOOTSPLASH_SUFFIX)
 bootsplash$(BOOTSPLASH_SUFFIX)-file := $(call strip_quotes,$(CONFIG_BOOTSPLASH_FILE))
 bootsplash$(BOOTSPLASH_SUFFIX)-type := bootsplash
+endif
 
 # Ensure that no payload segment overlaps with memory regions used by ramstage
 # (not for x86 since it can relocate itself in that case)