- app.py +213 -0
- assets/html/intro.txt +15 -0
- assets/images/banner-dugrainaupain.jpg +0 -0
- assets/images/before-after/moulin-insitu-1-_1610534-AFTER.jpg +0 -0
- assets/images/before-after/moulin-insitu-1-_1610534-BEFORE.jpg +0 -0
- assets/images/before-after/moulin-insitu-1-_1610534-schema-BEFORE.jpg +0 -0
- assets/windmill/images/dummy.txt +0 -0
- assets/windmill/models3D/dummy.txt +0 -0
- assets/windmill/videos/dummy.txt +0 -0
- infos.txt +2 -0
- requirements.txt +3 -0
- script.js +116 -0
app.py
ADDED
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from gradio_imageslider import ImageSlider
|
3 |
+
import os
|
4 |
+
import pprint
|
5 |
+
import sys
|
6 |
+
from pathlib import Path
|
7 |
+
from collections import OrderedDict
|
8 |
+
from PIL import Image
|
9 |
+
|
10 |
+
|
11 |
+
print('\n\n================================ START')
|
12 |
+
|
13 |
+
SEP = os.path.sep
|
14 |
+
BASE_URL = "https://huggingface.co/spaces/menorki/projet-moulin-belle-ile/resolve/main/"
|
15 |
+
BASE_PATH = Path(__file__).resolve().parent
|
16 |
+
BASE_DIR = str(BASE_PATH) + SEP
|
17 |
+
IN_SPACE = os.environ.get("SPACE_AUTHOR_NAME") in ["menorki"]
|
18 |
+
|
19 |
+
TMP_PATH = BASE_PATH / 'gradio_tmp'
|
20 |
+
TMP_DIR = str(TMP_PATH) + SEP
|
21 |
+
#if TMP_DIR.exists():
|
22 |
+
# shutil.rmtree(str(TMP_DIR))
|
23 |
+
TMP_PATH.mkdir(exist_ok=True, parents=True)
|
24 |
+
os.environ['GRADIO_TEMP_DIR'] = TMP_DIR
|
25 |
+
|
26 |
+
print(f"BASE_URL: {BASE_URL}")
|
27 |
+
print(f"BASE_DIR: {BASE_DIR}")
|
28 |
+
print(f"TMP_DIR: {TMP_DIR}")
|
29 |
+
print(f"IN_SPACE: {IN_SPACE}")
|
30 |
+
|
31 |
+
dir_models3D = "assets/windmill/models3D/"
|
32 |
+
dir_images = "assets/windmill/images/"
|
33 |
+
dir_videos = "assets/windmill/videos/"
|
34 |
+
|
35 |
+
# gr.set_static_paths(paths=[f"{BASE_DIR}assets/windmill"])
|
36 |
+
|
37 |
+
model3D_names = [f for f in os.listdir(dir_models3D) if f.endswith('.gltf') or f.endswith('.obj') or f.endswith('.glb')]
|
38 |
+
model3D_files = [BASE_URL + dir_models3D + name for name in model3D_names]
|
39 |
+
|
40 |
+
images_names = [f for f in os.listdir(dir_images) if f.endswith('.jpg') or f.endswith('.png')]
|
41 |
+
images_files = [(BASE_URL + dir_images + name , name) for name in images_names]
|
42 |
+
|
43 |
+
video_names = [f for f in os.listdir(dir_videos) if f.endswith('.mp4') or f.endswith('.avi')]
|
44 |
+
video_files = [BASE_URL + dir_videos + name for name in video_names]
|
45 |
+
|
46 |
+
|
47 |
+
DESCRIPTION = """# PROJET MOULIN SIMON """
|
48 |
+
|
49 |
+
css = '''
|
50 |
+
.gradio-container {max-width: 1280px !important; height:90%;}
|
51 |
+
#gallery { height: 90% !important; } /* Adjusted for padding/margin if any */
|
52 |
+
h1{text-align:center}
|
53 |
+
'''
|
54 |
+
|
55 |
+
head = '''
|
56 |
+
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.5.0/model-viewer.min.js"></script>
|
57 |
+
<script defer src="https://cdn.jsdelivr.net/npm/img-comparison-slider@8/dist/index.js"></script>
|
58 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/img-comparison-slider@8/dist/styles.css"/>
|
59 |
+
<style>
|
60 |
+
.custom-animated-handle {
|
61 |
+
transition: transform 0.2s;
|
62 |
+
}
|
63 |
+
|
64 |
+
.slider-with-animated-handle:hover .custom-animated-handle {
|
65 |
+
transform: scale(1.2);
|
66 |
+
}
|
67 |
+
|
68 |
+
h1, h2 {
|
69 |
+
color: #0056b3;
|
70 |
+
# padding-bottom:10px;
|
71 |
+
padding-top:10px;
|
72 |
+
}
|
73 |
+
p {
|
74 |
+
margin: 1em 0;
|
75 |
+
}
|
76 |
+
.highlight {
|
77 |
+
color: #d9534f;
|
78 |
+
font-weight: bold;
|
79 |
+
}
|
80 |
+
.emphasis {
|
81 |
+
color: #5cb85c;
|
82 |
+
font-style: italic;
|
83 |
+
}
|
84 |
+
</style>
|
85 |
+
'''
|
86 |
+
|
87 |
+
def read_text_file(path:str)->str :
|
88 |
+
with open(path, 'r', encoding='utf-8') as file:
|
89 |
+
content = file.read()
|
90 |
+
return content
|
91 |
+
|
92 |
+
def read_PIL_images(filenames):
|
93 |
+
images = []
|
94 |
+
for filename in filenames:
|
95 |
+
try:
|
96 |
+
print(f'Loading {filename}......')
|
97 |
+
img = Image.open(filename)
|
98 |
+
images.append(img)
|
99 |
+
print(f'Loaded {filename}')
|
100 |
+
except Exception as e:
|
101 |
+
print(f"Error opening image {filename}: {e}")
|
102 |
+
return images
|
103 |
+
|
104 |
+
def build_comparison_slider(before_url , after_url):
|
105 |
+
# @see https://img-comparison-slider.sneas.io/examples.html#always-show
|
106 |
+
html = f'''
|
107 |
+
<img-comparison-slider class="slider-with-animated-handle" style="max-width:500px; --divider-width: 4px; --divider-color: #ff0000;">
|
108 |
+
<img slot="first" width="100%" src="{before_url}" />
|
109 |
+
<img slot="second" width="100%" src="{after_url}" />
|
110 |
+
<svg slot="handle" class="custom-animated-handle" xmlns="http://www.w3.org/2000/svg" width="100" viewBox="-8 -3 16 6">
|
111 |
+
<path stroke="#fff" d="M -5 -2 L -7 0 L -5 2 M -5 -2 L -5 2 M 5 -2 L 7 0 L 5 2 M 5 -2 L 5 2" stroke-width="1" fill="#fff" vector-effect="non-scaling-stroke"></path>
|
112 |
+
</svg>
|
113 |
+
</img-comparison-slider>'''
|
114 |
+
|
115 |
+
return html
|
116 |
+
|
117 |
+
with gr.Blocks(analytics_enabled=False , head=head , css=css, theme="bethecloud/storj_theme" , elem_id='gradio-container') as demo:
|
118 |
+
gr.HTML(f'''<div style="width:100%; text-align:left"><img src="{BASE_URL}assets/images/banner-dugrainaupain.jpg" style="display: inline-block;"></div>''')
|
119 |
+
|
120 |
+
|
121 |
+
with gr.Tab("LE PROJET....."):
|
122 |
+
|
123 |
+
with gr.Row():
|
124 |
+
with gr.Column(scale=1):
|
125 |
+
before = BASE_URL + 'assets/images/before-after/moulin-insitu-1-_1610534-BEFORE.jpg'
|
126 |
+
after = BASE_URL + 'assets/images/before-after/moulin-insitu-1-_1610534-AFTER.jpg'
|
127 |
+
gr.HTML(build_comparison_slider(before , after))
|
128 |
+
|
129 |
+
with gr.Column(scale=1):
|
130 |
+
gr.HTML(read_text_file("assets/html/intro.txt"))
|
131 |
+
|
132 |
+
|
133 |
+
with gr.Tab("Avant/Après"):
|
134 |
+
with gr.Row():
|
135 |
+
before = BASE_URL + 'assets/images/before-after/moulin-insitu-1-_1610534-schema-BEFORE.jpg'
|
136 |
+
after = BASE_URL + 'assets/images/before-after/moulin-insitu-1-_1610534-AFTER.jpg'
|
137 |
+
gr.HTML(build_comparison_slider(before , after))
|
138 |
+
|
139 |
+
before = BASE_URL + 'assets/images/before-after/moulin-insitu-1-_1610534-BEFORE.jpg'
|
140 |
+
after = BASE_URL + 'assets/images/before-after/moulin-insitu-1-_1610534-AFTER.jpg'
|
141 |
+
gr.HTML(build_comparison_slider(before , after))
|
142 |
+
|
143 |
+
print(f'{BASE_URL}assets/images/before-after/moulin-insitu-1-_1610534-schema-BEFORE.jpg')
|
144 |
+
print(f'{BASE_URL}assets/images/before-after/moulin-insitu-1-_1610534-BEFORE.jpg')
|
145 |
+
print(f'{BASE_URL}assets/images/before-after/moulin-insitu-1-_1610534-AFTER.jpg')
|
146 |
+
|
147 |
+
|
148 |
+
with gr.Tab("Images"):
|
149 |
+
image_viewer = gr.Gallery(label="Generated images",
|
150 |
+
show_label=False,
|
151 |
+
elem_id='gallery',
|
152 |
+
columns=[3],
|
153 |
+
rows=[1],
|
154 |
+
object_fit="cover",
|
155 |
+
interactive=False,
|
156 |
+
value=images_files)
|
157 |
+
|
158 |
+
|
159 |
+
with gr.Tab("Modèles 3D"):
|
160 |
+
|
161 |
+
viewer_html = '''<div id="google-3D-viewer-container" style="min-width:800px; width:100%; height:600px;" style="flex: 1; display: flex; justify-content: center; align-items: center;">
|
162 |
+
<model-viewer id="google-3D-viewer" style="width: 100%; height: 100%;" src="DEFAULT_MODEL_URL" auto-rotate camera-controls></model-viewer>
|
163 |
+
</div>
|
164 |
+
'''
|
165 |
+
|
166 |
+
viewer_html = viewer_html.replace('DEFAULT_MODEL_URL' , BASE_URL + dir_models3D + model3D_names[0])
|
167 |
+
viewer_html = viewer_html.replace('BASE_URL_3D' , BASE_URL + dir_models3D)
|
168 |
+
|
169 |
+
google_viewer = gr.HTML(viewer_html)
|
170 |
+
|
171 |
+
with gr.Row(visible=True):
|
172 |
+
|
173 |
+
model_selection = gr.Radio(
|
174 |
+
show_label=True,
|
175 |
+
container=True,
|
176 |
+
interactive=True,
|
177 |
+
choices=model3D_names,
|
178 |
+
value=model3D_names[0],
|
179 |
+
label="Selectionner un modèle 3D :",
|
180 |
+
)
|
181 |
+
|
182 |
+
# js = f"(name) => document.getElementById('google-3D-viewer').src = '{BASE_URL + dir_models3D}' + name"
|
183 |
+
model_selection.change(fn=None,
|
184 |
+
inputs=model_selection,
|
185 |
+
outputs=None ,
|
186 |
+
js=f"(name) => document.getElementById('google-3D-viewer').src = '{BASE_URL + dir_models3D}' + name")
|
187 |
+
|
188 |
+
|
189 |
+
with gr.Tab("Videos"):
|
190 |
+
|
191 |
+
video_viewer = gr.Video(interactive=False, value=video_files[0])
|
192 |
+
|
193 |
+
with gr.Row(visible=True):
|
194 |
+
|
195 |
+
video_selection = gr.Radio(
|
196 |
+
show_label=True,
|
197 |
+
container=True,
|
198 |
+
interactive=True,
|
199 |
+
choices=video_names,
|
200 |
+
value=video_names[0],
|
201 |
+
label="Selectionner une video:"
|
202 |
+
)
|
203 |
+
|
204 |
+
def load_video(video_name):
|
205 |
+
video_file = BASE_URL + dir_videos + video_name
|
206 |
+
print(f'LOADING VIDEO: {video_file}')
|
207 |
+
return video_file
|
208 |
+
|
209 |
+
video_selection.change(fn=load_video, inputs=video_selection, outputs=video_viewer)
|
210 |
+
|
211 |
+
|
212 |
+
if __name__ == "__main__":
|
213 |
+
demo.launch(debug=not IN_SPACE, show_api=False)
|
assets/html/intro.txt
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="container">
|
2 |
+
<h2>Énergie Solidaire sur Belle-Île-en-Mer</h1>
|
3 |
+
<p><span class="highlight">Belle-Île-en-Mer</span>, joyau de la Bretagne, s'apprête à accueillir un projet ambitieux et unique en son genre : la construction d'un moulin à vent destiné à moudre du blé et à produire de la farine. Cette initiative est portée par l'association à but non lucratif <span class="highlight">"DU GRAIN AU PAIN"</span>.</p>
|
4 |
+
|
5 |
+
<h2>Un Projet pour Revitaliser l'Artisanat Local</h2>
|
6 |
+
<p>L'idée de ce projet est simple mais audacieuse : construire un moulin à vent traditionnel sur l'île pour moudre du blé cultivé localement. La farine produite sera ensuite vendue aux commerces locaux tels que les <span class="highlight">boulangeries</span> et les <span class="highlight">crêperies</span>. Ce projet vise non seulement à <span class="emphasis">revitaliser l'artisanat local</span>, mais aussi à promouvoir des pratiques agricoles durables et à renforcer l'économie de l'île.</p>
|
7 |
+
|
8 |
+
<h2>Un Patrimoine à Préserver</h2>
|
9 |
+
<p>Les moulins à vent font partie intégrante du patrimoine de Belle-Île-en-Mer. En construisant ce moulin, nous souhaitons rendre hommage à cette tradition et offrir à la communauté un symbole de <span class="emphasis">solidarité et de durabilité</span>. Le moulin sera également un lieu éducatif où les visiteurs pourront découvrir les méthodes de mouture traditionnelles et en apprendre davantage sur l'histoire de l'île.</p>
|
10 |
+
|
11 |
+
<h2>Participez à Notre Campagne de Financement Participatif</h2>
|
12 |
+
<p>Pour réaliser ce projet, nous lançons une campagne de <span class="highlight">financement participatif</span>. Chaque contribution, qu'elle soit petite ou grande, nous rapprochera de notre objectif. En soutenant ce projet, vous contribuez à la préservation de notre patrimoine et à la promotion d'une économie locale <span class="emphasis">durable</span>.</p>
|
13 |
+
|
14 |
+
<p>Rejoignez-nous dans cette aventure et aidez-nous à faire souffler un vent de solidarité sur Belle-Île-en-Mer. Ensemble, construisons le <span class="highlight">Moulin Simon</span> et faisons de ce rêve une réalité !</p>
|
15 |
+
</div>
|
assets/images/banner-dugrainaupain.jpg
ADDED
assets/images/before-after/moulin-insitu-1-_1610534-AFTER.jpg
ADDED
assets/images/before-after/moulin-insitu-1-_1610534-BEFORE.jpg
ADDED
assets/images/before-after/moulin-insitu-1-_1610534-schema-BEFORE.jpg
ADDED
assets/windmill/images/dummy.txt
ADDED
File without changes
|
assets/windmill/models3D/dummy.txt
ADDED
File without changes
|
assets/windmill/videos/dummy.txt
ADDED
File without changes
|
infos.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
https://huggingface.co/spaces/menorki/projet-moulin-belle-ile
|
2 |
+
https://menorki-projet-moulin-belle-ile.hf.space/
|
requirements.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
gradio_imageslider
|
3 |
+
Pillow
|
script.js
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function demo_load(x) {
|
2 |
+
document.body.scrollTop = document.documentElement.scrollTop = 0;
|
3 |
+
|
4 |
+
function gradioApp() {
|
5 |
+
const elems = document.getElementsByTagName('gradio-app');
|
6 |
+
const elem = elems.length == 0 ? document : elems[0];
|
7 |
+
|
8 |
+
if (elem !== document) {
|
9 |
+
elem.getElementById = function(id) {
|
10 |
+
return document.getElementById(id);
|
11 |
+
};
|
12 |
+
}
|
13 |
+
return elem.shadowRoot ? elem.shadowRoot : elem;
|
14 |
+
}
|
15 |
+
|
16 |
+
function all_gallery_buttons() {
|
17 |
+
var allGalleryButtons = gradioApp().querySelectorAll('#outputgallery .thumbnail-item.thumbnail-small');
|
18 |
+
var visibleGalleryButtons = [];
|
19 |
+
allGalleryButtons.forEach(function(elem) {
|
20 |
+
if (elem.parentElement.offsetParent) {
|
21 |
+
visibleGalleryButtons.push(elem);
|
22 |
+
}
|
23 |
+
});
|
24 |
+
return visibleGalleryButtons;
|
25 |
+
}
|
26 |
+
|
27 |
+
function selected_gallery_button() {
|
28 |
+
return all_gallery_buttons().find(elem => elem.classList.contains('selected')) ?? null;
|
29 |
+
}
|
30 |
+
|
31 |
+
function selected_gallery_index() {
|
32 |
+
return all_gallery_buttons().findIndex(elem => elem.classList.contains('selected'));
|
33 |
+
}
|
34 |
+
|
35 |
+
function loadImg(src){
|
36 |
+
return new Promise((resolve, reject) => {
|
37 |
+
let img = new Image()
|
38 |
+
img.onload = () => resolve(img)
|
39 |
+
img.onerror = reject
|
40 |
+
img.src = src
|
41 |
+
})
|
42 |
+
}
|
43 |
+
|
44 |
+
async function resize_b64_img(b64_img, max_side=2048) {
|
45 |
+
var img = await loadImg(b64_img);
|
46 |
+
naturalWidth = img.naturalWidth;
|
47 |
+
naturalHeight = img.naturalHeight;
|
48 |
+
|
49 |
+
if (naturalWidth > max_side || naturalHeight > max_side) {
|
50 |
+
var width = 0;
|
51 |
+
var height = 0;
|
52 |
+
if (naturalWidth >= naturalHeight) {
|
53 |
+
width = max_side;
|
54 |
+
height = Math.ceil((max_side / naturalWidth) * naturalHeight);
|
55 |
+
} else {
|
56 |
+
height = max_side;
|
57 |
+
width = Math.ceil((max_side / naturalHeight) * naturalWidth);
|
58 |
+
}
|
59 |
+
|
60 |
+
var canvas = document.createElement('canvas');
|
61 |
+
ctx = canvas.getContext('2d');
|
62 |
+
canvas.width = width;
|
63 |
+
canvas.height = height;
|
64 |
+
ctx.drawImage(img, 0, 0, width, height);
|
65 |
+
return canvas.toDataURL();
|
66 |
+
}
|
67 |
+
return b64_img;
|
68 |
+
}
|
69 |
+
|
70 |
+
// fix image preview on mobile
|
71 |
+
function imageMaskResize() {
|
72 |
+
const canvases = gradioApp().querySelectorAll('#inputmask canvas');
|
73 |
+
if (!canvases.length) {
|
74 |
+
window.removeEventListener('resize', imageMaskResize);
|
75 |
+
return;
|
76 |
+
}
|
77 |
+
|
78 |
+
const wrapper = canvases[0].closest('.wrap');
|
79 |
+
const previewImage = wrapper.previousElementSibling;
|
80 |
+
|
81 |
+
if (!previewImage.complete) {
|
82 |
+
previewImage.addEventListener('load', imageMaskResize);
|
83 |
+
return;
|
84 |
+
}
|
85 |
+
|
86 |
+
const w = previewImage.width;
|
87 |
+
const h = previewImage.height;
|
88 |
+
const nw = previewImage.naturalWidth;
|
89 |
+
const nh = previewImage.naturalHeight;
|
90 |
+
const portrait = nh > nw;
|
91 |
+
|
92 |
+
const wW = Math.min(w, portrait ? h / nh * nw : w / nw * nw);
|
93 |
+
const wH = Math.min(h, portrait ? h / nh * nh : w / nw * nh);
|
94 |
+
|
95 |
+
wrapper.style.width = `${wW}px`;
|
96 |
+
wrapper.style.height = `${wH}px`;
|
97 |
+
wrapper.style.left = `0px`;
|
98 |
+
wrapper.style.top = `0px`;
|
99 |
+
|
100 |
+
canvases.forEach(c => {
|
101 |
+
c.style.width = c.style.height = '';
|
102 |
+
c.style.maxWidth = '100%';
|
103 |
+
c.style.maxHeight = '100%';
|
104 |
+
c.style.objectFit = 'contain';
|
105 |
+
});
|
106 |
+
}
|
107 |
+
|
108 |
+
window.gradioApp = gradioApp
|
109 |
+
window.all_gallery_buttons = all_gallery_buttons
|
110 |
+
window.selected_gallery_button = selected_gallery_button
|
111 |
+
window.selected_gallery_index = selected_gallery_index
|
112 |
+
window.resize_b64_img = resize_b64_img
|
113 |
+
window.imageMaskResize = imageMaskResize;
|
114 |
+
|
115 |
+
window.addEventListener('resize', imageMaskResize);
|
116 |
+
}
|