diff --git a/modules/images.py b/modules/images.py index c1c913e..537cdd1 100644 --- a/modules/images.py +++ b/modules/images.py @@ -81,24 +81,23 @@ def handleImages(folderName, estimate): translatedData = openFiles(f"files/{folderName}") # Custom Names - customList = [[], []] - customList = processImagesDir("Custom", customList) + # customList = [[], []] + # customList = processImagesDir("Custom", customList) - # Write Strings to Images - if not ESTIMATE: - if not os.path.exists(f"translated/{folderName}"): - os.mkdir(f"translated/{folderName}") - for i in range(len(translatedData[0][0])): + # Write TL To Images + try: + translatedList, originalList, dimensionsList = translatedData[0] + for i in range(len(translatedList)): try: - translatedList = translatedData[0][0] - originalList = translatedData[0][1] - dimensionsList = translatedData[0][2] - image = stringToImage(translatedList[i], dimensionsList[i][0], dimensionsList[i][1]) - image.save(rf"translated/{folderName}/{customList[0][0]}.png", quality=100) - customList[0].pop(0) + # Create image from string + image = stringToImageOutline(translatedList[i], dimensionsList[i][0], dimensionsList[i][1]) + # Save image using the corresponding original filename + image.save(rf"translated/{folderName}/{originalList[i]}.png", quality=100) except Exception as e: - PBAR.write(f"{translatedList[i]}: {str(e)}") - # Ignore Error + # Log error if image saving fails + PBAR.write(f"Error processing {translatedList[i]}: {str(e)}") + except IndexError: + PBAR.write("Translated data is incomplete. Please check your input.") # Print File end = time.time() @@ -121,7 +120,7 @@ def openFiles(folderName): global PBAR if os.path.isdir(folderName): - imageList = [[], []] + imageList = [[], [], []] imageList = processImagesDir(folderName, imageList) # Start Translation @@ -134,7 +133,7 @@ def openFiles(folderName): ) as PBAR: translatedData = translateImages(imageList) translatedData = [ - [translatedData[0], imageList[0], imageList[1]], + [translatedData[0], imageList[2], imageList[1]], translatedData[1], translatedData[2], ] @@ -209,6 +208,8 @@ def stringToImage(text, width, height, font_path="fonts/TsunagiGothic.ttf", scal text_width = text_bbox[2] - text_bbox[0] text_height = text_bbox[3] - text_bbox[1] + 20 x = 0 + + x = (scaled_width - text_width) // 2 y = (scaled_height - text_height) // 2 # Draw the text on the image @@ -222,6 +223,110 @@ def stringToImage(text, width, height, font_path="fonts/TsunagiGothic.ttf", scal return image +from PIL import Image, ImageDraw, ImageFont + +def stringToImageOutline(text, width, height, font_path="fonts/TsunagiGothic.ttf", scale_factor=4): + # Outline + outline_color=(0, 0, 0, 255) + outline_thickness=4 + + # Increase the resolution + scaled_width = int(width * scale_factor) + scaled_height = int(height * scale_factor) + + # Find the appropriate font size for the scaled up image + font_size = getFontSize(text, scaled_width, scaled_height, font_path) + if font_size == 0: + raise ValueError("Text is too long to fit in the supplied dimensions.") + + # Create a new image with the scaled width and height and a transparent background + image = Image.new("RGBA", (scaled_width, scaled_height), (255, 255, 255, 0)) + + # Create a drawing context + draw = ImageDraw.Draw(image) + + # Load the appropriate font + font = ImageFont.truetype(font_path, font_size) + + # Calculate the size of the text to center it + text_bbox = draw.textbbox((0, 0), text, font=font) + text_width = text_bbox[2] - text_bbox[0] + text_height = text_bbox[3] - text_bbox[1] + 20 + x = (scaled_width - text_width) // 2 + y = (scaled_height - text_height) // 2 + + # Draw the text outline by applying the text multiple times with small offsets + for dx in range(-outline_thickness, outline_thickness + 1): + for dy in range(-outline_thickness, outline_thickness + 1): + if dx != 0 or dy != 0: + draw.text((x + dx, y + dy), text, font=font, fill=outline_color) + + # Draw the main text + draw.text((x, y), text, font=font, fill=(60, 160, 230, 255)) + + # Resize back to the original dimensions to get a clearer text rendering + image = image.resize((width, height), Image.LANCZOS) + + return image + +def stringToImageBox(text, width, height, font_path="fonts/TsunagiGothic.ttf", scale_factor=4): + # Increase the resolution + scaled_width = int(width * scale_factor) + scaled_height = int(height * scale_factor) + + # Padding around the text + padding = 10 + + # Calculate the dimensions available for text placement + available_width = scaled_width - 2 * padding + available_height = scaled_height - 2 * padding + + # Determine the best font size to fit within the available dimensions + font_size = getFontSize(text, available_width, available_height, font_path) + if font_size <= 0: + raise ValueError("Text is too long to fit in the supplied dimensions.") + + # Create a new image with increased resolution + image = Image.new("RGBA", (scaled_width, scaled_height), (255, 255, 255, 0)) + draw = ImageDraw.Draw(image) + + # Load the calculated font + font = ImageFont.truetype(font_path, font_size) + + # Calculate the size and bounding box of the text + text_bbox = draw.textbbox((0, 0), text, font=font) + text_width = text_bbox[2] - text_bbox[0] + text_height = text_bbox[3] - text_bbox[1] + 20 + + # Determine centered position for the text while considering padding + # Additional adjustment ensures text appears centrally aligned + x = (scaled_width - text_width) // 2 + y = (scaled_height - text_height) // 2 + + # Draw a black box with a white outline that fits the image dimensions precisely + draw.rectangle( + [0, 0, scaled_width - 1, scaled_height - 1], + outline=(255, 255, 255, 255), + width=1 + ) + + # Fill the inside box with black color + draw.rectangle( + [1, 1, scaled_width - 2, scaled_height - 2], + fill=(0, 0, 0, 255) + ) + + # Render the text within the image + draw.text((x, y), text, font=font, fill=(255, 255, 255, 255)) + + # Shrink the image back to original dimensions with high-quality interpolation + image = image.resize( + (width, height), + Image.LANCZOS, + ) + + return image + def getImageDimensions(file_path): try: @@ -248,8 +353,14 @@ def processImagesDir(directory_path, imageList): } for target, replacement in placeholders.items(): file_name = file_name.replace(target, replacement) - imageList[0].append(file_name) + match = re.search(r"[\[【].+?[\]】](.*)", file_name) + if match: + text = match.group(1) + else: + text = file_name + imageList[0].append(text) imageList[1].append([width, height]) + imageList[2].append(file_name) except Exception as e: print(f"Error processing {file_name}: {e}") diff --git a/modules/rpgmakermvmz.py b/modules/rpgmakermvmz.py index db0df9c..8667108 100644 --- a/modules/rpgmakermvmz.py +++ b/modules/rpgmakermvmz.py @@ -138,7 +138,7 @@ def handleMVMZ(filename, estimate): def openFiles(filename): - with open("files/" + filename, "r", encoding="utf-8-sig") as f: + with open("files/" + filename, "r", encoding="utf-8") as f: data = json.load(f) # Map Files @@ -1314,7 +1314,7 @@ def searchCodes(page, pbar, jobList, filename): for key, (argVar, font) in headerMappings.items(): if key in headerString: translatePlugins(argVar, font) - + if headerString == "LL_GalgeChoiceWindow": ### Message Text First jaString = codeList[i]["parameters"][3]["messageText"] diff --git a/modules/wolf.py b/modules/wolf.py index e78b5d4..7695901 100644 --- a/modules/wolf.py +++ b/modules/wolf.py @@ -81,8 +81,8 @@ PBAR = None FILENAME = None # Dialogue / Choices -CODE101 = False -CODE102 = False +CODE101 = True +CODE102 = True # Set String (Fragile but necessary) CODE122 = False @@ -301,56 +301,56 @@ def searchCodes(events, pbar, jobList, filename): if codeList[i]["code"] == 101 and CODE101 == True: # Grab String jaString = codeList[i]["stringArgs"][0] - initialJAString = jaString + speaker = "" # Grab Speaker if ":\n" in jaString: - nameList = re.findall(r"(.*):\n", jaString) - if nameList is not None: + match = re.search(r"@\d+\n(.*):\n", jaString) + if match: # TL Speaker - response = getSpeaker(nameList[0]) + response = getSpeaker(match.group(1)) speaker = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Set nametag and remove from string - nametag = f"{speaker}:\n" - jaString = jaString.replace(f"{nameList[0]}:\n", "") + codeList[i]["stringArgs"][0] = codeList[i]["stringArgs"][0].replace(match.group(1), speaker) + + # Grab Only Text + match = re.search(r"\n\s+([\w\W\n]+)", codeList[i]["stringArgs"][0]) + if match: + jaString = match.group(1) + initialJAString = jaString - # Remove Textwrap - jaString = jaString.replace("\n", " ") + # Remove Textwrap + jaString = jaString.replace("\n", " ") - # 1st Pass (Save Text to List) - if not setData: - if speaker == "": - stringList.append(jaString) + # 1st Pass (Save Text to List) + if not setData: + if speaker == "": + stringList.append(jaString) + else: + stringList.append(f"[{speaker}]: {jaString}") + + # 2nd Pass (Set Text) else: - stringList.append(f"[{speaker}]: {jaString}") + # Grab Translated String + translatedText = stringList[0] - # 2nd Pass (Set Text) - else: - # Grab Translated String - translatedText = stringList[0] + # Remove speaker + matchSpeakerList = re.findall(r"^(\[.+?\]\s?[|:]\s?)\s?", translatedText) + if len(matchSpeakerList) > 0: + translatedText = translatedText.replace(matchSpeakerList[0], "") - # Remove speaker - matchSpeakerList = re.findall(r"^(\[.+?\]\s?[|:]\s?)\s?", translatedText) - if len(matchSpeakerList) > 0: - translatedText = translatedText.replace(matchSpeakerList[0], "") + # Textwrap + if FIXTEXTWRAP is True: + translatedText = textwrap.fill(translatedText, width=WIDTH) - # Textwrap - if FIXTEXTWRAP is True: - translatedText = textwrap.fill(translatedText, width=WIDTH) + # Set Data + codeList[i]["stringArgs"][0] = codeList[i]["stringArgs"][0].replace(initialJAString, translatedText) - # Add back Nametag - translatedText = nametag + translatedText - nametag = "" - - # Set Data - codeList[i]["stringArgs"][0] = translatedText - - # Reset Data and Pop Item - speaker = "" - stringList.pop(0) + # Reset Data and Pop Item + stringList.pop(0) ### Event Code: 102 Choices if codeList[i]["code"] == 102 and CODE102 == True: diff --git a/vocab.txt b/vocab.txt index 2ef5598..c3746e1 100644 --- a/vocab.txt +++ b/vocab.txt @@ -1,12 +1,18 @@ Here are some vocabulary and terms so that you know the proper spelling and translation. ``` # Game Characters -水原 雪 (Mizuhara Yuki) - Female -彩芽 (Ayame) - Female -水原 独苑 (Mizuhara Dokuen) - Male -空木 (Utsugi) - Male -金目 (Kaname) - Male -銀目 (Ginme) - Male +ジロウ (Jirou) - Male +サクラ (Sakura) - Female +ゼフ (Zeff) - Male +ヨモダ (Yomada) - Male +グダ (Guda) - Male +フジワラ (Fujiwara) - Male +ナオ (Nao) - Female +タジ (Taji) - Male +カリン (Karin) - Female +セリナ (Serina) - Female +ラグ (Ragu) - Male +ハッカイ (Hakkai) - Male # Lewd Terms マンコ (pussy)