diff --git a/resources/g2/sprites.json b/resources/g2/sprites.json index f7aa6dd278..d2f4bd51f3 100644 --- a/resources/g2/sprites.json +++ b/resources/g2/sprites.json @@ -314,242 +314,242 @@ { "path": "palette_map/palette_map_dark_olive_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_dark_olive_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_saturated_brown_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_bordeaux_red_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_bordeaux_red_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_grass_green_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_grass_green_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_olive_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_olive_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_saturated_green_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_tan_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_tan_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_dull_purple_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_dull_green_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_dull_green_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_saturated_purple_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_saturated_purple_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_orange_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_aqua_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_magenta_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_dull_brown_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_dull_brown_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_invisible.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_void.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_dark_olive_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_dark_olive_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_saturated_brown_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_bordeaux_red_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_bordeaux_red_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_grass_green_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_grass_green_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_olive_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_olive_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_saturated_green_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_tan_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_tan_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_dull_purple_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_dull_green_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_dull_green_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_saturated_purple_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_saturated_purple_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_orange_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_aqua_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_magenta_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_dull_brown_dark.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_dull_brown_light.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_invisible.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "palette_map/palette_map_glass_void.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "surface/glassy_recolourable.png", @@ -581,1961 +581,1961 @@ "path": "font/latin/ae-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/ae-small.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-stroke-uc-small.png", "x": -1, "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-stroke-small.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1028-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1041-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1043-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1044-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1046-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1047-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1048-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1049-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1051-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1055-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1059-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1060-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1062-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1063-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1064-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1065-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1066-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1067-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1068-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1069-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1070-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1071-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1073-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1074-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1075-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1076-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1078-small.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1079-small.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1080-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1081-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1082-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1083-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1084-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1085-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1087-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1090-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1092-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1094-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1095-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1096-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1097-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1099-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1100-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1101-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1102-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1103-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1108-small.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1168-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1169-small.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/german-openquotes-small.png", "y": 6, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/guilder-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-breve-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/i-with-dot-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-cedilla-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-breve-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/i-without-dot-small.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-cedilla-small.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/interpunct-small.png", "y": 3, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/a-breve-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-comma-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-comma-small.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/ellipsis-small.png", "y": 6, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-caron-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-caron-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-acute-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-acute-small.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-double-acute-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-double-acute-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/oe-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/oe-small.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-double-acute-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-double-acute-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/d-caron-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/d-caron-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/e-caron-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/e-caron-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/n-caron-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/n-caron-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/r-caron-uc-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/r-caron-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-caron-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-caron-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-caron-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-caron-small.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-ring-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-ring-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/w-circumflex-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/w-circumflex-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-circumflex-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-circumflex-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/z-caron-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/z-caron-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/rouble-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-small.png", "x": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/l-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-circumflex-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-circumflex-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-circumflex-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-circumflex-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/h-circumflex-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/h-circumflex-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-circumflex-uc-small.png", "x": -1, "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-circumflex-small.png", "x": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-circumflex-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-circumflex-small.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-breve-uc-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-breve-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/left-brace-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/vertical-bar-small.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/right-brace-small.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/tilde-small.png", "y": 3, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/eye.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/ae-uc-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/ae-bold.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-stroke-uc-bold.png", "x": -1, "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-stroke-bold.png", "x": 0, "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1028-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1041-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1043-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1044-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1046-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1047-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1048-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1049-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1051-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1055-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1059-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1060-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1062-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1063-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1064-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1065-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1066-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1067-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1068-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1069-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1070-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1071-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1073-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1074-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1075-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1076-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1078-bold.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1079-bold.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1080-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1081-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1082-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1083-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1084-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1085-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1087-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1090-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1092-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1094-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1095-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1096-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1097-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1099-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1100-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1101-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1102-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1103-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1108-bold.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1168-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1169-bold.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/german-openquotes-bold.png", "y": 5, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/guilder-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-breve-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/i-with-dot-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-cedilla-uc-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-breve-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/i-without-dot-bold.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-cedilla-bold.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/interpunct-bold.png", "y": 3, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/a-breve-uc-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-comma-uc-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-comma-bold.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/ellipsis-bold.png", "y": 6, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-caron-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-caron-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-acute-uc-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-acute-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-double-acute-uc-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-double-acute-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/oe-uc-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/oe-bold.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-double-acute-uc-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-double-acute-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/d-caron-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/d-caron-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/e-caron-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/e-caron-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/n-caron-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/n-caron-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/r-caron-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/r-caron-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-caron-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-caron-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-caron-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-caron-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-ring-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-ring-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/w-circumflex-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/w-circumflex-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-circumflex-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-circumflex-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/z-caron-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/z-caron-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/rouble-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-bold.png", "x": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/l-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-circumflex-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-circumflex-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-circumflex-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-circumflex-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/h-circumflex-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/h-circumflex-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-circumflex-uc-bold.png", "x": -1, "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-circumflex-bold.png", "x": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-circumflex-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-circumflex-bold.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-breve-uc-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-breve-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/left-brace-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/vertical-bar-bold.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/right-brace-bold.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/tilde-bold.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/eye.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/ae-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/ae-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-stroke-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-stroke-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1028-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1041-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1043-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1044-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1046-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1047-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1048-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1049-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1051-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1055-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1059-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1060-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1062-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1063-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1064-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1065-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1066-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1067-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1068-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1069-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1070-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1071-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1073-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1074-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1075-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1076-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1078-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1079-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1080-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1081-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1082-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1083-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1084-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1085-tiny.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1087-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1090-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1092-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1094-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1095-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1096-tiny.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1097-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1099-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1100-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1101-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1102-tiny.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1103-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1108-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1168-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/cyrillic/U1169-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/german-openquotes-tiny.png", "y": 4, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/guilder-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-breve-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/i-with-dot-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-cedilla-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-breve-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/i-without-dot-tiny.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-cedilla-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/interpunct-tiny.png", "y": 2, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/a-breve-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-comma-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-comma-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/ellipsis-tiny.png", "y": 4, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-caron-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-caron-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-acute-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-acute-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-double-acute-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/o-double-acute-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/oe-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/oe-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-double-acute-uc-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-double-acute-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/d-caron-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/d-caron-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/e-caron-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/e-caron-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/n-caron-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/n-caron-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/r-caron-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/r-caron-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-caron-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-caron-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-caron-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/t-caron-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-ring-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-ring-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/w-circumflex-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/w-circumflex-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-circumflex-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/y-circumflex-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/z-caron-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/z-caron-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/rouble-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-tiny.png", "x": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/l-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-circumflex-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/c-circumflex-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-circumflex-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/g-circumflex-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/h-circumflex-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/h-circumflex-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-circumflex-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/j-circumflex-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-circumflex-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/s-circumflex-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-breve-uc-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/latin/u-breve-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/left-brace-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/vertical-bar-tiny.png", "y": -1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/right-brace-tiny.png", "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/tilde-tiny.png", "y": 1, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "font/eye-tiny.png", "y": 0, "palette": "keep", - "forceBmp": true + "format": "raw" }, { "path": "track/junior/flat_to_steep_1.png" diff --git a/src/openrct2-ui/scripting/CustomImages.cpp b/src/openrct2-ui/scripting/CustomImages.cpp index e2700b8740..c3839c7cae 100644 --- a/src/openrct2-ui/scripting/CustomImages.cpp +++ b/src/openrct2-ui/scripting/CustomImages.cpp @@ -275,6 +275,21 @@ namespace OpenRCT2::Scripting return unpadded; } + static ImportMode getImportModeFromPalette(const PixelDataPaletteKind& palette) + { + switch (palette) + { + case PixelDataPaletteKind::Closest: + return ImportMode::Closest; + case PixelDataPaletteKind::Dither: + return ImportMode::Dithering; + case PixelDataPaletteKind::None: + case PixelDataPaletteKind::Keep: + default: + return ImportMode::Default; + } + } + static std::vector GetBufferFromPixelData(duk_context* ctx, PixelData& pixelData) { std::vector imageData; @@ -303,18 +318,14 @@ namespace OpenRCT2::Scripting case PixelDataKind::Png: { auto imageFormat = pixelData.Palette == PixelDataPaletteKind::Keep ? IMAGE_FORMAT::PNG : IMAGE_FORMAT::PNG_32; - auto palette = pixelData.Palette == PixelDataPaletteKind::Keep ? ImageImporter::Palette::KeepIndices - : ImageImporter::Palette::OpenRCT2; - auto importMode = ImageImporter::ImportMode::Default; - if (pixelData.Palette == PixelDataPaletteKind::Closest) - importMode = ImageImporter::ImportMode::Closest; - else if (pixelData.Palette == PixelDataPaletteKind::Dither) - importMode = ImageImporter::ImportMode::Dithering; + auto palette = pixelData.Palette == PixelDataPaletteKind::Keep ? Palette::KeepIndices : Palette::OpenRCT2; + auto importMode = getImportModeFromPalette(pixelData.Palette); auto pngData = DukGetDataFromBufferLikeObject(pixelData.Data); auto image = Imaging::ReadFromBuffer(pngData, imageFormat); + ImageImportMeta meta = { { 0, 0 }, palette, ImportFlags::RLE, importMode }; ImageImporter importer; - auto importResult = importer.Import(image, 0, 0, palette, ImageImporter::ImportFlags::RLE, importMode); + auto importResult = importer.Import(image, meta); pixelData.Type = PixelDataKind::Rle; pixelData.Width = importResult.Element.width; diff --git a/src/openrct2/CommandLineSprite.cpp b/src/openrct2/CommandLineSprite.cpp index fa8d1c2138..ffe578309d 100644 --- a/src/openrct2/CommandLineSprite.cpp +++ b/src/openrct2/CommandLineSprite.cpp @@ -225,21 +225,12 @@ static bool SpriteImageExport(const G1Element& spriteElement, u8string_view outP } } -static std::optional SpriteImageImport( - const char* path, int16_t x_offset, int16_t y_offset, ImageImporter::Palette palette, bool forceBmp, - ImageImporter::ImportMode mode) +static std::optional SpriteImageImport(u8string_view path, ImageImportMeta meta) { try { auto format = IMAGE_FORMAT::PNG_32; - auto flags = ImageImporter::ImportFlags::None; - - if (!forceBmp) - { - flags = ImageImporter::ImportFlags::RLE; - } - - if (palette == ImageImporter::Palette::KeepIndices) + if (meta.palette == Palette::KeepIndices) { format = IMAGE_FORMAT::PNG; } @@ -247,7 +238,7 @@ static std::optional SpriteImageImport( ImageImporter importer; auto image = Imaging::ReadFromFile(path, format); - return importer.Import(image, x_offset, y_offset, palette, flags, mode); + return importer.Import(image, meta); } catch (const std::exception& e) { @@ -483,21 +474,21 @@ int32_t CommandLineForSprite(const char** argv, int32_t argc) const utf8* spriteFilePath = argv[1]; const utf8* imagePath = argv[2]; - int16_t x_offset = 0; - int16_t y_offset = 0; + int16_t xOffset = 0; + int16_t yOffset = 0; if (argc == 5) { char* endptr; - x_offset = strtol(argv[3], &endptr, 0); + xOffset = strtol(argv[3], &endptr, 0); if (*endptr != 0) { fprintf(stderr, "X offset must be an integer\n"); return -1; } - y_offset = strtol(argv[4], &endptr, 0); + yOffset = strtol(argv[4], &endptr, 0); if (*endptr != 0) { fprintf(stderr, "Y offset must be an integer\n"); @@ -505,8 +496,8 @@ int32_t CommandLineForSprite(const char** argv, int32_t argc) } } - auto importResult = SpriteImageImport( - imagePath, x_offset, y_offset, ImageImporter::Palette::OpenRCT2, false, gSpriteMode); + ImageImportMeta meta = { { xOffset, yOffset }, Palette::OpenRCT2, ImportFlags::RLE, gSpriteMode }; + auto importResult = SpriteImageImport(imagePath, meta); if (!importResult.has_value()) return -1; @@ -579,18 +570,12 @@ int32_t CommandLineForSprite(const char** argv, int32_t argc) } std::string strPath = Json::GetString(path); - json_t x_offset = jsonSprite["x"]; - json_t y_offset = jsonSprite["y"]; - - auto palette = (Json::GetString(jsonSprite["palette"]) == "keep") ? ImageImporter::Palette::KeepIndices - : ImageImporter::Palette::OpenRCT2; - bool forceBmp = !jsonSprite["palette"].is_null() && Json::GetBoolean(jsonSprite["forceBmp"]); + auto meta = createImageImportMetaFromJson(jsonSprite); + meta.importMode = gSpriteMode; auto imagePath = Path::GetAbsolute(Path::Combine(directoryPath, strPath)); - auto importResult = SpriteImageImport( - imagePath.c_str(), Json::GetNumber(x_offset), Json::GetNumber(y_offset), palette, forceBmp, - gSpriteMode); + auto importResult = SpriteImageImport(imagePath, meta); if (importResult == std::nullopt) { fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath.c_str()); diff --git a/src/openrct2/CommandLineSprite.h b/src/openrct2/CommandLineSprite.h index ec31c9505a..726722ec10 100644 --- a/src/openrct2/CommandLineSprite.h +++ b/src/openrct2/CommandLineSprite.h @@ -13,4 +13,4 @@ #include "drawing/ImageImporter.h" int32_t CommandLineForSprite(const char** argv, int32_t argc); -extern OpenRCT2::Drawing::ImageImporter::ImportMode gSpriteMode; +extern OpenRCT2::Drawing::ImportMode gSpriteMode; diff --git a/src/openrct2/command_line/SpriteCommands.cpp b/src/openrct2/command_line/SpriteCommands.cpp index 6bb5ca1b0c..7e13e9791f 100644 --- a/src/openrct2/command_line/SpriteCommands.cpp +++ b/src/openrct2/command_line/SpriteCommands.cpp @@ -16,7 +16,7 @@ #define SZ_CLOSEST "closest" #define SZ_DITHERING "dithering" -using ImportMode = OpenRCT2::Drawing::ImageImporter::ImportMode; +using ImportMode = OpenRCT2::Drawing::ImportMode; ImportMode gSpriteMode = ImportMode::Default; diff --git a/src/openrct2/drawing/ImageImporter.cpp b/src/openrct2/drawing/ImageImporter.cpp index 2d5354f10a..c5fc730faa 100644 --- a/src/openrct2/drawing/ImageImporter.cpp +++ b/src/openrct2/drawing/ImageImporter.cpp @@ -10,374 +10,395 @@ #include "ImageImporter.h" #include "../core/Imaging.h" +#include "../core/Json.hpp" #include #include #include -using namespace OpenRCT2::Drawing; -using ImportResult = ImageImporter::ImportResult; - -constexpr int32_t PALETTE_TRANSPARENT = -1; - -ImportResult ImageImporter::Import( - const Image& image, int32_t offsetX, int32_t offsetY, Palette palette, ImportFlags flags, ImportMode mode) const +namespace OpenRCT2::Drawing { - return Import(image, 0, 0, image.Width, image.Height, offsetX, offsetY, palette, flags, mode); -} + constexpr int32_t PALETTE_TRANSPARENT = -1; -ImportResult ImageImporter::Import( - const Image& image, int32_t srcX, int32_t srcY, int32_t width, int32_t height, int32_t offsetX, int32_t offsetY, - Palette palette, ImportFlags flags, ImportMode mode) const -{ - if (width > 256 || height > 256) + ImageImporter::ImportResult ImageImporter::Import(const Image& image, ImageImportMeta& meta) const { - throw std::invalid_argument("Only images 256x256 or less are supported."); - } + if (meta.srcSize.width == 0) + meta.srcSize.width = image.Width; - if (palette == Palette::KeepIndices && image.Depth != 8) - { - throw std::invalid_argument("Image is not paletted, it has bit depth of " + std::to_string(image.Depth)); - } + if (meta.srcSize.height == 0) + meta.srcSize.height = image.Height; - auto pixels = GetPixels(image.Pixels.data(), image.Stride, srcX, srcY, width, height, palette, flags, mode); - auto buffer = flags & ImportFlags::RLE ? EncodeRLE(pixels.data(), width, height) : EncodeRaw(pixels.data(), width, height); - - G1Element outElement; - outElement.width = width; - outElement.height = height; - outElement.flags = (flags & ImportFlags::RLE ? G1_FLAG_RLE_COMPRESSION : G1_FLAG_HAS_TRANSPARENCY); - outElement.x_offset = offsetX; - outElement.y_offset = offsetY; - outElement.zoomed_offset = 0; - - ImportResult result; - result.Element = outElement; - result.Buffer = std::move(buffer); - result.Element.offset = result.Buffer.data(); - return result; -} - -std::vector ImageImporter::GetPixels( - const uint8_t* pixels, uint32_t pitch, uint32_t srcX, uint32_t srcY, uint32_t width, uint32_t height, Palette palette, - ImportFlags flags, ImportMode mode) -{ - std::vector buffer; - buffer.reserve(width * height); - - // A larger range is needed for proper dithering - auto palettedSrc = pixels; - std::unique_ptr rgbaSrcBuffer; - if (palette != Palette::KeepIndices) - { - rgbaSrcBuffer = std::make_unique(height * width * 4); - } - - auto rgbaSrc = rgbaSrcBuffer.get(); - if (palette != Palette::KeepIndices) - { - auto src = pixels + (srcY * pitch) + (srcX * 4); - auto dst = rgbaSrc; - for (uint32_t y = 0; y < height; y++) + if (meta.srcSize.width > 256 || meta.srcSize.height > 256) { - for (uint32_t x = 0; x < width * 4; x++) - { - *dst = static_cast(*src); - src++; - dst++; - } - src += (pitch - (width * 4)); + throw std::invalid_argument("Only images 256x256 or less are supported."); } + + if (meta.palette == Palette::KeepIndices && image.Depth != 8) + { + throw std::invalid_argument("Image is not paletted, it has bit depth of " + std::to_string(image.Depth)); + } + const bool isRLE = meta.importFlags & ImportFlags::RLE; + + auto pixels = GetPixels(image, meta); + auto buffer = isRLE ? EncodeRLE(pixels.data(), meta.srcSize) : EncodeRaw(pixels.data(), meta.srcSize); + + G1Element outElement; + outElement.width = meta.srcSize.width; + outElement.height = meta.srcSize.height; + outElement.flags = isRLE ? G1_FLAG_RLE_COMPRESSION : G1_FLAG_HAS_TRANSPARENCY; + outElement.x_offset = meta.offset.x; + outElement.y_offset = meta.offset.y; + outElement.zoomed_offset = meta.zoomedOffset; + + ImageImporter::ImportResult result; + result.Element = outElement; + result.Buffer = std::move(buffer); + result.Element.offset = result.Buffer.data(); + return result; } - if (palette == Palette::KeepIndices) + std::vector ImageImporter::GetPixels(const Image& image, const ImageImportMeta& meta) { - palettedSrc += srcX + srcY * pitch; - for (uint32_t y = 0; y < height; y++) + const uint8_t* pixels = image.Pixels.data(); + std::vector buffer; + buffer.reserve(meta.srcSize.width * meta.srcSize.height); + + // A larger range is needed for proper dithering + auto palettedSrc = pixels; + std::unique_ptr rgbaSrcBuffer; + if (meta.palette != Palette::KeepIndices) { - for (uint32_t x = 0; x < width; x++) + rgbaSrcBuffer = std::make_unique(meta.srcSize.height * meta.srcSize.width * 4); + } + + auto rgbaSrc = rgbaSrcBuffer.get(); + if (meta.palette != Palette::KeepIndices) + { + auto src = pixels + (meta.srcOffset.y * image.Stride) + (meta.srcOffset.x * 4); + auto dst = rgbaSrc; + for (auto y = 0; y < meta.srcSize.height; y++) { - int32_t paletteIndex = *palettedSrc; - // The 1st index is always transparent - if (paletteIndex == 0) + for (auto x = 0; x < meta.srcSize.width * 4; x++) { - paletteIndex = PALETTE_TRANSPARENT; + *dst = static_cast(*src); + src++; + dst++; } - palettedSrc += 1; - buffer.push_back(paletteIndex); - } - palettedSrc += (pitch - width); - } - } - else - { - for (uint32_t y = 0; y < height; y++) - { - for (uint32_t x = 0; x < width; x++) - { - auto paletteIndex = CalculatePaletteIndex(mode, rgbaSrc, x, y, width, height); - rgbaSrc += 4; - buffer.push_back(paletteIndex); + src += (image.Stride - (meta.srcSize.width * 4)); } } - } - return buffer; -} - -std::vector ImageImporter::EncodeRaw(const int32_t* pixels, uint32_t width, uint32_t height) -{ - auto bufferLength = width * height; - std::vector buffer(bufferLength); - for (size_t i = 0; i < bufferLength; i++) - { - auto p = pixels[i]; - buffer[i] = (p == PALETTE_TRANSPARENT ? 0 : static_cast(p)); - } - return buffer; -} - -std::vector ImageImporter::EncodeRLE(const int32_t* pixels, uint32_t width, uint32_t height) -{ - struct RLECode - { - uint8_t NumPixels{}; - uint8_t OffsetX{}; - }; - - auto src = pixels; - std::vector buffer((height * 2) + (width * height * 16)); - - std::fill_n(buffer.data(), (height * 2) + (width * height * 16), 0x00); - auto yOffsets = reinterpret_cast(buffer.data()); - auto dst = buffer.data() + (height * 2); - for (uint32_t y = 0; y < height; y++) - { - yOffsets[y] = static_cast(dst - buffer.data()); - - auto previousCode = static_cast(nullptr); - auto currentCode = reinterpret_cast(dst); - dst += 2; - - auto startX = 0; - auto npixels = 0; - bool pushRun = false; - for (uint32_t x = 0; x < width; x++) + if (meta.palette == Palette::KeepIndices) { - int32_t paletteIndex = *src++; - if (paletteIndex == PALETTE_TRANSPARENT) + palettedSrc += meta.srcOffset.x + meta.srcOffset.y * image.Stride; + for (auto y = 0; y < meta.srcSize.height; y++) { - if (npixels != 0) + for (auto x = 0; x < meta.srcSize.width; x++) { - x--; - src--; - pushRun = true; - } - } - else - { - if (npixels == 0) - { - startX = x; - } - - npixels++; - *dst++ = static_cast(paletteIndex); - } - if (npixels == 127 || x == width - 1) - { - pushRun = true; - } - - if (pushRun) - { - if (npixels > 0) - { - previousCode = currentCode; - currentCode->NumPixels = npixels; - currentCode->OffsetX = startX; - - if (x == width - 1) + int32_t paletteIndex = *palettedSrc; + // The 1st index is always transparent + if (paletteIndex == 0) { - currentCode->NumPixels |= 0x80; + paletteIndex = PALETTE_TRANSPARENT; } + palettedSrc += 1; + buffer.push_back(paletteIndex); + } + palettedSrc += (image.Stride - meta.srcSize.width); + } + } + else + { + for (auto y = 0; y < meta.srcSize.height; y++) + { + for (auto x = 0; x < meta.srcSize.width; x++) + { + auto paletteIndex = CalculatePaletteIndex( + meta.importMode, rgbaSrc, x, y, meta.srcSize.width, meta.srcSize.height); + rgbaSrc += 4; + buffer.push_back(paletteIndex); + } + } + } - currentCode = reinterpret_cast(dst); - dst += 2; + return buffer; + } + + std::vector ImageImporter::EncodeRaw(const int32_t* pixels, ScreenSize size) + { + auto bufferLength = size.width * size.height; + std::vector buffer(bufferLength); + for (auto i = 0; i < bufferLength; i++) + { + auto p = pixels[i]; + buffer[i] = (p == PALETTE_TRANSPARENT ? 0 : static_cast(p)); + } + return buffer; + } + + std::vector ImageImporter::EncodeRLE(const int32_t* pixels, ScreenSize size) + { + struct RLECode + { + uint8_t NumPixels{}; + uint8_t OffsetX{}; + }; + + auto src = pixels; + std::vector buffer((size.height * 2) + (size.width * size.height * 16)); + + std::fill_n(buffer.data(), (size.height * 2) + (size.width * size.height * 16), 0x00); + auto yOffsets = reinterpret_cast(buffer.data()); + auto dst = buffer.data() + (size.height * 2); + for (auto y = 0; y < size.height; y++) + { + yOffsets[y] = static_cast(dst - buffer.data()); + + auto previousCode = static_cast(nullptr); + auto currentCode = reinterpret_cast(dst); + dst += 2; + + auto startX = 0; + auto npixels = 0; + bool pushRun = false; + for (auto x = 0; x < size.width; x++) + { + int32_t paletteIndex = *src++; + if (paletteIndex == PALETTE_TRANSPARENT) + { + if (npixels != 0) + { + x--; + src--; + pushRun = true; + } } else { - if (previousCode == nullptr) + if (npixels == 0) { - currentCode->NumPixels = 0x80; - currentCode->OffsetX = 0; + startX = x; + } + + npixels++; + *dst++ = static_cast(paletteIndex); + } + if (npixels == 127 || x == size.width - 1) + { + pushRun = true; + } + + if (pushRun) + { + if (npixels > 0) + { + previousCode = currentCode; + currentCode->NumPixels = npixels; + currentCode->OffsetX = startX; + + if (x == size.width - 1) + { + currentCode->NumPixels |= 0x80; + } + + currentCode = reinterpret_cast(dst); + dst += 2; } else { - previousCode->NumPixels |= 0x80; - dst -= 2; + if (previousCode == nullptr) + { + currentCode->NumPixels = 0x80; + currentCode->OffsetX = 0; + } + else + { + previousCode->NumPixels |= 0x80; + dst -= 2; + } } - } - startX = 0; - npixels = 0; - pushRun = false; + startX = 0; + npixels = 0; + pushRun = false; + } } } + + auto bufferLength = static_cast(dst - buffer.data()); + buffer.resize(bufferLength); + return buffer; } - auto bufferLength = static_cast(dst - buffer.data()); - buffer.resize(bufferLength); - return buffer; -} - -int32_t ImageImporter::CalculatePaletteIndex( - ImportMode mode, int16_t* rgbaSrc, int32_t x, int32_t y, int32_t width, int32_t height) -{ - auto& palette = StandardPalette; - auto paletteIndex = GetPaletteIndex(palette, rgbaSrc); - if ((mode == ImportMode::Closest || mode == ImportMode::Dithering) && !IsInPalette(palette, rgbaSrc)) + int32_t ImageImporter::CalculatePaletteIndex( + ImportMode mode, int16_t* rgbaSrc, int32_t x, int32_t y, int32_t width, int32_t height) { - paletteIndex = GetClosestPaletteIndex(palette, rgbaSrc); - if (mode == ImportMode::Dithering) + auto& palette = StandardPalette; + auto paletteIndex = GetPaletteIndex(palette, rgbaSrc); + if ((mode == ImportMode::Closest || mode == ImportMode::Dithering) && !IsInPalette(palette, rgbaSrc)) { - auto dr = rgbaSrc[0] - static_cast(palette[paletteIndex].Red); - auto dg = rgbaSrc[1] - static_cast(palette[paletteIndex].Green); - auto db = rgbaSrc[2] - static_cast(palette[paletteIndex].Blue); - - // We don't want to dither remappable colours with nonremappable colours, etc - PaletteIndexType thisIndexType = GetPaletteIndexType(paletteIndex); - - if (x + 1 < width) + paletteIndex = GetClosestPaletteIndex(palette, rgbaSrc); + if (mode == ImportMode::Dithering) { - if (!IsInPalette(palette, rgbaSrc + 4) - && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4))) - { - // Right - rgbaSrc[4] += dr * 7 / 16; - rgbaSrc[5] += dg * 7 / 16; - rgbaSrc[6] += db * 7 / 16; - } - } + auto dr = rgbaSrc[0] - static_cast(palette[paletteIndex].Red); + auto dg = rgbaSrc[1] - static_cast(palette[paletteIndex].Green); + auto db = rgbaSrc[2] - static_cast(palette[paletteIndex].Blue); - if (y + 1 < height) - { - if (x > 0) - { - if (!IsInPalette(palette, rgbaSrc + 4 * (width - 1)) - && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * (width - 1)))) - { - // Bottom left - rgbaSrc[4 * (width - 1)] += dr * 3 / 16; - rgbaSrc[4 * (width - 1) + 1] += dg * 3 / 16; - rgbaSrc[4 * (width - 1) + 2] += db * 3 / 16; - } - } - - // Bottom - if (!IsInPalette(palette, rgbaSrc + 4 * width) - && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * width))) - { - rgbaSrc[4 * width] += dr * 5 / 16; - rgbaSrc[4 * width + 1] += dg * 5 / 16; - rgbaSrc[4 * width + 2] += db * 5 / 16; - } + // We don't want to dither remappable colours with nonremappable colours, etc + PaletteIndexType thisIndexType = GetPaletteIndexType(paletteIndex); if (x + 1 < width) { - if (!IsInPalette(palette, rgbaSrc + 4 * (width + 1)) - && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * (width + 1)))) + if (!IsInPalette(palette, rgbaSrc + 4) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4))) { - // Bottom right - rgbaSrc[4 * (width + 1)] += dr * 1 / 16; - rgbaSrc[4 * (width + 1) + 1] += dg * 1 / 16; - rgbaSrc[4 * (width + 1) + 2] += db * 1 / 16; + // Right + rgbaSrc[4] += dr * 7 / 16; + rgbaSrc[5] += dg * 7 / 16; + rgbaSrc[6] += db * 7 / 16; + } + } + + if (y + 1 < height) + { + if (x > 0) + { + if (!IsInPalette(palette, rgbaSrc + 4 * (width - 1)) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * (width - 1)))) + { + // Bottom left + rgbaSrc[4 * (width - 1)] += dr * 3 / 16; + rgbaSrc[4 * (width - 1) + 1] += dg * 3 / 16; + rgbaSrc[4 * (width - 1) + 2] += db * 3 / 16; + } + } + + // Bottom + if (!IsInPalette(palette, rgbaSrc + 4 * width) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * width))) + { + rgbaSrc[4 * width] += dr * 5 / 16; + rgbaSrc[4 * width + 1] += dg * 5 / 16; + rgbaSrc[4 * width + 2] += db * 5 / 16; + } + + if (x + 1 < width) + { + if (!IsInPalette(palette, rgbaSrc + 4 * (width + 1)) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * (width + 1)))) + { + // Bottom right + rgbaSrc[4 * (width + 1)] += dr * 1 / 16; + rgbaSrc[4 * (width + 1) + 1] += dg * 1 / 16; + rgbaSrc[4 * (width + 1) + 2] += db * 1 / 16; + } } } } } + + return paletteIndex; } - return paletteIndex; -} - -int32_t ImageImporter::GetPaletteIndex(const GamePalette& palette, int16_t* colour) -{ - if (!IsTransparentPixel(colour)) + int32_t ImageImporter::GetPaletteIndex(const GamePalette& palette, int16_t* colour) { - for (uint32_t i = 0; i < PALETTE_SIZE; i++) + if (!IsTransparentPixel(colour)) { - if (static_cast(palette[i].Red) == colour[0] && static_cast(palette[i].Green) == colour[1] - && static_cast(palette[i].Blue) == colour[2]) + for (uint32_t i = 0; i < PALETTE_SIZE; i++) { - return i; + if (static_cast(palette[i].Red) == colour[0] && static_cast(palette[i].Green) == colour[1] + && static_cast(palette[i].Blue) == colour[2]) + { + return i; + } } } + return PALETTE_TRANSPARENT; } - return PALETTE_TRANSPARENT; -} -bool ImageImporter::IsTransparentPixel(const int16_t* colour) -{ - return colour[3] < 128; -} - -/** - * @returns true if this colour is in the standard palette. - */ -bool ImageImporter::IsInPalette(const GamePalette& palette, int16_t* colour) -{ - return !(GetPaletteIndex(palette, colour) == PALETTE_TRANSPARENT && !IsTransparentPixel(colour)); -} - -/** - * @returns true if palette index is an index not used for a special purpose. - */ -bool ImageImporter::IsChangablePixel(int32_t paletteIndex) -{ - PaletteIndexType entryType = GetPaletteIndexType(paletteIndex); - return entryType != PaletteIndexType::Special && entryType != PaletteIndexType::PrimaryRemap; -} - -/** - * @returns the type of palette entry this is. - */ -ImageImporter::PaletteIndexType ImageImporter::GetPaletteIndexType(int32_t paletteIndex) -{ - if (paletteIndex <= 9) - return PaletteIndexType::Special; - if (paletteIndex >= 230 && paletteIndex <= 239) - return PaletteIndexType::Special; - if (paletteIndex == 255) - return PaletteIndexType::Special; - if (paletteIndex >= 243 && paletteIndex <= 254) - return PaletteIndexType::PrimaryRemap; - if (paletteIndex >= 202 && paletteIndex <= 213) - return PaletteIndexType::SecondaryRemap; - if (paletteIndex >= 46 && paletteIndex <= 57) - return PaletteIndexType::TertiaryRemap; - return PaletteIndexType::Normal; -} - -int32_t ImageImporter::GetClosestPaletteIndex(const GamePalette& palette, const int16_t* colour) -{ - auto smallestError = static_cast(-1); - auto bestMatch = PALETTE_TRANSPARENT; - for (uint32_t x = 0; x < PALETTE_SIZE; x++) + bool ImageImporter::IsTransparentPixel(const int16_t* colour) { - if (IsChangablePixel(x)) - { - uint32_t error = (static_cast(palette[x].Red) - colour[0]) - * (static_cast(palette[x].Red) - colour[0]) - + (static_cast(palette[x].Green) - colour[1]) * (static_cast(palette[x].Green) - colour[1]) - + (static_cast(palette[x].Blue) - colour[2]) * (static_cast(palette[x].Blue) - colour[2]); + return colour[3] < 128; + } - if (smallestError == static_cast(-1) || smallestError > error) + /** + * @returns true if this colour is in the standard palette. + */ + bool ImageImporter::IsInPalette(const GamePalette& palette, int16_t* colour) + { + return !(GetPaletteIndex(palette, colour) == PALETTE_TRANSPARENT && !IsTransparentPixel(colour)); + } + + /** + * @returns true if palette index is an index not used for a special purpose. + */ + bool ImageImporter::IsChangablePixel(int32_t paletteIndex) + { + PaletteIndexType entryType = GetPaletteIndexType(paletteIndex); + return entryType != PaletteIndexType::Special && entryType != PaletteIndexType::PrimaryRemap; + } + + /** + * @returns the type of palette entry this is. + */ + ImageImporter::PaletteIndexType ImageImporter::GetPaletteIndexType(int32_t paletteIndex) + { + if (paletteIndex <= 9) + return PaletteIndexType::Special; + if (paletteIndex >= 230 && paletteIndex <= 239) + return PaletteIndexType::Special; + if (paletteIndex == 255) + return PaletteIndexType::Special; + if (paletteIndex >= 243 && paletteIndex <= 254) + return PaletteIndexType::PrimaryRemap; + if (paletteIndex >= 202 && paletteIndex <= 213) + return PaletteIndexType::SecondaryRemap; + if (paletteIndex >= 46 && paletteIndex <= 57) + return PaletteIndexType::TertiaryRemap; + return PaletteIndexType::Normal; + } + + int32_t ImageImporter::GetClosestPaletteIndex(const GamePalette& palette, const int16_t* colour) + { + auto smallestError = static_cast(-1); + auto bestMatch = PALETTE_TRANSPARENT; + for (uint32_t x = 0; x < PALETTE_SIZE; x++) + { + if (IsChangablePixel(x)) { - bestMatch = x; - smallestError = error; + uint32_t error = (static_cast(palette[x].Red) - colour[0]) + * (static_cast(palette[x].Red) - colour[0]) + + (static_cast(palette[x].Green) - colour[1]) + * (static_cast(palette[x].Green) - colour[1]) + + (static_cast(palette[x].Blue) - colour[2]) * (static_cast(palette[x].Blue) - colour[2]); + + if (smallestError == static_cast(-1) || smallestError > error) + { + bestMatch = x; + smallestError = error; + } } } + return bestMatch; } - return bestMatch; -} + + ImageImportMeta createImageImportMetaFromJson(json_t& input) + { + auto xOffset = Json::GetNumber(input["x"]); + auto yOffset = Json::GetNumber(input["y"]); + auto keepPalette = Json::GetString(input["palette"]) == "keep"; + auto palette = keepPalette ? Palette::KeepIndices : Palette::OpenRCT2; + + auto raw = Json::GetString(input["format"]) == "raw"; + auto flags = raw ? ImportFlags::None : ImportFlags::RLE; + + auto srcX = Json::GetNumber(input["srcX"]); + auto srcY = Json::GetNumber(input["srcY"]); + auto srcWidth = Json::GetNumber(input["srcWidth"]); + auto srcHeight = Json::GetNumber(input["srcHeight"]); + auto zoomedOffset = Json::GetNumber(input["zoom"]); + + return ImageImportMeta{ { xOffset, yOffset }, palette, flags, ImportMode::Default, { srcX, srcY }, + { srcWidth, srcHeight }, zoomedOffset }; + }; +} // namespace OpenRCT2::Drawing diff --git a/src/openrct2/drawing/ImageImporter.h b/src/openrct2/drawing/ImageImporter.h index 8566c4e2a3..e9ec90feb7 100644 --- a/src/openrct2/drawing/ImageImporter.h +++ b/src/openrct2/drawing/ImageImporter.h @@ -10,6 +10,7 @@ #pragma once #include "../core/Imaging.h" +#include "../core/JsonFwd.hpp" #include "Drawing.h" #include @@ -19,6 +20,36 @@ struct Image; namespace OpenRCT2::Drawing { + enum class ImportMode : uint8_t + { + Default, + Closest, + Dithering, + }; + + enum ImportFlags : uint8_t + { + None = 0, + RLE = 1 << 1, + }; + + enum class Palette : uint8_t + { + OpenRCT2, + KeepIndices, + }; + + struct ImageImportMeta + { + ScreenCoordsXY offset{}; + Palette palette = Palette::OpenRCT2; + ImportFlags importFlags = ImportFlags::RLE; + ImportMode importMode = ImportMode::Default; + ScreenCoordsXY srcOffset{}; + ScreenSize srcSize{}; + int32_t zoomedOffset{}; + }; + /** * Imports images to the internal RCT G1 format. */ @@ -31,32 +62,7 @@ namespace OpenRCT2::Drawing std::vector Buffer; }; - enum class ImportMode : uint8_t - { - Default, - Closest, - Dithering, - }; - - enum ImportFlags : uint8_t - { - None = 0, - RLE = 1 << 1, - }; - - enum class Palette : uint8_t - { - OpenRCT2, - KeepIndices, - }; - - ImportResult Import( - const Image& image, int32_t srcX, int32_t srcY, int32_t width, int32_t height, int32_t offsetX, int32_t offsetY, - Palette palette = Palette::OpenRCT2, ImportFlags flags = ImportFlags::None, - ImportMode mode = ImportMode::Default) const; - ImportResult Import( - const Image& image, int32_t offsetX = 0, int32_t offsetY = 0, Palette palette = Palette::OpenRCT2, - ImportFlags flags = ImportFlags::None, ImportMode mode = ImportMode::Default) const; + ImportResult Import(const Image& image, ImageImportMeta& meta) const; private: enum class PaletteIndexType : uint8_t @@ -68,11 +74,9 @@ namespace OpenRCT2::Drawing Special, }; - static std::vector GetPixels( - const uint8_t* pixels, uint32_t pitch, uint32_t srcX, uint32_t srcY, uint32_t width, uint32_t height, - Palette palette, ImportFlags flags, ImportMode mode); - static std::vector EncodeRaw(const int32_t* pixels, uint32_t width, uint32_t height); - static std::vector EncodeRLE(const int32_t* pixels, uint32_t width, uint32_t height); + static std::vector GetPixels(const Image& image, const ImageImportMeta& meta); + static std::vector EncodeRaw(const int32_t* pixels, ScreenSize size); + static std::vector EncodeRLE(const int32_t* pixels, ScreenSize size); static int32_t CalculatePaletteIndex( ImportMode mode, int16_t* rgbaSrc, int32_t x, int32_t y, int32_t width, int32_t height); @@ -83,6 +87,9 @@ namespace OpenRCT2::Drawing static PaletteIndexType GetPaletteIndexType(int32_t paletteIndex); static int32_t GetClosestPaletteIndex(const GamePalette& palette, const int16_t* colour); }; + + // Note: jsonSprite is deliberately left non-const: json_t behaviour changes when const. + ImageImportMeta createImageImportMetaFromJson(json_t& input); } // namespace OpenRCT2::Drawing constexpr GamePalette StandardPalette = { { diff --git a/src/openrct2/object/ImageTable.cpp b/src/openrct2/object/ImageTable.cpp index dcd8d788c7..3ac0b90a8c 100644 --- a/src/openrct2/object/ImageTable.cpp +++ b/src/openrct2/object/ImageTable.cpp @@ -161,9 +161,10 @@ std::vector> ImageTable::ParseImages( { auto imageData = context->GetData(s); auto image = Imaging::ReadFromBuffer(imageData); + auto meta = ImageImportMeta{}; ImageImporter importer; - auto importResult = importer.Import(image, 0, 0, ImageImporter::Palette::OpenRCT2, ImageImporter::ImportFlags::RLE); + auto importResult = importer.Import(image, meta); result.push_back(std::make_unique(importResult.Element)); } @@ -183,30 +184,11 @@ std::vector> ImageTable::ParseImages( Guard::Assert(el.is_object(), "ImageTable::ParseImages expects parameter el to be object"); auto path = Json::GetString(el["path"]); - auto x = Json::GetNumber(el["x"]); - auto y = Json::GetNumber(el["y"]); - auto srcX = Json::GetNumber(el["srcX"]); - auto srcY = Json::GetNumber(el["srcY"]); - auto srcWidth = Json::GetNumber(el["srcWidth"]); - auto srcHeight = Json::GetNumber(el["srcHeight"]); - auto raw = Json::GetString(el["format"]) == "raw"; - auto keepPalette = Json::GetString(el["palette"]) == "keep"; - auto zoomOffset = Json::GetNumber(el["zoom"]); + auto meta = createImageImportMetaFromJson(el); std::vector> result; try { - auto flags = ImageImporter::ImportFlags::None; - auto palette = ImageImporter::Palette::OpenRCT2; - if (!raw) - { - flags = static_cast(flags | ImageImporter::ImportFlags::RLE); - } - if (keepPalette) - { - palette = ImageImporter::Palette::KeepIndices; - } - auto itSource = std::find_if( imageSources.begin(), imageSources.end(), [&path](const std::pair& item) { return item.first == path; }); @@ -216,16 +198,9 @@ std::vector> ImageTable::ParseImages( } auto& image = itSource->second; - if (srcWidth == 0) - srcWidth = image.Width; - - if (srcHeight == 0) - srcHeight = image.Height; - ImageImporter importer; - auto importResult = importer.Import(image, srcX, srcY, srcWidth, srcHeight, x, y, palette, flags); + auto importResult = importer.Import(image, meta); auto g1element = importResult.Element; - g1element.zoomed_offset = zoomOffset; result.push_back(std::make_unique(g1element)); } catch (const std::exception& e) diff --git a/test/tests/ImageImporterTests.cpp b/test/tests/ImageImporterTests.cpp index cfe50c4fa9..ec5d232f87 100644 --- a/test/tests/ImageImporterTests.cpp +++ b/test/tests/ImageImporterTests.cpp @@ -41,7 +41,8 @@ TEST_F(ImageImporterTests, Import_Logo) ImageImporter importer; auto image = Imaging::ReadFromFile(logoPath, IMAGE_FORMAT::PNG_32); - auto result = importer.Import(image, 3, 5, ImageImporter::Palette::OpenRCT2, ImageImporter::ImportFlags::RLE); + auto meta = ImageImportMeta{ .offset = { 3, 5 } }; + auto result = importer.Import(image, meta); ASSERT_EQ(result.Buffer.data(), result.Element.offset); ASSERT_EQ(128, result.Element.width);