|
#!/usr/bin/env python |
|
|
|
# GIMP Python plug-in to build edit and export CBD board printers UIs |
|
# for printers like Anycubic Photon, Epax, Orbeat... |
|
# Copyright 2019 X3msnake |
|
# |
|
# -------------------------------------------------------------------- |
|
# This program is free software: you can redistribute it and/or modify |
|
# it under the terms of the GNU General Public License as published by |
|
# the Free Software Foundation; either version 3 of the License, or |
|
# (at your option) any later version. |
|
# |
|
# This program is distributed in the hope that it will be useful, |
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
# GNU General Public License for more details. |
|
# |
|
# You should have received a copy of the GNU General Public License |
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
|
|
# If you want the plugin to be nested inside a folder on the gimp plugins folder, the nested folder name must be the same as the python file |
|
import csv |
|
import logging |
|
import sys |
|
from gimpfu import * |
|
|
|
|
|
def ph_ui_builder(ph_dir, ph_csv, ph_ui_name): |
|
|
|
pdb.gimp_message_set_handler(2) #Send messages to gimp debug window |
|
pdb.gimp_message("DIR:"+ ph_dir +"\n"+ "CSV: "+ ph_csv ) |
|
|
|
|
|
try: |
|
# Import CSV and pass the variable set by user on the UI |
|
ph_load_csv(ph_dir, ph_csv,ph_ui_name) |
|
|
|
except Exception as e: |
|
# catch python errors and show them as popups to the user |
|
e_msg(e) |
|
|
|
return |
|
|
|
def ph_load_csv(ph_directory, ph_csv_table, ph_project_name): |
|
|
|
# Debug check if the passed variable is a string |
|
pdb.gimp_message(type(ph_csv_table)) |
|
|
|
# CSV columns should be like this |
|
#[0]'Image UID', [1]'Offset', [2]'Xpos', [3]'Ypos', [4]'Xwidth', [5]'Yheight', [6]'Reserved'] |
|
with open(ph_csv_table) as csv_file: |
|
csv_reader = csv.reader(csv_file, delimiter=',') |
|
line_count = 0 |
|
debug_table = "" |
|
|
|
for row in csv_reader: |
|
|
|
# Ignore first line since this is the header |
|
if line_count == 0: |
|
pdb.gimp_message(row) |
|
line_count += 1 |
|
|
|
else: |
|
UID = int(row[0] ,0) |
|
Offset = int(row[1] ,0) |
|
Xpos = int(row[2] ,0) |
|
Ypos = int(row[3] ,0) |
|
Xwidth = int(row[4] ,0) |
|
Yheight = int(row[5] ,0) |
|
Reserved = int(row[6] ,0) |
|
|
|
|
|
# Extract the UI base size from the first image [ 2.8"(320x240) | 3.5"(480x320) | 5.0"(480x272) ] |
|
if UID == 1 and line_count < 3: |
|
debug_ui_size = str(Xwidth)+"x"+str(Yheight) |
|
ph_build_basefile(ph_project_name, Xwidth, Yheight) |
|
pdb.gimp_message(type(ph_new_image)) |
|
|
|
#Define layer groups |
|
ph_layers_main = [["ui_print", "PRINT"], ["ui_system", "SYSTEM"], ["ui_tool","TOOLS"]] |
|
ph_layers_ui_print = [["ui_fileinfo", "FileInfo"], ["ui_printing", "Printing..."], ["ui_printingcfg", "PrintConfig"], ["ui_numpadkeys", "Numpad"]] |
|
ph_layers_ui_system = [["ui_sysinfo", "SystemInfo"], ["ui_network","Network"], ["ui_service", "Support"]] |
|
ph_layers_ui_tool =[["ui_move", "ManualMove"], ["ui_calibrate", "Calibrate"], ["ui_test","Test"]] |
|
|
|
pdb.gimp_message(ph_layers_main[0]) |
|
pdb.gimp_message(ph_layers_main[0][1]) |
|
|
|
#Create Layer Group and add layer to image |
|
ui_main_menu = pdb.gimp_layer_group_new(ph_new_image) |
|
pdb.gimp_image_insert_layer(ph_new_image, ui_main_menu, None , -1) |
|
ui_main_menu.name = "MAIN-MENU" |
|
|
|
#Create Main Layers |
|
ph_layers_main[0][0] = pdb.gimp_layer_group_new(ph_new_image) |
|
pdb.gimp_image_insert_layer(ph_new_image, ph_layers_main[0][0], ui_main_menu , 1) |
|
ph_layers_main[0][0].name = ph_layers_main[0][1] |
|
|
|
ph_layers_main[1][0] = pdb.gimp_layer_group_new(ph_new_image) |
|
pdb.gimp_image_insert_layer(ph_new_image, ph_layers_main[1][0], ui_main_menu , 1) |
|
ph_layers_main[1][0].name = ph_layers_main[1][1] |
|
|
|
ph_layers_main[2][0] = pdb.gimp_layer_group_new(ph_new_image) |
|
pdb.gimp_image_insert_layer(ph_new_image, ph_layers_main[2][0], ui_main_menu , 1) |
|
ph_layers_main[2][0].name = ph_layers_main[2][1] |
|
|
|
|
|
if UID != 0 : |
|
|
|
# Concatenate a debug_table |
|
debug_table = debug_table+"UID:" +str(UID)+ "| Off7:" +str(Offset) |
|
debug_table = debug_table+"| Xpos:" +str(Xpos)+ "| Ypos:" +str(Ypos) |
|
debug_table = debug_table+"| Xwidth:" +str(Xwidth)+ "| Yheight:" +str(Yheight) |
|
debug_table = debug_table+"| Res:" +str(Reserved)+ "\n" |
|
|
|
# Define target Layer |
|
|
|
target_layer = None |
|
|
|
if (UID == 1) or (UID == 151): |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "MAIN-MENU") |
|
|
|
if (UID == 5) or (UID == 155): |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "PRINT") |
|
if UID == 154 or UID == 4: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "FileInfo") |
|
if UID == 163 or UID == 13: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "Printing...") |
|
if UID == 162 or UID == 12: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "PrintConfig") |
|
if UID == 161 or UID == 11: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "Numpad") |
|
|
|
if UID == 2 or UID == 152: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "SYSTEM") |
|
if UID == 157 or UID == 7: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "SystemInfo") |
|
if UID == 215 or UID == 214: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "Network") |
|
if UID == 290 or UID == 289: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "Support") |
|
|
|
if UID == 3 or UID == 153: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "TOOLS") |
|
if UID == 156 or UID == 6: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "ManualMove") |
|
if UID == 352: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "Calibrate") |
|
if UID == 355: |
|
target_layer = pdb.gimp_image_get_layer_by_name(ph_new_image, "Test") |
|
|
|
|
|
# Load File as Layer and insert it into a open image |
|
UID = pdb.gimp_file_load_layer(ph_new_image, ph_directory+"\\"+str(UID)+".bmp") |
|
pdb.gimp_image_insert_layer(ph_new_image, UID, target_layer , 0) |
|
|
|
# Get layer current position and move it to a new place starting from 0,0 |
|
x_off, y_off = UID.offsets |
|
pdb.gimp_layer_translate(UID, Xpos - x_off, Ypos - y_off) |
|
|
|
line_count += 1 |
|
|
|
#Print debug_table and other infos on console |
|
pdb.gimp_message(debug_table) |
|
pdb.gimp_message({line_count}) |
|
pdb.gimp_message(type(UID)) |
|
pdb.gimp_message(debug_ui_size) |
|
|
|
# Render image on screen > depends on sucess of ph_buil_basefile() |
|
display = pdb.gimp_display_new(ph_new_image) |
|
|
|
|
|
return |
|
|
|
# Function creates a new base file to hold the layers based on user input |
|
def ph_build_basefile(ph_basefile_name, ph_basefile_width, ph_basefile_height, ph_image_depth = 0): |
|
|
|
# Debug basefile pass |
|
pdb.gimp_message("Building " + ph_basefile_name + " basefile...") |
|
|
|
# Set image holder variable as global so we can access it from outside this function |
|
global ph_new_image |
|
# Create a new image based on the first value of the user passed table |
|
ph_new_image = pdb.gimp_image_new(ph_basefile_width, ph_basefile_height, ph_image_depth) |
|
# Set name of the new file from user input form |
|
pdb.gimp_image_set_filename(ph_new_image, ph_basefile_name) |
|
|
|
|
|
# Error message function, sets errors as popups and prints a passed message |
|
def e_msg(ph_message): |
|
pdb.gimp_message_set_handler(0) |
|
pdb.gimp_message(ph_message) |
|
|
|
|
|
register( |
|
"python_fu_photon_ui_builder", |
|
"Photon ui builder", |
|
"rebuilds CBD board ui from sprites and csv table", |
|
"X3msnake", |
|
"Photonsters", |
|
"2010", |
|
"Photon Ui Builder...", |
|
"", # Alternately use RGB, RGB*, GRAY*, INDEXED etc. |
|
[ |
|
(PF_DIRNAME, "ph_dir", "IMAGE FOLDER", "/tmp"), |
|
(PF_FILE, "ph_csv", "CSV FILE", "nofile"), |
|
(PF_STRING, "ph_ui_name", "UI new name", "Untitled"), |
|
#(PF_INT, "number", "Number?", 50), |
|
#(PF_FLOAT, "angle", "Angle", 3.14159), |
|
# you can also use PF_INT8, PF_INT16, PF_INT32 |
|
#(PF_STRING, "word", "Word", "Zebrafish!"), |
|
# PF_VALUE is another term for PF_STRING |
|
#(PF_TEXT, "text", "Some Text", |
|
# "The quick red fox jumped over the lazy dog"), |
|
|
|
#(PF_COLOR, "bg-color", "Background", (1.0, 1.0, 1.0)), |
|
# or you can spell it PF_COLOUR |
|
|
|
#(PF_IMAGE, "image", "Input image", None), |
|
#(PF_LAYER, "layer", "Input layer", None), |
|
#(PF_CHANNEL, "channel", "Which channel", None), |
|
#(PF_DRAWABLE, "drawable", "Input drawable", None), |
|
|
|
#(PF_TOGGLE, "shadow", "Shadow?", 1), |
|
#(PF_BOOL, "ascending", "_Ascending", True), |
|
#(PF_RADIO, "imagefmt", "Image format", "jpg", |
|
# (("png", "png"), ("jpg", "jpg"))), |
|
#(PF_OPTION, "option", "Option", 2, ("Mouse", "Cat", "Dog", "Horse")), |
|
|
|
#(PF_SPINNER, "size", "Pixel Size", 50, (1, 8000, 1)), |
|
#(PF_SLIDER, "opacity", "Op_acity", 100, (0, 100, 1)), |
|
#(PF_ADJUSTMENT is the same as PF_SPINNER |
|
|
|
|
|
#(PF_FONT, "font", "Font", "Sans"), |
|
#(PF_BRUSH, "brush", "Brush", None), |
|
#(PF_PATTERN, "pattern", "Pattern", None), |
|
#(PF_GRADIENT, "gradient", "Gradient", None), |
|
#(PF_PALETTE, "palette", "Palette", ""), |
|
|
|
# New items that don't quite work yet: |
|
#(PF_VECTORS, "vectors", "Vectors", None), |
|
#(PF_DISPLAY, "display", "Display", None), |
|
], |
|
[], |
|
ph_ui_builder, menu="<Image>/PhotonTools" ) |
|
|
|
main() |
Examples
https://gimpbook.com/scripting/
Basics
https://www.neuraldump.net/2017/01/program-python-plug-ins-for-gimp-hello-gimp-world/
Debugging
https://stackoverflow.com/questions/20763448/writing-gimp-plugins-in-python-on-windows-how-do-i-debug-where-is-the-output
Video Tutorials on scripting with pythong for Gimp
https://www.youtube.com/watch?v=cPQRxZo9BJE&list=PLyRItRv4aHfOuUC8a1SMeTLV08wxdnWt-
Web tutorials
https://www.tablix.org/~avian/blog/articles/talks/extending_gimp_python.pdf (Plugin Basics)
https://www.gimp.org/docs/python/index.html (python on gimp)
https://realpython.com/python-csv/ (parsing csv with python)
https://realpython.com/iterate-through-dictionary-python/ (iterate dictionaries)
https://www.geeksforgeeks.org/python-check-values-list-greater-given-value/ (Comparing sigle values to a array - Transversing a list)
https://stackoverflow.com/questions/10221926/get-sublayers-from-group-layer-with-python-in-gimp/10314140 (Manipulate Layers)
https://gitlab.gnome.org/GNOME/gimp/issues/1119 (some scripts about layers)
https://stackoverflow.com/questions/3620943/measuring-elapsed-time-with-the-time-module/47637891#47637891
Important Tips
dir() shows a list of all the available constants, classes and instances
dir(pdb.something).... shows the list of properties of a given class
dir(pdb.something.something) list properties of properties...
Potential Usefull Plugins
https://github.com/crapola/PixInflate (inflate pixels cradinally - maybe usable for erode?)
https://github.com/avian2/gimp-plugin-onion-layers (Onion Skin Layers - Maybe usefull if we implement a Photon2xfc plugin)