admin commited on
Commit
470f9a1
·
1 Parent(s): fd41354

update styles

Browse files
Files changed (5) hide show
  1. requirements.txt +1 -1
  2. src/modules/app.py +10 -7
  3. src/modules/link.py +50 -10
  4. src/modules/main.py +12 -64
  5. style.css +77 -12
requirements.txt CHANGED
@@ -1,6 +1,6 @@
1
  gradio==4.32.2
2
- links==1.0
3
  Markdown==3.6
 
4
  Pillow==10.3.0
5
  python_frontmatter==1.1.0
6
  qrcode==7.4.2
 
1
  gradio==4.32.2
 
2
  Markdown==3.6
3
+ pandas==1.5.3
4
  Pillow==10.3.0
5
  python_frontmatter==1.1.0
6
  qrcode==7.4.2
src/modules/app.py CHANGED
@@ -40,11 +40,18 @@ with gr.Blocks() as demo:
40
  with gr.Column():
41
  access_token = gr.Textbox(label="Access Token", placeholder="***")
42
  api_url = gr.Textbox(label="API base URL", placeholder="https://")
43
- txt_input = gr.TextArea(label="Enter Text with URLs")
44
  count_url = gr.Dropdown(visible=False, allow_custom_value=True)
45
  @gr.render(inputs=[txt_input])
46
  def update_cnt(txt):
47
- urls = re.findall(r'http[s]?://\S+', txt)
 
 
 
 
 
 
 
48
  return urls
49
 
50
  with gr.Row():
@@ -87,7 +94,7 @@ with gr.Blocks() as demo:
87
  txt_input, cm_img_input, idv_img_input
88
  ]
89
  examples = [
90
- ['https://example.com',
91
  ['demo/demo.jpg'],
92
  ['demo/logo.png']
93
  ]
@@ -102,10 +109,6 @@ with gr.Blocks() as demo:
102
  cm_img_input.change(update_df, cm_img_input, df)
103
  idv_img_input.change(update_df, idv_img_input, df)
104
 
105
- # example_temp_html = TextProcessor.apply_style('demo/demo.md', 'style.css') # TODO
106
- with open('demo/demo.md') as f:
107
- demo_txt = f.read()
108
-
109
  submit_button.click(
110
  UrlProcessor.shorten_and_generate_qr,
111
  inputs=[
 
40
  with gr.Column():
41
  access_token = gr.Textbox(label="Access Token", placeholder="***")
42
  api_url = gr.Textbox(label="API base URL", placeholder="https://")
43
+ txt_input = gr.MultimodalTextbox(label="Enter Text with URLs")
44
  count_url = gr.Dropdown(visible=False, allow_custom_value=True)
45
  @gr.render(inputs=[txt_input])
46
  def update_cnt(txt):
47
+ text = ''
48
+ if txt['files']:
49
+ for f in txt['files']:
50
+ with open(f) as f:
51
+ text += f.read()
52
+ if txt['text']:
53
+ text += txt['text']
54
+ urls = re.findall(r'http[s]?://\S+', text)
55
  return urls
56
 
57
  with gr.Row():
 
94
  txt_input, cm_img_input, idv_img_input
95
  ]
96
  examples = [
97
+ [{'files': ['demo/demo.md'], 'text': 'https://example.com'},
98
  ['demo/demo.jpg'],
99
  ['demo/logo.png']
100
  ]
 
109
  cm_img_input.change(update_df, cm_img_input, df)
110
  idv_img_input.change(update_df, idv_img_input, df)
111
 
 
 
 
 
112
  submit_button.click(
113
  UrlProcessor.shorten_and_generate_qr,
114
  inputs=[
src/modules/link.py CHANGED
@@ -1,16 +1,27 @@
1
  import os
2
- import requests
3
  import re
4
- import base64
5
  import json
 
 
6
  import qrcode
 
7
  import markdown
 
 
 
 
 
 
 
 
 
8
  import itertools
 
9
  from io import BytesIO
10
  from PIL import ImageOps
11
 
12
  from utils import Utils
13
- from main import Image, ImageProcessor
14
 
15
 
16
  BITLY_ACCESS_TOKEN = os.getenv('BITLY_ACCESS_TOKEN', None)
@@ -82,15 +93,23 @@ class UrlProcessor:
82
  return None, None, {"error": str(e)}
83
 
84
 
85
- @staticmethod
86
- def shorten_and_generate_qr(access_token, api_url, txt, shorten, generate_qr, common_images, individual_images, positions_df):
87
  bitly = UrlProcessor(access_token, api_url)
88
 
 
 
 
 
 
 
 
 
89
  urls = re.findall(r'http[s]?://\S+', txt)
90
 
91
  results = []
92
  ts, tmpd = Utils.get_tempdir()
93
 
 
94
  markdown_links = txt
95
  all_json_responses = []
96
  qr_svgs = []
@@ -175,6 +194,18 @@ class UrlProcessor:
175
  else:
176
  num_iterations = 1
177
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  for idx in range(num_iterations):
179
  qr_idx = idx % len(qr_pngs) if qr_pngs else 0
180
  indv_idx = idx // len(qr_pngs) if individual_images else 0
@@ -183,7 +214,6 @@ class UrlProcessor:
183
  indv = individual_images[indv_idx] if individual_images else None
184
 
185
  if qr or indv:
186
- print(idx)
187
  try:
188
  pos_x = int(positions_df.loc[idx, 'PosX'])
189
  pos_y = int(positions_df.loc[idx, 'PosY'])
@@ -203,6 +233,9 @@ class UrlProcessor:
203
  if indv:
204
  layer = processor.combine_images(layer, indv, (size_x, size_y), (pos_x, pos_y))
205
 
 
 
 
206
  if qr:
207
  layer = processor.combine_images(layer, qr, (size_px, size_py), (pos_px, pos_py))
208
 
@@ -215,12 +248,16 @@ class UrlProcessor:
215
  with open(card_path, "rb") as image_file:
216
  encoded_string = base64.b64encode(image_file.read()).decode()
217
 
218
- card_html = f'<img src="data:image/png;base64,{encoded_string}" alt="Card"> '
 
219
  card_htmls.append(card_html)
220
 
221
  except Exception as e:
222
  raise Exception(f"Error combining images: {e}")
223
 
 
 
 
224
  try:
225
  json_output_path = os.path.join(tmpd, 'response.json')
226
  with open(json_output_path, 'w') as json_file:
@@ -254,15 +291,18 @@ class UrlProcessor:
254
  for idx, png in enumerate(card_pngs):
255
  card_png_output_paths.append(png)
256
 
257
- index_html = f'<html><head><link rel="stylesheet" type="text/css" href="{css_path}"></head><body>'
258
  for card_html in card_htmls:
259
  index_html += card_html
260
- index_html += '</body></html>'
261
 
262
  index_output_path = os.path.join(tmpd, index_path)
263
  with open(index_output_path, 'w') as index_file:
264
  index_file.write(index_html)
265
 
 
 
 
266
  zip_output_path = os.path.join(tmpd, f"{ts}.zip")
267
  zip_content_list = [
268
  json_output_path,
@@ -272,7 +312,7 @@ class UrlProcessor:
272
  *card_svg_output_paths,
273
  *card_png_output_paths,
274
  index_output_path,
275
- css_path
276
  ]
277
  zip_output_path = Utils.create_zip(zip_content_list, zip_output_path)
278
  except Exception as e:
 
1
  import os
 
2
  import re
 
3
  import json
4
+ import base64
5
+ import shutil
6
  import qrcode
7
+ import requests
8
  import markdown
9
+ from markdown.extensions.codehilite import CodeHiliteExtension
10
+ from markdown.extensions.toc import TocExtension
11
+ from markdown.extensions.sane_lists import SaneListExtension
12
+ from markdown.extensions.nl2br import Nl2BrExtension
13
+ from markdown.extensions.fenced_code import FencedCodeExtension
14
+ from markdown.extensions.wikilinks import WikiLinkExtension
15
+ from markdown.extensions.footnotes import FootnoteExtension
16
+ from markdown.extensions.tables import TableExtension
17
+
18
  import itertools
19
+ import frontmatter
20
  from io import BytesIO
21
  from PIL import ImageOps
22
 
23
  from utils import Utils
24
+ from main import Image, ImageProcessor, TextProcessor
25
 
26
 
27
  BITLY_ACCESS_TOKEN = os.getenv('BITLY_ACCESS_TOKEN', None)
 
93
  return None, None, {"error": str(e)}
94
 
95
 
96
+ def shorten_and_generate_qr(access_token, api_url, text, shorten, generate_qr, common_images, individual_images, positions_df):
 
97
  bitly = UrlProcessor(access_token, api_url)
98
 
99
+ txt = ''
100
+ if text['files']:
101
+ for f in text['files']:
102
+ with open(f) as f:
103
+ txt += f.read()
104
+ if text['text']:
105
+ txt += text['text']
106
+
107
  urls = re.findall(r'http[s]?://\S+', txt)
108
 
109
  results = []
110
  ts, tmpd = Utils.get_tempdir()
111
 
112
+ anno_txt = 'test'
113
  markdown_links = txt
114
  all_json_responses = []
115
  qr_svgs = []
 
194
  else:
195
  num_iterations = 1
196
 
197
+
198
+ # -------------------content start --------------------------------
199
+ index_html = f'<html><head><link rel="stylesheet" type="text/css" href="{css_path}"></head><body>'
200
+
201
+ processed_text = ''
202
+ md = markdown.Markdown()
203
+ for idx, file in enumerate(text['files']):
204
+ fm = frontmatter.load(file) # TODO
205
+ replacements = {key: list(item.values())[0] \
206
+ for item in fm.metadata['replace'] for key in item}
207
+ processed_text += TextProcessor.apply_frontmatter(fm.content, replacements)
208
+
209
  for idx in range(num_iterations):
210
  qr_idx = idx % len(qr_pngs) if qr_pngs else 0
211
  indv_idx = idx // len(qr_pngs) if individual_images else 0
 
214
  indv = individual_images[indv_idx] if individual_images else None
215
 
216
  if qr or indv:
 
217
  try:
218
  pos_x = int(positions_df.loc[idx, 'PosX'])
219
  pos_y = int(positions_df.loc[idx, 'PosY'])
 
233
  if indv:
234
  layer = processor.combine_images(layer, indv, (size_x, size_y), (pos_x, pos_y))
235
 
236
+ # if anno_txt:
237
+ # layer = processor.combine_txt(layer, anno_txt, (size_px, size_py), (pos_px, pos_py))
238
+
239
  if qr:
240
  layer = processor.combine_images(layer, qr, (size_px, size_py), (pos_px, pos_py))
241
 
 
248
  with open(card_path, "rb") as image_file:
249
  encoded_string = base64.b64encode(image_file.read()).decode()
250
 
251
+ html_txt = md.convert(processed_text)
252
+ card_html = f'<div class="card"><img src="data:image/png;base64,{encoded_string}" alt="Card">{html_txt}</div>'
253
  card_htmls.append(card_html)
254
 
255
  except Exception as e:
256
  raise Exception(f"Error combining images: {e}")
257
 
258
+ index_html += '</body></html>'
259
+ # -------------------content end --------------------------------
260
+
261
  try:
262
  json_output_path = os.path.join(tmpd, 'response.json')
263
  with open(json_output_path, 'w') as json_file:
 
291
  for idx, png in enumerate(card_pngs):
292
  card_png_output_paths.append(png)
293
 
294
+
295
  for card_html in card_htmls:
296
  index_html += card_html
297
+
298
 
299
  index_output_path = os.path.join(tmpd, index_path)
300
  with open(index_output_path, 'w') as index_file:
301
  index_file.write(index_html)
302
 
303
+ css_output_path = os.path.join(tmpd, css_path)
304
+ shutil.copy(css_path, css_output_path)
305
+
306
  zip_output_path = os.path.join(tmpd, f"{ts}.zip")
307
  zip_content_list = [
308
  json_output_path,
 
312
  *card_svg_output_paths,
313
  *card_png_output_paths,
314
  index_output_path,
315
+ css_output_path
316
  ]
317
  zip_output_path = Utils.create_zip(zip_content_list, zip_output_path)
318
  except Exception as e:
src/modules/main.py CHANGED
@@ -1,6 +1,4 @@
1
  import os
2
- import markdown
3
- import frontmatter
4
  from PIL import Image, ImageDraw, ImageFont, ImageOps
5
 
6
  from utils import Utils
@@ -11,26 +9,6 @@ class TextProcessor:
11
  text = text.replace(f'{{{key}}}', value)
12
  return text
13
 
14
- def apply_style(input_markdown_path, style_css_path):
15
- with open(input_markdown_path, 'r') as file:
16
- md_content = file.read()
17
-
18
- fm = frontmatter.load(input_markdown_path)
19
- replacements = {key: list(item.values())[0] \
20
- for item in fm.metadata['replace'] for key in item}
21
- processed_text = TextProcessor.apply_frontmatter(md_content, replacements)
22
-
23
- with open(style_css_path, 'r') as file:
24
- style_css = file.read()
25
-
26
- html_content = markdown.markdown(processed_text)
27
- html_content = f'<html><head><style>{style_css}</style></head><body>{html_content}</body></html>'
28
-
29
- temp_html_path = os.path.join(tempfile.gettempdir(), 'processed.html')
30
- with open(temp_html_path, 'w') as file:
31
- file.write(html_content)
32
-
33
- return temp_html_path
34
 
35
  class ImageProcessor:
36
  def __init__(self):
@@ -71,46 +49,16 @@ class ImageProcessor:
71
  return base_img
72
  except Exception as e:
73
  raise Exception(f"Error combining images: {e}")
74
- # @staticmethod
75
- # def insert_txt(png_path, text):
76
- # img = Image.open(png_path)
77
- # draw = ImageDraw.Draw(img)
78
- # font = ImageFont.load_default() # Update to a specific font if needed
79
- # width, height = img.size
80
- # text_width, text_height = draw.textlength(text, font=font)
81
- # text_position = (width - text_width - 10, height - text_height - 10)
82
- # draw.text(text_position, text, font=font, fill="black")
83
-
84
- # with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmpfile:
85
- # img.save(tmpfile.name, format="PNG")
86
- # return tmpfile.name
87
-
88
- # @staticmethod
89
- # def insert_txt(png_path, text):
90
- # img = Image.open(png_path)
91
- # draw = ImageDraw.Draw(img)
92
- # font = ImageFont.load_default() # Update to a specific font if needed
93
- # width, height = img.size
94
- # text_width, text_height = draw.textlength(text, font=font)
95
- # text_position = (width - text_width - 10, height - text_height - 10)
96
- # draw.text(text_position, text, font=font, fill="black")
97
-
98
- # with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmpfile:
99
- # img.save(tmpfile.name, format="PNG")
100
- # return tmpfile.name
101
-
102
- @staticmethod
103
- def move_image(image_path, position, temp_dir=None):
104
- try:
105
- if temp_dir is None:
106
- _, temp_dir = Utils.get_tempdir()
107
- with open(image_path, 'rb') as f:
108
- img = Image.open(f).convert("RGBA")
109
- result_img = Image.new("RGBA", img.size, (255, 255, 255, 0))
110
- result_img.paste(img, position, img)
111
- file_path = os.path.join(temp_dir, 'moved.png')
112
- result_img.save(file_path, format="PNG")
113
- return file_path
114
- except Exception as e:
115
- raise Exception(f"Error moving image: {e}")
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
 
 
2
  from PIL import Image, ImageDraw, ImageFont, ImageOps
3
 
4
  from utils import Utils
 
9
  text = text.replace(f'{{{key}}}', value)
10
  return text
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  class ImageProcessor:
14
  def __init__(self):
 
49
  return base_img
50
  except Exception as e:
51
  raise Exception(f"Error combining images: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ # def combine_txt(self, base_image, text, size, position, font_path='fonts/msmincho.ttc', font_size=12, fill="black"):
54
+ # try:
55
+ # font_path = str(Path(__file__).parent / "../fonts/msmincho.ttc")
56
+ # font = ImageFont.truetype(font_path, font_size)
57
+ # base_img = base_image.convert("RGBA")
58
+ # draw = ImageDraw.Draw(base_img)
59
+ # w, h = size
60
+ # draw.text(position, text, font=font, fill=fill)
61
+
62
+ # return base_img
63
+ # except Exception as e:
64
+ # raise Exception(f"Error combining text: {e}")
style.css CHANGED
@@ -1,41 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  h1 {
2
- font-weight: bold;
3
  }
4
 
5
- /* フォントとマージンの設定 */
6
  p {
7
  font-family: 'MS Mincho', serif;
8
- margin: 10%;
9
  }
10
 
11
- /* 画像の透明度設定 */
12
  img {
13
- opacity: 0.5;
14
  }
15
 
16
- /* QRコードの位置設定 */
17
  .qr {
18
  position: absolute;
19
  bottom: 10px;
20
  right: 10px;
21
- margin: 10%;
22
  }
23
 
24
- /* カードのサイズとグリッドレイアウト設定 */
25
  .card {
26
  width: 91mm;
27
  height: 55mm;
28
  display: grid;
29
  grid-template-columns: 1fr;
30
- grid-template-rows: 1fr;
31
  align-items: center;
32
  justify-items: center;
33
- border: 1px solid black;
34
- margin: 5mm;
35
  position: relative;
36
  }
37
 
38
- /* 印刷時のA4用紙設定 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  @media print {
40
  .a4 {
41
  page-break-after: always;
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Alegreya:ital,wght@0,400;0,500;0,700;0,800;0,900;1,400;1,500;1,700;1,800;1,900&display=swap');
2
+
3
+ @font-face {
4
+ font-family: 'YuMincho';
5
+ src: url("./fonts/yumin.ttf") format('truetype');
6
+ font-weight: regular;
7
+ }
8
+
9
+ body {
10
+ font-size: 10pt;
11
+ font-family: Alegreya, "Times New Roman", "游明朝", YuMincho, "Hiragino Mincho ProN", "MS PMincho", "Crimson Text", serif;
12
+ }
13
+
14
  h1 {
15
+ font-weight: bold;
16
  }
17
 
 
18
  p {
19
  font-family: 'MS Mincho', serif;
 
20
  }
21
 
 
22
  img {
23
+ opacity: 1;
24
  }
25
 
 
26
  .qr {
27
  position: absolute;
28
  bottom: 10px;
29
  right: 10px;
 
30
  }
31
 
 
32
  .card {
33
  width: 91mm;
34
  height: 55mm;
35
  display: grid;
36
  grid-template-columns: 1fr;
37
+ grid-template-rows: 2fr 1fr 1fr 1fr 3fr;
38
  align-items: center;
39
  justify-items: center;
40
+ border: 0px solid black;
 
41
  position: relative;
42
  }
43
 
44
+ .card > * {
45
+ margin: 0;
46
+ }
47
+
48
+ .card h1 {
49
+ font-size: 1.4rem;
50
+ font-weight: bold;
51
+ grid-column: 1;
52
+ grid-row: 2;
53
+ }
54
+
55
+ .card h2 {
56
+ font-size: 1rem;
57
+ grid-column: 1;
58
+ grid-row: 3;
59
+ }
60
+
61
+ .card h3 {
62
+ font-size: 1rem;
63
+ grid-column: 1;
64
+ grid-row: 4;
65
+ }
66
+
67
+ .card h4 {
68
+ font-size: 1rem;
69
+ }
70
+
71
+ .card h5 {
72
+ font-size: 1rem;
73
+ }
74
+
75
+ .card h6 {
76
+ font-size: 1rem;
77
+ }
78
+
79
+ .card ul {
80
+ list-style: none;
81
+ justify-self: start;
82
+ grid-column: 1;
83
+ grid-row: 5;
84
+ }
85
+
86
+ .card ol {
87
+ list-style: none;
88
+ padding: 0;
89
+ }
90
+
91
+ .card li {
92
+ font-size: 0.6rem;
93
+ }
94
+
95
+ .card img {
96
+ max-width: 100%;
97
+ max-height: 100%;
98
+ grid-row: 4;
99
+ justify-self: end;
100
+ align-self: end;
101
+ position: fixed;
102
+ }
103
+
104
  @media print {
105
  .a4 {
106
  page-break-after: always;