commit 611036df632e8f435810f61d6426e7e96e9ab611 Author: fzorb Date: Tue Dec 17 11:31:30 2024 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..38ae6c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +input.* +venv/ \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..ff9e935 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3201f55 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# img2bop +`img2bop` is a Python script that converts any image to a .bopjson file, which can then be loaded into Bopimo. + +This is a glorified proof of concept and must be treated as such. There are better ways to insert images into your Bopimo level. If you wish to publish your level, please note that there is a hard limit of **2048 blocks** that can be created on the server. You must manually resize your input images. Eventually, this script will resize your images automatically to use the most blocks it can. + +**Demo level**: https://www.bopimo.com/levels/1597 + +## Usage: +``` +python3 img2bop.py +``` + +## Installation: +```sh +git clone https://git.fzorb.xyz/fzorb/img2bop +cd img2bop +python -m venv venv +# On *nix systems: +source ./venv/bin/activate +# On Windows: +./venv/Scripts/activate.ps1 +pip install -r requirements.txt +# You're now ready to rock! +``` + diff --git a/img2bop.py b/img2bop.py new file mode 100644 index 0000000..5921082 --- /dev/null +++ b/img2bop.py @@ -0,0 +1,50 @@ +import json +from PIL import Image +import sys + +def normalise(r, g, b): + return [r / 255.0, g / 255.0, b / 255.0, 0] + +if len(sys.argv) < 3: + print("You must specify an input and an output file in order to use this!\nExample: python3 img2bop.py input.jpeg output.bopijson") + exit() + +im = Image.open(sys.argv[1]).convert('RGB') + +bop = json.load(open("./sample.json")) + +w, h = im.size + +for x in range(w): + for y in range(h): + r, g, b = im.getpixel((x, y)) + colour = normalise(r, g, b) + newBlock = { + "__gdtype": "Dictionary", + "pairs": [ + { "key": { "__gdtype": "StringName", "name": "uid" }, "value": 420 + x * h + y }, + { "key": { "__gdtype": "StringName", "name": "block_id" }, "value": 0 }, + { "key": { "__gdtype": "StringName", "name": "block_name" }, "value": "Block" }, + { "key": { "__gdtype": "StringName", "name": "block_color" }, "value": { "__gdtype": "Color", "values": colour } }, + { "key": { "__gdtype": "StringName", "name": "block_position" }, "value": { "__gdtype": "Vector3", "values": [x, -y, 0.0] } }, + { "key": { "__gdtype": "StringName", "name": "block_rotation" }, "value": { "__gdtype": "Vector3", "values": [0.0, 0.0, 0.0] } }, + { "key": { "__gdtype": "StringName", "name": "block_scale" }, "value": { "__gdtype": "Vector3", "values": [1.0, 1.0, 1.0] } }, + { "key": { "__gdtype": "StringName", "name": "block_pattern" }, "value": 0 }, + { "key": { "__gdtype": "StringName", "name": "block_pattern_color" }, "value": { "__gdtype": "Color", "values": [0.0, 0.0, 0.0, 1.0] } }, + { "key": "position_enabled", "value": False }, + { "key": "position_points", "value": { "__gdtype": "PackedVector3Array", "values": [] } }, + { "key": "position_travel_speed", "value": 5.0 }, + { "key": "rotation_enabled", "value": False }, + { "key": "rotation_pivot_offset", "value": { "__gdtype": "Vector3", "values": [0.0, 0.0, 0.0] } }, + { "key": "rotation_direction", "value": { "__gdtype": "Vector3", "values": [0.0, 0.0, 0.0] } }, + { "key": "rotation_speed", "value": 1.0 }, + { "key": { "__gdtype": "StringName", "name": "transparency" }, "value": 7 }, + { "key": { "__gdtype": "StringName", "name": "collision_enabled" }, "value": True }, + { "key": { "__gdtype": "StringName", "name": "transparency_enabled" }, "value": False } + ] + } + + bop["level_blocks"].append(newBlock) + +with open(sys.argv[2], "w") as file: + json.dump(bop, file, indent=4) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b412802 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pillow==11.0.0 diff --git a/sample.json b/sample.json new file mode 100644 index 0000000..0d2764f --- /dev/null +++ b/sample.json @@ -0,0 +1,18 @@ +{ + "GAME_VERSION": "1.0.4", + "TIME_OF_SAVE": "2024-12-17 07:08:11", + "level_blocks": [], + "level_death_plane": -1000.0, + "level_description": "", + "level_fog_color": { "__gdtype": "Color", "values": [0.501960813999176, 0.501960813999176, 0.501960813999176, 1.0] }, + "level_fog_distance": 0.0, + "level_fog_enabled": false, + "level_gravity": 85.0, + "level_lives": 0, + "level_music": { "__gdtype": "PackedInt32Array", "values": [0, 1, 2] }, + "level_name": "gewghqewgqfgq", + "level_players_damage_players": true, + "level_sky": 0, + "level_sky_energy": 1.0, + "level_weather": 0 +}