import os #from PIL import Image, ImageDraw, ImageFont, ImageColor from expertmm import * from minetestinfo import * #paths and FLAG_EMPTY_HEXCOLOR = "#010000" try: from PIL import Image, ImageDraw, ImageFont, ImageColor except: print("You must first install Pillow's PIL." print("On Windows:") print("Right-click windows menu, 'Command Prompt (Admin)' then:") print("pip install Pillow") print("") print("On *nix-like systems:") print("sudo pip install Pillow") exit() import shutil u_skins_mod_path = os.path.join(profile_path,"Desktop\\Backup\\fcalocal\\usr\\local\\share\\minetest\\games\\fca_game_a\\mods\\u_skins\\u_skins") games_path = os.path.join(minetestinfo.get_var("shared_minetest_path"), "games") verbose_enable = True image_size = (64,32) preview_size = (16,32) visual_debug_enable = False dump_path = os.path.join(u_skins_mod_path, "debug") # only created or used if visual_debug_enable world_path = None world_name = None if minetestinfo.contains("primary_world_path"): world_path = minetestinfo.get_var("primary_world_path") world_name = os.path.basename(world_path) print("Using world '"+world_name+"'") #game_name = game_path_from_gameid_dict( gameid = None game_path = None mods_path = None if not os.path.isdir(u_skins_mod_path): if world_path is not None and os.path.isdir(world_path): gameid=get_world_var("gameid") print("Using game '"+str(gameid)+"'") if gameid is not None and games_path is not None: game_path = os.path.join(games_path, gameid) mods_path=os.path.join(game_path, "mods") print("Using mods_path '"+mods_path+"'") print("Looking for u_skins mod in u_skins modpack...") #u_skins_mod_path = os.path.join( os.path.join( os.path.join(game_path, "mods"), "u_skins" ), "u_skins" ) # get the u_skins mod in the u_skins modpack #print(" trying '"+u_skins_mod_path+"'") u_skins_modpack_path = os.path.join(mods_path, "u_skins") u_skins_mod_path = os.path.join(u_skins_modpack_path, "u_skins") else: print("Unknown world, so can't detect game.") meta_path = os.path.join(u_skins_mod_path,"meta") textures_path = os.path.join(u_skins_mod_path,"textures") image_prefix = "character_" preview_suffix = "_preview" default_license_string = "CC BY-SA 3.0" png_count = 0 class RectTransferInfo: source_rect_tuple = None dest_rect_tuple = None flip_h = None def __init__(self, source_rect_tuple, dest_rect_tuple, flip_h): self.flip_h = flip_h self.source_rect_tuple = source_rect_tuple self.dest_rect_tuple = dest_rect_tuple rect_trans_list = list() rect_trans_list.append(RectTransferInfo((8,8,8,8),(4,0,8,8),False)) # face rect_trans_list.append(RectTransferInfo((20,20,8,12),(4,8,8,12),False)) # shirt #rect_trans_list.append(RectTransferInfo((44,28,4,4),(0,16,4,4),False)) # hand.r #rect_trans_list.append(RectTransferInfo((44,28,4,4),(12,16,4,4),True)) # hand.l (True since must be flipped manually) rect_trans_list.append(RectTransferInfo((44,20,4,12),(0,8,4,12),False)) # arm.r rect_trans_list.append(RectTransferInfo((44,20,4,12),(12,8,4,12),True)) # arm.l (True since on hands, left one must be flipped manually) rect_trans_list.append(RectTransferInfo((4,20,4,12),(8,20,4,12),False)) # leg.l rect_trans_list.append(RectTransferInfo((4,20,4,12),(4,20,4,12),True)) # leg.r (True since on legs, right one must be flipped manually) #yes, the flipping is different for leg vs arm class USkinInfo: author_string = None name_string = None license_name_string = None #region temp source_image_path = None #endregion temp def __init__(self): pass def set_from_skindb_skin_file_path(self, file_path, license_name_string): self.author_string = None self.name_string = None self.license_name_string=license_name_string self.source_image_path = file_path file_name = os.path.basename(self.source_image_path) noext_name = file_name dot_index = file_name.rfind(".") if dot_index>=0: noext_name = file_name[:dot_index] by_string = "_by_" by_index = noext_name.rfind(by_string) #print("noext_name:"+noext_name) if by_index>=0: self.author_string = noext_name[by_index+len(by_string):] self.name_string = noext_name[:by_index] else: self.author_string = "" self.name_string = noext_name def set_from_metadata_path(self, metadata_file_path): is_ok = False self.name_string = None self.author_string = None self.license_name_string = None if os.path.isfile(metadata_file_path): ins = open(metadata_file_path, 'r') line = True counting_number = 1 while line: participle = "reading line "+str(counting_number) line = ins.readline() if line: line_strip = line.strip() if len(line_strip)>0: if self.name_string is None: self.name_string = line_strip elif self.author_string is None: self.author_string = line_strip is_ok = True elif self.license_name_string is None: self.license_name_string = line_strip counting_number += 1 ins.close() if not is_ok: raw_input("ERROR: Did not find line 2 for name_string in '"+metadata_file_path+"'") else: raw_input("Missing '"+metadata_file_path+"' -- press enter to continue...") return is_ok def print_dump(self, min_indent): print(min_indent+"name_string:"+self.name_string) print(min_indent+"author_string:"+self.author_string) print(min_indent+"license_name_string:"+self.license_name_string) def _save_metadata(self, metadata_file_path): outs = open(metadata_file_path, 'w') outs.write(self.name_string+"\n") outs.write(self.author_string+"\n") outs.write(self.license_name_string+"\n") outs.close() def push_next_skin_file_if_self_is_new(self): result = False os.listdir(textures_path) this_index = 1 while os.path.isfile( get_png_path_from_index(this_index) ): this_index += 1 if not skin_exists(self.name_string, self.author_string): #image_name = get_png_name_from_index(this_index) image_path = get_png_path_from_index(this_index) metadata_name = get_metadata_name_from_index(this_index) metadata_path = os.path.join(meta_path, metadata_name) #preview_name = get_preview_name_from_index(this_index) preview_path = get_preview_path_from_index(this_index) print("saving to image_path:"+image_path) print("saving to metadata_path:"+metadata_path) self._save_metadata(metadata_path) #actually save the skin and metadata files: print("saving to preview_path:"+preview_path) self.print_dump(" ") shutil.copy(self.source_image_path, image_path) result = True preview_im = Image.new("RGBA", preview_size, "#000000") fill_image_with_transparency(preview_im) skin_im = Image.open(open(self.source_image_path, 'rb')) # double-open to make sure file is finished writing #NOTE: PIL automatically closes, otherwise you can do something like https://bytes.com/topic/python/answers/24308-pil-do-i-need-close #fp = open(file_name, "rb") #im = Image.open(fp) # open from file object #im.load() # make sure PIL has read the data #fp.close() for rect_trans in rect_trans_list: source_left, source_top, source_right, source_bottom = rect_trans.source_rect_tuple source_right+=source_left source_bottom+=source_top pil_source_rect_tuple = source_left, source_top, source_right, source_bottom partial_im = skin_im.crop(pil_source_rect_tuple) dest_left, dest_top, dest_right, dest_bottom = rect_trans.dest_rect_tuple dest_right+=dest_left dest_bottom+=dest_top pil_dest_rect_tuple = dest_left, dest_top, dest_right, dest_bottom preview_im.paste(partial_im, (dest_left, dest_top)) debug_img_name="debug "+str(pil_source_rect_tuple)+".png" if visual_debug_enable: #if visual_debug_enable: #raw_input("Press enter to save temp cropping images to '"+dump_path+"'") if not os.path.isdir(dump_path): os.makedirs(dump_path) debug_img_path = os.path.join(dump_path, debug_img_name) #if not os.path.isfile(debug_img_path): print(" saving "+debug_img_path) print(" (after pasting to destination rect "+str(pil_dest_rect_tuple)+")") partial_im.save(debug_img_path) preview_im.save(preview_path) print("Saved preview to '"+preview_path+"'") print("") else: print("Skin already exists: "+self.name_string+" by "+self.author_string) def get_png_path_from_index(this_index): return os.path.join(textures_path, get_png_name_from_index(this_index)) def get_png_name_from_index(this_index): return image_prefix+str(this_index)+".png" def get_preview_path_from_index(this_index): return os.path.join(textures_path, get_preview_name_from_index(this_index)) def get_preview_name_from_index(this_index): return image_prefix+str(this_index)+preview_suffix+".png" def get_metadata_name_from_index(this_index): return image_prefix+str(this_index)+".txt" def get_metadata_path_from_index(this_index): return os.path.join(meta_path, get_metadata_name_from_index(this_index)) print("Loading existing skin metadata to avoid duplication (but ignoring metadata files that do not have pngs)") si_list = list() this_index = 1 while os.path.isfile( get_png_path_from_index(this_index) ): existing_metadata_path = get_metadata_path_from_index(this_index) this_si = USkinInfo() is_ok=this_si.set_from_metadata_path(get_metadata_path_from_index(this_index)) if is_ok: #if not skin_exists(this_si.name_string, this_si.author_string): si_list.append(this_si) #if verbose_enable: # print("Added skin metadata:") # this_si.print_dump(" ") this_index += 1 print(" Found metadata for "+str(len(si_list))+" png file(s).") print(" The functions in "+__file__+" are now ready.") print(" * These functions mark destination as '"+default_license_string+"' license unless you") print(" first change the global default_license_string variable") print(" in your program that has:") print(" from u_skin_adder import *") print(" * Skin filename should include _by_ (with underscores) to specify author.") print(" * Examples:") print(" load_new_skins_from_folder(folder_path)") print(" add_skin_if_new(file_path)") def fill_image_with_transparency(im): #modified version of: unutbu. "Python PIL: how to make area transparent in PNG? (answer 7 Dec 2010 at 19:08)" . 7 Dec 2010. 8 Apr 2016. #who cited http://stackoverflow.com/questions/890051/how-do-i-generate-circular-thumbnails-with-pil #import Image #import ImageDraw #im = Image.open("image.png") #transparent_area = (50,80,100,200) transparent_area = (0,0,im.size[0],im.size[1]) mask=Image.new('L', im.size, color=255) draw=ImageDraw.Draw(mask) draw.rectangle(transparent_area, fill=0) im.putalpha(mask) #im.save('/tmp/output.png') show_no_dest_warnings = True def skin_exists(name_string, author_string): global show_no_dest_warnings #global si_list result = False count = 0 #if verbose_enable: # print(" Checking for existing "+name_string+" by "+author_string+":") for si in si_list: if si.name_string==name_string and si.author_string==author_string: result = True break #else: # if verbose_enable: # print(" "+si.name_string+" by "+si.author_string+" is not it.") count += 1 if not result: if count<1: #if show_no_dest_warnings: raw_input("WARNING: 0 skins during skin_exists check. Press enter to continue...") #show_no_dest_warnings = False return result #if os.path.isdir(meta_path): # #accepts CC BY 3.0 skins, and looks for _by_ in name, followed by author (otherwise puts on author line of metadata txt file in u_skin/meta folder) def add_skin_if_new(sub_path): this_usi = USkinInfo() this_usi.set_from_skindb_skin_file_path(sub_path, default_license_string) return this_usi.push_next_skin_file_if_self_is_new() def load_new_skins_from_folder(in_path): #in_path = os.path.join(profile_path,"Downloads\\skins-to-add") #if not os.path.isdir(in_path): # in_path = "." # print("Looking for new textures in current directory") if not skin_exists("Sam 0","Jordach"): print("") print("WARNING: Missing 'Sam 0' by 'Jordach'") print(" among "+str(len(si_list))+" skin(s).") print(" Only continue if you expected that skin to not be there.") raw_input(" Press enter to continue...") if os.path.isdir(meta_path): if os.path.isdir(textures_path): if os.path.isdir(in_path): folder_path = in_path new_count = 0 found_count = 0 old_count = 0 for sub_name in os.listdir(folder_path): sub_path = os.path.join(folder_path,sub_name) if os.path.isfile(sub_path): if (sub_name[:1]!="."): if len(sub_name)>4 and sub_name[-4:]==".png": found_count += 1 if add_skin_if_new(sub_path): new_count += 1 else: old_count += 1 print("Added "+str(new_count)+" new skins(s) among "+str(found_count)+" discovered in specified source folder.") if old_count>0: print(" "+str(old_count)+" (with matching author and title) were already in destination.") else: print("ERROR: Failed to get new texture files since in_path does not exist:'"+in_path+"'") else: print("ERROR: missing textures_path (tried '"+textures_path+"')") else: print("ERROR: missing meta_path (tried '"+meta_path+"')") #raw_input("Press return to exit.") #load_new_skins_from_folder("C:\\Users\\Owner\\ownCloud\\Pictures\\Projects\\Characters - Mine - In-Game\\Minetest Player Skins") #add_skin_if_new("z:\\yelby.png")