def writeBezelConfig(bezel, systemName, rom): romBase = os.path.splitext( os.path.basename(rom))[0] # filename without extension tmpZipDir = "/var/run/mame_artwork/" + romBase # ok, no need to zip, a folder is taken too # clean, in case no bezel is set, and in case we want to recreate it if os.path.exists(tmpZipDir): shutil.rmtree(tmpZipDir) if bezel is None: return # let's generate the zip file os.makedirs(tmpZipDir) # bezels infos bz_infos = bezelsUtil.getBezelInfos(rom, bezel, systemName) if bz_infos is None: return # copy the png inside os.symlink(bz_infos["png"], tmpZipDir + "/default.png") img_width, img_height = bezelsUtil.fast_image_size(bz_infos["png"]) game_width, game_height = MameGenerator.getMameMachineSize( romBase, tmpZipDir) bz_width = (game_width * img_height) / game_height bz_height = img_height bz_x = int((img_width - bz_width) / 2) bz_y = 0 f = open(tmpZipDir + "/default.lay", 'w') f.write("<mamelayout version=\"2\">") f.write( "<element name=\"bezel\"><image file=\"default.png\" /></element>") f.write("<view name=\"bezel\">") f.write("<screen index=\"0\"><bounds x=\"" + str(bz_x) + "\" y=\"" + str(bz_y) + "\" width=\"" + str(bz_width) + "\" height=\"" + str(bz_height) + "\" /></screen>") f.write("<bezel element=\"bezel\"><bounds x=\"0\" y=\"0\" width=\"" + str(img_width) + "\" height=\"" + str(img_height) + "\" /></bezel>") f.write("</view>") f.write("</mamelayout>") f.close()
def getHudBezel(system, rom, gameResolution): if 'bezel' not in system.config or system.config['bezel'] == "" or system.config['bezel'] == "none": return None eslog.debug("hud enabled. trying to apply the bezel {}".format(system.config['bezel'])) if generators[system.config['emulator']].supportsInternalBezels(): eslog.debug("skipping bezels for emulator {}".format(system.config['emulator'])) return None bezel = system.config['bezel'] bz_infos = bezelsUtil.getBezelInfos(rom, bezel, system.name) if bz_infos is None: eslog.debug("no bezel info file found") return None overlay_info_file = bz_infos["info"] overlay_png_file = bz_infos["png"] # check the info file # bottom, top, left and right must not cover too much the image to be considered as compatible if os.path.exists(overlay_info_file): try: infos = json.load(open(overlay_info_file)) except: eslog.warning("unable to read {}".format(overlay_info_file)) infos = {} else: infos = {} if "width" in infos and "height" in infos: bezel_width = infos["width"] bezel_height = infos["height"] eslog.info("bezel size read from {}".format(overlay_info_file)) else: bezel_width, bezel_height = bezelsUtil.fast_image_size(overlay_png_file) eslog.info("bezel size read from {}".format(overlay_png_file)) # max cover proportion and ratio distortion max_cover = 0.05 # 5% max_ratio_delta = 0.01 screen_ratio = gameResolution["width"] / gameResolution["height"] bezel_ratio = bezel_width / bezel_height # the screen and bezel ratio must be approximatly the same if abs(screen_ratio - bezel_ratio) > max_ratio_delta: eslog.debug("screen ratio ({}) is too far from the bezel one ({}) : {} - {} > {}".format(screen_ratio, bezel_ratio, screen_ratio, bezel_ratio, max_ratio_delta)) return None # the ingame image and the bezel free space must feet ## the bezel top and bottom cover must be minimum if "top" in infos and infos["top"] / bezel_height > max_cover: eslog.debug("bezel top covers too much the game image : {} / {} > {}".format(infos["top"], bezel_height, max_cover)) return None if "bottom" in infos and infos["bottom"] / bezel_height > max_cover: eslog.debug("bezel bottom covers too much the game image : {} / {} > {}".format(infos["bottom"], bezel_height, max_cover)) return None # if there is no information about top/bottom, assume default is 0 ## the bezel left and right cover must be maximum ingame_ratio = generators[system.config['emulator']].getInGameRatio(system.config, gameResolution) img_height = bezel_height img_width = img_height * ingame_ratio if "left" not in infos: eslog.debug("bezel has no left info in {}".format(overlay_info_file)) # assume default is 4/3 over 16/9 infos_left = (bezel_width - (bezel_height / 3 * 4)) / 2 if abs((infos_left - ((bezel_width-img_width)/2.0)) / img_width) > max_cover: eslog.debug("bezel left covers too much the game image : {} / {} > {}".format(infos_left - ((bezel_width-img_width)/2.0), img_width, max_cover)) return None if "right" not in infos: eslog.debug("bezel has no right info in {}".format(overlay_info_file)) # assume default is 4/3 over 16/9 infos_right = (bezel_width - (bezel_height / 3 * 4)) / 2 if abs((infos_right - ((bezel_width-img_width)/2.0)) / img_width) > max_cover: eslog.debug("bezel right covers too much the game image : {} / {} > {}".format(infos_right - ((bezel_width-img_width)/2.0), img_width, max_cover)) return None if "left" in infos and abs((infos["left"] - ((bezel_width-img_width)/2.0)) / img_width) > max_cover: eslog.debug("bezel left covers too much the game image : {} / {} > {}".format(infos["left"] - ((bezel_width-img_width)/2.0), img_width, max_cover)) return None if "right" in infos and abs((infos["right"] - ((bezel_width-img_width)/2.0)) / img_width) > max_cover: eslog.debug("bezel right covers too much the game image : {} / {} > {}".format(infos["right"] - ((bezel_width-img_width)/2.0), img_width, max_cover)) return None # if screen and bezel sizes doesn't match, resize if (bezel_width != gameResolution["width"] or bezel_height != gameResolution["height"]): eslog.debug("bezel needs to be resized") output_png_file = "/tmp/bezel.png" try: bezelsUtil.resizeImage(overlay_png_file, output_png_file, gameResolution["width"], gameResolution["height"]) except Exception as e: eslog.error("failed to resize the image {}".format(e)) return None overlay_png_file = output_png_file if system.isOptSet('bezel.tattoo') and system.config['bezel.tattoo'] != "0": output_png_file = "/tmp/bezel_tattooed.png" bezelsUtil.tatooImage(overlay_png_file, output_png_file, system) overlay_png_file = output_png_file eslog.debug("applying bezel {}".format(overlay_png_file)) return overlay_png_file
def writeBezelConfig(bezel, retroarchConfig, systemName, rom, gameResolution, bezel_stretch): # disable the overlay # if all steps are passed, enable them retroarchConfig['input_overlay_hide_in_menu'] = "false" overlay_cfg_file = batoceraFiles.overlayConfigFile # bezel are disabled # default values in case something wrong append retroarchConfig['input_overlay_enable'] = "false" retroarchConfig['video_message_pos_x'] = 0.05 retroarchConfig['video_message_pos_y'] = 0.05 if bezel is None: return bz_infos = bezelsUtil.getBezelInfos(rom, bezel, systemName) if bz_infos is None: return overlay_info_file = bz_infos["info"] overlay_png_file = bz_infos["png"] bezel_game = bz_infos["specific_to_game"] # only the png file is mandatory if os.path.exists(overlay_info_file): try: infos = json.load(open(overlay_info_file)) except: infos = {} else: infos = {} # if image is not at the correct size, find the correct size bezelNeedAdaptation = False viewPortUsed = True if "width" not in infos or "height" not in infos or "top" not in infos or "left" not in infos or "bottom" not in infos or "right" not in infos: viewPortUsed = False gameRatio = float(gameResolution["width"]) / float( gameResolution["height"]) if viewPortUsed: if gameResolution["width"] != infos["width"] or gameResolution[ "height"] != infos["height"]: if gameRatio < 1.6: # let's use bezels only for 16:10, 5:3, 16:9 and wider aspect ratios return else: bezelNeedAdaptation = True retroarchConfig['aspect_ratio_index'] = str( ratioIndexes.index( "custom")) # overwritten from the beginning of this file else: # when there is no information about width and height in the .info, assume that the tv is HD 16/9 and infos are core provided if gameRatio < 1.6: # let's use bezels only for 16:10, 5:3, 16:9 and wider aspect ratios return else: # No info on the bezel, let's get the bezel image width and height and apply the # ratios from usual 16:9 1920x1080 bezels (example: theBezelProject) try: infos["width"], infos["height"] = bezelsUtil.fast_image_size( overlay_png_file) infos["top"] = int(infos["height"] * 2 / 1080) infos["left"] = int( infos["width"] * 241 / 1920 ) # 241 = (1920 - (1920 / (4:3))) / 2 + 1 pixel = where viewport start infos["bottom"] = int(infos["height"] * 2 / 1080) infos["right"] = int(infos["width"] * 241 / 1920) bezelNeedAdaptation = True except: pass # outch, no ratio will be applied. if gameResolution["width"] == infos["width"] and gameResolution[ "height"] == infos["height"]: bezelNeedAdaptation = False retroarchConfig['aspect_ratio_index'] = str(ratioIndexes.index("core")) retroarchConfig['input_overlay_enable'] = "true" retroarchConfig['input_overlay_scale'] = "1.0" retroarchConfig['input_overlay'] = overlay_cfg_file retroarchConfig['input_overlay_hide_in_menu'] = "true" if "opacity" not in infos: infos["opacity"] = 1.0 if "messagex" not in infos: infos["messagex"] = 0.0 if "messagey" not in infos: infos["messagey"] = 0.0 retroarchConfig['input_overlay_opacity'] = infos["opacity"] if bezelNeedAdaptation: wratio = gameResolution["width"] / float(infos["width"]) hratio = gameResolution["height"] / float(infos["height"]) # If width or height < original, can't add black borders, need to stretch if gameResolution["width"] < infos["width"] or gameResolution[ "height"] < infos["height"]: bezel_stretch = True if bezel_stretch: retroarchConfig['custom_viewport_x'] = infos["left"] * wratio retroarchConfig['custom_viewport_y'] = infos["top"] * hratio retroarchConfig['custom_viewport_width'] = ( infos["width"] - infos["left"] - infos["right"]) * wratio retroarchConfig['custom_viewport_height'] = ( infos["height"] - infos["top"] - infos["bottom"]) * hratio retroarchConfig['video_message_pos_x'] = infos["messagex"] * wratio retroarchConfig['video_message_pos_y'] = infos["messagey"] * hratio else: if bezel_game is True: output_png_file = "/tmp/bezel_game_adapted.png" create_new_bezel_file = True else: create_new_bezel_file = False output_png_file = "/tmp/" + os.path.splitext( os.path.basename(overlay_png_file))[0] + "_adapted.png" if os.path.exists(output_png_file) is False: create_new_bezel_file = True else: if os.path.getmtime(output_png_file) < os.path.getmtime( overlay_png_file): create_new_bezel_file = True # fast way of checking the size of a png oldwidth, oldheight = bezelsUtil.fast_image_size(output_png_file) if (oldwidth != gameResolution["width"] or oldheight != gameResolution["height"]): create_new_bezel_file = True xoffset = gameResolution["width"] - infos["width"] yoffset = gameResolution["height"] - infos["height"] retroarchConfig['custom_viewport_x'] = infos["left"] + xoffset / 2 retroarchConfig['custom_viewport_y'] = infos["top"] + yoffset / 2 retroarchConfig['custom_viewport_width'] = infos["width"] - infos[ "left"] - infos["right"] retroarchConfig['custom_viewport_height'] = infos[ "height"] - infos["top"] - infos["bottom"] retroarchConfig[ 'video_message_pos_x'] = infos["messagex"] + xoffset / 2 retroarchConfig[ 'video_message_pos_y'] = infos["messagey"] + yoffset / 2 if create_new_bezel_file is True: # Padding left and right borders for ultrawide screens (larger than 16:9 aspect ratio) # or up/down for 4K eslog.log("Generating a new adapted bezel file {}".format( output_png_file)) fillcolor = 'black' borderw = 0 borderh = 0 if wratio > 1: borderw = xoffset / 2 if hratio > 1: borderh = yoffset / 2 imgin = Image.open(overlay_png_file) if imgin.mode != "RGBA": # TheBezelProject have Palette + alpha, not RGBA. PIL can't convert from P+A to RGBA. # Even if it can load P+A, it can't save P+A as PNG. So we have to recreate a new image to adapt it. if not 'transparency' in imgin.info: return # no transparent layer for the viewport, abort alpha = imgin.split()[ -1] # alpha from original palette + alpha ix, iy = imgin.size imgnew = Image.new("RGBA", (ix, iy), (0, 0, 0, 255)) imgnew.paste(alpha, (0, 0, ix, iy)) imgout = ImageOps.expand(imgnew, border=(borderw, borderh, xoffset - borderw, yoffset - borderh), fill=fillcolor) imgout.save(output_png_file, mode="RGBA", format="PNG") else: imgout = ImageOps.expand(imgin, border=(borderw, borderh, xoffset - borderw, yoffset - borderh), fill=fillcolor) imgout.save(output_png_file, mode="RGBA", format="PNG") overlay_png_file = output_png_file # replace by the new file (recreated or cached in /tmp) else: if viewPortUsed: retroarchConfig['custom_viewport_x'] = infos["left"] retroarchConfig['custom_viewport_y'] = infos["top"] retroarchConfig['custom_viewport_width'] = infos["width"] - infos[ "left"] - infos["right"] retroarchConfig['custom_viewport_height'] = infos[ "height"] - infos["top"] - infos["bottom"] retroarchConfig['video_message_pos_x'] = infos["messagex"] retroarchConfig['video_message_pos_y'] = infos["messagey"] eslog.log("Bezel file set to {}".format(overlay_png_file)) writeBezelCfgConfig(overlay_cfg_file, overlay_png_file)
def writeBezelConfig(bezel, retroarchConfig, rom, gameResolution, system): # disable the overlay # if all steps are passed, enable them retroarchConfig['input_overlay_hide_in_menu'] = "false" overlay_cfg_file = batoceraFiles.overlayConfigFile # bezel are disabled # default values in case something wrong append retroarchConfig['input_overlay_enable'] = "false" retroarchConfig['video_message_pos_x'] = 0.05 retroarchConfig['video_message_pos_y'] = 0.05 if bezel is None: return bz_infos = bezelsUtil.getBezelInfos(rom, bezel, system.name) if bz_infos is None: return overlay_info_file = bz_infos["info"] overlay_png_file = bz_infos["png"] bezel_game = bz_infos["specific_to_game"] # only the png file is mandatory if os.path.exists(overlay_info_file): try: infos = json.load(open(overlay_info_file)) except: infos = {} else: infos = {} # if image is not at the correct size, find the correct size bezelNeedAdaptation = False viewPortUsed = True if "width" not in infos or "height" not in infos or "top" not in infos or "left" not in infos or "bottom" not in infos or "right" not in infos: viewPortUsed = False gameRatio = float(gameResolution["width"]) / float( gameResolution["height"]) if viewPortUsed: if gameResolution["width"] != infos["width"] or gameResolution[ "height"] != infos["height"]: if gameRatio < 1.6: # let's use bezels only for 16:10, 5:3, 16:9 and wider aspect ratios return else: bezelNeedAdaptation = True retroarchConfig['aspect_ratio_index'] = str( ratioIndexes.index( "custom")) # overwritten from the beginning of this file else: # when there is no information about width and height in the .info, assume that the tv is HD 16/9 and infos are core provided if gameRatio < 1.6: # let's use bezels only for 16:10, 5:3, 16:9 and wider aspect ratios return else: # No info on the bezel, let's get the bezel image width and height and apply the # ratios from usual 16:9 1920x1080 bezels (example: theBezelProject) try: infos["width"], infos["height"] = bezelsUtil.fast_image_size( overlay_png_file) infos["top"] = int(infos["height"] * 2 / 1080) infos["left"] = int( infos["width"] * 241 / 1920 ) # 241 = (1920 - (1920 / (4:3))) / 2 + 1 pixel = where viewport start infos["bottom"] = int(infos["height"] * 2 / 1080) infos["right"] = int(infos["width"] * 241 / 1920) bezelNeedAdaptation = True except: pass # outch, no ratio will be applied. if gameResolution["width"] == infos["width"] and gameResolution[ "height"] == infos["height"]: bezelNeedAdaptation = False retroarchConfig['aspect_ratio_index'] = str(ratioIndexes.index("core")) retroarchConfig['input_overlay_enable'] = "true" retroarchConfig['input_overlay_scale'] = "1.0" retroarchConfig['input_overlay'] = overlay_cfg_file retroarchConfig['input_overlay_hide_in_menu'] = "true" if "opacity" not in infos: infos["opacity"] = 1.0 if "messagex" not in infos: infos["messagex"] = 0.0 if "messagey" not in infos: infos["messagey"] = 0.0 retroarchConfig['input_overlay_opacity'] = infos["opacity"] # stretch option if system.isOptSet('bezel_stretch') and system.getOptBoolean( 'bezel_stretch') == True: bezel_stretch = True else: bezel_stretch = False if bezelNeedAdaptation: wratio = gameResolution["width"] / float(infos["width"]) hratio = gameResolution["height"] / float(infos["height"]) # If width or height < original, can't add black borders, need to stretch if gameResolution["width"] < infos["width"] or gameResolution[ "height"] < infos["height"]: bezel_stretch = True if bezel_stretch: retroarchConfig['custom_viewport_x'] = infos["left"] * wratio retroarchConfig['custom_viewport_y'] = infos["top"] * hratio retroarchConfig['custom_viewport_width'] = ( infos["width"] - infos["left"] - infos["right"]) * wratio retroarchConfig['custom_viewport_height'] = ( infos["height"] - infos["top"] - infos["bottom"]) * hratio retroarchConfig['video_message_pos_x'] = infos["messagex"] * wratio retroarchConfig['video_message_pos_y'] = infos["messagey"] * hratio else: if bezel_game is True: output_png_file = "/tmp/bezel_game_adapted.png" create_new_bezel_file = True else: create_new_bezel_file = False output_png_file = "/tmp/" + os.path.splitext( os.path.basename(overlay_png_file))[0] + "_adapted.png" if os.path.exists(output_png_file) is False: create_new_bezel_file = True else: if os.path.getmtime(output_png_file) < os.path.getmtime( overlay_png_file): create_new_bezel_file = True # fast way of checking the size of a png oldwidth, oldheight = bezelsUtil.fast_image_size(output_png_file) if (oldwidth != gameResolution["width"] or oldheight != gameResolution["height"]): create_new_bezel_file = True xoffset = gameResolution["width"] - infos["width"] yoffset = gameResolution["height"] - infos["height"] retroarchConfig['custom_viewport_x'] = infos["left"] + xoffset / 2 retroarchConfig['custom_viewport_y'] = infos["top"] + yoffset / 2 retroarchConfig['custom_viewport_width'] = infos["width"] - infos[ "left"] - infos["right"] retroarchConfig['custom_viewport_height'] = infos[ "height"] - infos["top"] - infos["bottom"] retroarchConfig[ 'video_message_pos_x'] = infos["messagex"] + xoffset / 2 retroarchConfig[ 'video_message_pos_y'] = infos["messagey"] + yoffset / 2 if create_new_bezel_file is True: # Padding left and right borders for ultrawide screens (larger than 16:9 aspect ratio) # or up/down for 4K eslog.debug("Generating a new adapted bezel file {}".format( output_png_file)) try: bezelsUtil.padImage(overlay_png_file, output_png_file, gameResolution["width"], gameResolution["height"], infos["width"], infos["height"]) except: return overlay_png_file = output_png_file # replace by the new file (recreated or cached in /tmp) else: if viewPortUsed: retroarchConfig['custom_viewport_x'] = infos["left"] retroarchConfig['custom_viewport_y'] = infos["top"] retroarchConfig['custom_viewport_width'] = infos["width"] - infos[ "left"] - infos["right"] retroarchConfig['custom_viewport_height'] = infos[ "height"] - infos["top"] - infos["bottom"] retroarchConfig['video_message_pos_x'] = infos["messagex"] retroarchConfig['video_message_pos_y'] = infos["messagey"] if system.isOptSet( 'bezel.tattoo') and system.config['bezel.tattoo'] != "0": output_png = "/tmp/bezel_tattooed.png" bezelsUtil.tatooImage(overlay_png_file, output_png_file, system) overlay_png_file = output_png_file eslog.debug("Bezel file set to {}".format(overlay_png_file)) writeBezelCfgConfig(overlay_cfg_file, overlay_png_file)
def writeBezelConfig(bezelSet, system, rom, messSys): romBase = os.path.splitext( os.path.basename(rom))[0] # filename without extension if messSys == "": tmpZipDir = "/var/run/mame_artwork/" + romBase # ok, no need to zip, a folder is taken too else: tmpZipDir = "/var/run/mame_artwork/" + messSys # ok, no need to zip, a folder is taken too # clean, in case no bezel is set, and in case we want to recreate it if os.path.exists(tmpZipDir): shutil.rmtree(tmpZipDir) if bezelSet is None: return # let's generate the zip file os.makedirs(tmpZipDir) # bezels infos bz_infos = bezelsUtil.getBezelInfos(rom, bezelSet, system.name) if bz_infos is None: return # copy the png inside if os.path.exists(bz_infos["mamezip"]): if messSys == "": artFile = "/var/run/mame_artwork/" + romBase + ".zip" else: artFile = "/var/run/mame_artwork/" + messSys + ".zip" if os.path.exists(artFile): if os.islink(artFile): os.unlink(artFile) else: os.remove(artFile) os.symlink(bz_infos["mamezip"], artFile) return elif os.path.exists(bz_infos["layout"]): os.symlink(bz_infos["layout"], tmpZipDir + "/default.lay") pngFile = os.path.split(bz_infos["png"])[1] os.symlink(bz_infos["png"], tmpZipDir + "/" + pngFile) else: pngFile = "default.png" os.symlink(bz_infos["png"], tmpZipDir + "/default.png") if os.path.exists(bz_infos["info"]): bzInfoFile = open(bz_infos["info"], "r") bzInfoText = bzInfoFile.readlines() bz_alpha = 1.0 # Just in case it's not set in the info file for infoLine in bzInfoText: if len(infoLine) > 7: infoLineClean = (infoLine.replace( '"', '')).rstrip(",\n").lstrip() infoLineData = infoLineClean.split(":") if infoLineData[0].lower() == "width": img_width = int(infoLineData[1]) elif infoLineData[0].lower() == "height": img_height = int(infoLineData[1]) elif infoLineData[0].lower() == "top": bz_y = int(infoLineData[1]) elif infoLineData[0].lower() == "left": bz_x = int(infoLineData[1]) elif infoLineData[0].lower() == "bottom": bz_bottom = int(infoLineData[1]) elif infoLineData[0].lower() == "right": bz_right = int(infoLineData[1]) elif infoLineData[0].lower() == "opacity": bz_alpha = float(infoLineData[1]) bzInfoFile.close() bz_width = img_width - bz_x - bz_right bz_height = img_height - bz_y - bz_bottom else: img_width, img_height = bezelsUtil.fast_image_size( bz_infos["png"]) _, _, rotate = MameGenerator.getMameMachineSize( romBase, tmpZipDir) # assumes that all bezels are setup for 4:3H or 3:4V aspects if rotate == 270 or rotate == 90: bz_width = int(img_height * (3 / 4)) else: bz_width = int(img_height * (4 / 3)) bz_height = img_height bz_x = int((img_width - bz_width) / 2) bz_y = 0 bz_alpha = 1.0 f = open(tmpZipDir + "/default.lay", 'w') f.write("<mamelayout version=\"2\">\n") f.write( "<element name=\"bezel\"><image file=\"default.png\" /></element>\n" ) f.write("<view name=\"bezel\">\n") f.write("<screen index=\"0\"><bounds x=\"" + str(bz_x) + "\" y=\"" + str(bz_y) + "\" width=\"" + str(bz_width) + "\" height=\"" + str(bz_height) + "\" /></screen>\n") f.write("<element ref=\"bezel\"><bounds x=\"0\" y=\"0\" width=\"" + str(img_width) + "\" height=\"" + str(img_height) + "\" alpha=\"" + str(bz_alpha) + "\" /></element>\n") f.write("</view>\n") f.write("</mamelayout>\n") f.close() if system.isOptSet( 'bezel.tattoo') and system.config['bezel.tattoo'] != "0": if system.config['bezel.tattoo'] == 'system': try: tattoo_file = '/usr/share/batocera/controller-overlays/' + system.name + '.png' if not os.path.exists(tattoo_file): tattoo_file = '/usr/share/batocera/controller-overlays/generic.png' tattoo = Image.open(tattoo_file) except Exception as e: eslog.error("Error opening controller overlay: {}".format( tattoo_file)) elif system.config['bezel.tattoo'] == 'custom' and os.path.exists( system.config['bezel.tattoo_file']): try: tattoo_file = system.config['bezel.tattoo_file'] tattoo = Image.open(tattoo_file) except: eslog.error( "Error opening custom file: {}".format('tattoo_file')) else: try: tattoo_file = '/usr/share/batocera/controller-overlays/generic.png' tattoo = Image.open(tattoo_file) except: eslog.error( "Error opening custom file: {}".format('tattoo_file')) output_png_file = "/tmp/bezel_tattooed.png" back = Image.open(tmpZipDir + "/" + pngFile) tattoo = tattoo.convert("RGBA") back = back.convert("RGBA") tw, th = bezelsUtil.fast_image_size(tattoo_file) tatwidth = int( 240 / 1920 * img_width ) # 240 = half of the difference between 4:3 and 16:9 on 1920px (0.5*1920/16*4) pcent = float(tatwidth / tw) tatheight = int(float(th) * pcent) tattoo = tattoo.resize((tatwidth, tatheight), Image.ANTIALIAS) alpha = back.split()[-1] alphatat = tattoo.split()[-1] if system.isOptSet('bezel.tattoo_corner'): corner = system.config['bezel.tattoo_corner'] else: corner = 'NW' if (corner.upper() == 'NE'): back.paste(tattoo, (img_width - tatwidth, 20), alphatat) # 20 pixels vertical margins (on 1080p) elif (corner.upper() == 'SE'): back.paste(tattoo, (img_width - tatwidth, img_height - tatheight - 20), alphatat) elif (corner.upper() == 'SW'): back.paste(tattoo, (0, img_height - tatheight - 20), alphatat) else: # default = NW back.paste(tattoo, (0, 20), alphatat) imgnew = Image.new("RGBA", (img_width, img_height), (0, 0, 0, 255)) imgnew.paste(back, (0, 0, img_width, img_height)) imgnew.save(output_png_file, mode="RGBA", format="PNG") try: os.remove(tmpZipDir + "/" + pngFile) except: pass os.symlink(output_png_file, tmpZipDir + "/" + pngFile)
def writeBezelConfig(bezel, system, rom): romBase = os.path.splitext(os.path.basename(rom))[0] # filename without extension tmpZipDir = "/var/run/mame_artwork/" + romBase # ok, no need to zip, a folder is taken too # clean, in case no bezel is set, and in case we want to recreate it if os.path.exists(tmpZipDir): shutil.rmtree(tmpZipDir) if bezel is None: return # let's generate the zip file os.makedirs(tmpZipDir) # bezels infos bz_infos = bezelsUtil.getBezelInfos(rom, bezel, system.name) if bz_infos is None: return # copy the png inside os.symlink(bz_infos["png"], tmpZipDir + "/default.png") img_width, img_height = bezelsUtil.fast_image_size(bz_infos["png"]) _, _, rotate = MameGenerator.getMameMachineSize(romBase, tmpZipDir) # assumes that all bezels are setup for 4:3H or 3:4V aspects if rotate == 270 or rotate == 90: bz_width = int(img_height * (3 / 4)) else: bz_width = int(img_height * (4 / 3)) bz_height = img_height bz_x = int((img_width - bz_width) / 2) bz_y = 0 if system.isOptSet('bezel.tattoo') and system.config['bezel.tattoo'] != "0": if system.config['bezel.tattoo'] == 'system': try: tattoo_file = '/usr/share/batocera/controller-overlays/'+system.name+'.png' if not os.path.exists(tattoo_file): tattoo_file = '/usr/share/batocera/controller-overlays/generic.png' tattoo = Image.open(tattoo_file) except Exception as e: eslog.error("Error opening controller overlay: {}".format(tattoo_file)) elif system.config['bezel.tattoo'] == 'custom' and os.path.exists(system.config['bezel.tattoo_file']): try: tattoo_file = system.config['bezel.tattoo_file'] tattoo = Image.open(tattoo_file) except: eslog.error("Error opening custom file: {}".format('tattoo_file')) else: try: tattoo_file = '/usr/share/batocera/controller-overlays/generic.png' tattoo = Image.open(tattoo_file) except: eslog.error("Error opening custom file: {}".format('tattoo_file')) output_png_file = "/tmp/bezel_tattooed.png" back = Image.open(tmpZipDir + "/default.png") tattoo = tattoo.convert("RGBA") back = back.convert("RGBA") tw,th = bezelsUtil.fast_image_size(tattoo_file) tatwidth = int(240/1920 * img_width) # 240 = half of the difference between 4:3 and 16:9 on 1920px (0.5*1920/16*4) pcent = float(tatwidth / tw) tatheight = int(float(th) * pcent) tattoo = tattoo.resize((tatwidth,tatheight), Image.ANTIALIAS) alpha = back.split()[-1] alphatat = tattoo.split()[-1] if system.isOptSet('bezel.tattoo_corner'): corner = system.config['bezel.tattoo_corner'] else: corner = 'NW' if (corner.upper() == 'NE'): back.paste(tattoo, (img_width-tatwidth,20), alphatat) # 20 pixels vertical margins (on 1080p) elif (corner.upper() == 'SE'): back.paste(tattoo, (img_width-tatwidth,img_height-tatheight-20), alphatat) elif (corner.upper() == 'SW'): back.paste(tattoo, (0,img_height-tatheight-20), alphatat) else: # default = NW back.paste(tattoo, (0,20), alphatat) imgnew = Image.new("RGBA", (img_width,img_height), (0,0,0,255)) imgnew.paste(back, (0,0,img_width,img_height)) imgnew.save(output_png_file, mode="RGBA", format="PNG") try: os.remove(tmpZipDir + "/default.png") except: pass os.symlink(output_png_file, tmpZipDir + "/default.png") f = open(tmpZipDir + "/default.lay", 'w') f.write("<mamelayout version=\"2\">") f.write("<element name=\"bezel\"><image file=\"default.png\" /></element>") f.write("<view name=\"bezel\">") f.write("<screen index=\"0\"><bounds x=\"" + str(bz_x) + "\" y=\"" + str(bz_y) + "\" width=\"" + str(bz_width) + "\" height=\"" + str(bz_height) + "\" /></screen>") f.write("<bezel element=\"bezel\"><bounds x=\"0\" y=\"0\" width=\"" + str(img_width) + "\" height=\"" + str(img_height) + "\" /></bezel>") f.write("</view>") f.write("</mamelayout>") f.close()