import random as rn import gradio as gr from PIL import Image import pillow_avif import backend from backend import season_color mh_season = ['Atom01', 'Binary01', 'Cream01', 'Divine01', 'Ever01'] mh_season_default = 'Ever01' mh_class = ['Welcome', 'First', 'Special', 'Premier', 'OMA1', 'OMA2'] mh_member_names = [ "SeoYeon", "HyeRin", "JiWoo", "ChaeYeon", "YooYeon", "SooMin", "Nakyoung", "YuBin", "Kaede", "DaHyun", "Kotone", "YeonJi", "Nien", "SoHyun", "Xinyu", "Mayu", "Lynn", "JooBin", "HaYeon", "ShiOn", "ChaeWon", "Sullin", "SeoAh", "JiYeon", 'HeeJin', 'HaSeul', 'KimLip', 'JinSoul', 'Choerry' ] mh_artist_names = ['tripleS', 'ARTMS'] mh_number = [ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 401 ] mh_line = ['Z', 'A'] def x_y(x): return x def quick_tab_selected(*all_components): image, path = backend.front('quick', all_components[0], *all_components[1:]) #마지막 all_components는 list가 아니여야함 return 'quick', image, path def balanced_tab_selected(*all_components): image, path = backend.front('balanced', all_components[0], *all_components[1:]) #마지막 all_components는 list가 아니여야함 return 'balanced', image, path def expert_tab_selected(*all_components): image, path = backend.front('expert', all_components[0], *all_components[1:]) #마지막 all_components는 list가 아니여야함 return 'expert', image, path def class_change(class_name, number, line): visible = False match class_name: case 'First': visible = True number = rn.randint(101,120) case 'Welcome': number = 100 case 'Special': number = rn.randint(201, 221) case 'Double': visible = True number = rn.randint(301, 258) case 'Premier': number = '401' line = 'A' case 'OMA1': number = '304' case 'OMA2': number = '322' return gr.Radio(visible=visible), number, line def expert_color_change(radio): visible = [False, False, False] if radio == 'Static': visible[0] = True elif radio == 'Gradient': visible[1] = True elif radio == 'Image': visible[2] = True return gr.ColorPicker(visible=visible[0]), gr.Slider(visible=visible[1]), gr.Image(visible=visible[2]) # replaced it in backend.image_uploaded """ def resize_image(image): if not isinstance(image, Image.Image): raise gr.Error("This format cannot be uploaded.") if not image.size == (1083, 1673): target_width, target_height = (1083, 1673) # 원본 이미지의 너비와 높이 original_width, original_height = image.size # 원하는 비율 계산 target_ratio = target_width / target_height original_ratio = original_width / original_height if original_ratio > target_ratio: # 이미지가 가로로 더 길 경우: 양쪽을 잘라냄 new_width = int(original_height * target_ratio) new_height = original_height left = (original_width - new_width) // 2 top = 0 right = left + new_width bottom = new_height else: # 이미지가 세로로 더 길 경우: 위아래를 잘라냄 new_width = original_width new_height = int(original_width / target_ratio) left = 0 top = (original_height - new_height) // 2 right = new_width bottom = top + new_height img_cropped = image.crop((left, top, right, bottom)) img_resized = img_cropped.resize((target_width, target_height), Image.Resampling.LANCZOS) return img_resized, img_resized else: return image, image """ # Updated CSS with 'top: 0;' and overflow adjustments css = """ body, html, .gradio-container, .gradio-container > .gr-block { overflow: visible !important; -webkit-touch-callout:none; -webkit-user-select:none; -webkit-tap-highlight-color:rgba(0, 0, 0, 0); } .sticky-image { position: sticky; top: 10px; height: 45dvh; z-index: 1000; } /* When dvh < dvw, set height to 80dvh */ @media (min-aspect-ratio: 1.3/1) { .sticky-image { height: 80dvh; } } footer{display:none !important} """ animation = """ function createGradioAnimation() { var container = document.createElement('div'); container.id = 'gradio-animation'; container.style.fontSize = '2em'; container.style.fontWeight = 'bold'; container.style.textAlign = 'center'; container.style.marginTop = '0px'; container.style.marginBottom = '5px'; var text = 'Objektify'; for (var i = 0; i < text.length; i++) { (function(i){ setTimeout(function(){ var letter = document.createElement('span'); letter.style.opacity = '0'; letter.style.transition = 'opacity 0.5s'; letter.innerText = text[i]; container.appendChild(letter); setTimeout(function() { letter.style.opacity = '1'; }, 50); }, i * 250); })(i); } var gradioContainer = document.querySelector('.gradio-container'); gradioContainer.insertBefore(container, gradioContainer.firstChild); setTimeout(function() { container.style.transition = 'all 2s'; container.style.fontSize = '1em'; container.style.letterSpacing = '0.1em'; }, 3000); return 'Animation created'; } """ theme = gr.themes.Ocean( primary_hue="violet", neutral_hue="zinc", ) with gr.Blocks(css=css, theme=theme, js=animation) as objektify: with gr.Group(visible=False): current_tab = gr.Textbox('quick', label='mode') original_image = gr.Image(type='pil', format='png', image_mode='RGBA') with gr.Tab('Front'): with gr.Row(): with gr.Row(elem_classes='sticky-image'): input_image = gr.Image(type='filepath', interactive=True, show_download_button=True, show_fullscreen_button=True, format='png', show_label=False, elem_classes='sticky-image', sources='upload') with gr.Column(): with gr.Row(): common_name = gr.Dropdown(label='Name',choices=mh_member_names, allow_custom_value=True, interactive=True) common_group = gr.Dropdown(label='Group', choices=mh_artist_names, allow_custom_value=True, interactive=True) with gr.Tab('Quick') as quick: quick_season = gr.Radio(label='Season', value=mh_season_default,choices=mh_season) with gr.Tab('Balanced') as balanced: balanced_class = gr.Radio(label='Class', value='Welcome',choices=mh_class) balanced_season = gr.Radio(label='Season', value=mh_season_default, choices=mh_season, visible=False) with gr.Row(): balanced_number = gr.Dropdown(label='Number', choices=mh_number, allow_custom_value=True) balanced_line = gr.Dropdown(label='On/Offline', choices=mh_line, allow_custom_value=True) balanced_serial = gr.Textbox(label='Serial', value='1', interactive=True) with gr.Tab('Expert') as expert: with gr.Column(): expert_color_radio = gr.Radio(label='Main Color', choices=['Static', 'Gradient', 'Image'], value='Static') with gr.Row(): with gr.Group(): expert_static = gr.ColorPicker(interactive=True, visible=True, value=season_color[mh_season_default], label='Main Color') expert_gradient = gr.Slider(interactive=True, visible=False, minimum=1, maximum=1000) expert_image = gr.Image(interactive=True, visible=False) expert_text_color = gr.ColorPicker(interactive=True, visible=True, value='#000000', label='Text Color') with gr.Row(): expert_number = gr.Dropdown(label='Number', choices=mh_number, allow_custom_value=True) expert_line = gr.Dropdown(label='On/Offline', choices=mh_line, allow_custom_value=True) expert_serial = gr.Textbox(label='Serial', value='1', interactive=True) with gr.Row(): download_button = gr.DownloadButton(variant="primary") share_button = gr.Button('Share') input_image.upload(fn=backend.image_uploaded, inputs=input_image, outputs=[original_image]) input_image.clear(fn=lambda : gr.Image(value=None), outputs=original_image) #quick_season.select(fn=x_y, inputs=quick_season, outputs=balanced_season) #balanced_season.select(fn=x_y, inputs=balanced_season, outputs=quick_season) balanced_class.change(fn=class_change, inputs=[balanced_class, balanced_number, balanced_line], outputs=[balanced_season, balanced_number, balanced_line]) expert_color_radio.change(fn=expert_color_change, inputs=expert_color_radio, outputs=[expert_static, expert_gradient, expert_image]) all_components = [original_image, common_name, common_group, quick_season, balanced_season, balanced_class, balanced_number, balanced_line, balanced_serial, expert_color_radio, expert_static, expert_gradient, expert_image, expert_text_color, expert_number, expert_line, expert_serial] quick.select(fn=quick_tab_selected, outputs=[current_tab, input_image, download_button], inputs=[]+all_components) balanced.select(fn=balanced_tab_selected, outputs=[current_tab, input_image, download_button], inputs=all_components) expert.select(fn=expert_tab_selected, outputs=[current_tab, input_image, download_button], inputs=all_components) for component in all_components: if not component == balanced_class: # avoid double generate component.change(fn=backend.front, inputs=[current_tab]+all_components, outputs=[input_image, download_button]) #with gr.Tab('back'): if __name__ == '__main__': objektify.launch(server_name='0.0.0.0', allowed_paths=['./data'])