TheEeeeLin commited on
Commit
5ea080f
1 Parent(s): 6da028a

update kb resize

Browse files
Files changed (4) hide show
  1. .gitignore +6 -0
  2. app.py +285 -88
  3. image_utils.py +58 -0
  4. output/.gitkeep +0 -0
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ *.pyc
2
+ **/__pycache__
3
+ .idea
4
+ .DS_Store
5
+ hivision_modnet.onnx
6
+ output/*.jpg
app.py CHANGED
@@ -5,10 +5,20 @@ from hivisionai.hycv.vision import add_background
5
  from src.layoutCreate import generate_layout_photo, generate_layout_image
6
  import pathlib
7
  import numpy as np
8
-
9
- size_list_dict = {"一寸": (413, 295), "二寸": (626, 413),
10
- "教师资格证": (413, 295), "国家公务员考试": (413, 295), "初级会计考试": (413, 295)}
11
- color_list_dict = {"蓝色": (86, 140, 212), "白色": (255, 255, 255), "红色": (233, 51, 35)}
 
 
 
 
 
 
 
 
 
 
12
 
13
 
14
  # 设置Gradio examples
@@ -26,25 +36,30 @@ def range_check(value, min_value=0, max_value=255):
26
  return value
27
 
28
 
29
- def idphoto_inference(input_image,
30
- mode_option,
31
- size_list_option,
32
- color_option,
33
- render_option,
34
- custom_color_R,
35
- custom_color_G,
36
- custom_color_B,
37
- custom_size_height,
38
- custom_size_width,
39
- head_measure_ratio=0.2,
40
- head_height_ratio=0.45,
41
- top_distance_max=0.12,
42
- top_distance_min=0.10):
 
 
 
 
43
 
44
  idphoto_json = {
45
  "size_mode": mode_option,
46
  "color_mode": color_option,
47
  "render_mode": render_option,
 
48
  }
49
 
50
  # 如果尺寸模式选择的是尺寸列表
@@ -54,97 +69,182 @@ def idphoto_inference(input_image,
54
  elif idphoto_json["size_mode"] == "自定义尺寸":
55
  id_height = int(custom_size_height)
56
  id_width = int(custom_size_width)
57
- if id_height < id_width or min(id_height, id_width) < 100 or max(id_height, id_width) > 1800:
 
 
 
 
58
  return {
59
  img_output_standard: gr.update(value=None),
60
  img_output_standard_hd: gr.update(value=None),
61
- notification: gr.update(value="宽度应不大于长度;长宽不应小于100,大于1800", visible=True)}
 
 
 
62
  idphoto_json["size"] = (id_height, id_width)
63
  else:
64
  idphoto_json["size"] = (None, None)
65
 
66
  # 如果颜色模式选择的是自定义底色
67
  if idphoto_json["color_mode"] == "自定义底色":
68
- idphoto_json["color_bgr"] = (range_check(custom_color_R),
69
- range_check(custom_color_G),
70
- range_check(custom_color_B))
 
 
71
  else:
72
  idphoto_json["color_bgr"] = color_list_dict[color_option]
73
 
74
- result_image_hd, result_image_standard, typography_arr, typography_rotate, \
75
- _, _, _, _, status = IDphotos_create(input_image,
76
- mode=idphoto_json["size_mode"],
77
- size=idphoto_json["size"],
78
- head_measure_ratio=head_measure_ratio,
79
- head_height_ratio=head_height_ratio,
80
- align=False,
81
- beauty=False,
82
- fd68=None,
83
- human_sess=sess,
84
- IS_DEBUG=False,
85
- top_distance_max=top_distance_max,
86
- top_distance_min=top_distance_min)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  # 如果检测到人脸数量不等于1
89
  if status == 0:
90
  result_messgae = {
91
  img_output_standard: gr.update(value=None),
92
  img_output_standard_hd: gr.update(value=None),
93
- notification: gr.update(value="人脸数量不等于1", visible=True)
94
  }
95
 
96
  # 如果检测到人脸数量等于1
97
  else:
98
  if idphoto_json["render_mode"] == "纯色":
99
  result_image_standard = np.uint8(
100
- add_background(result_image_standard, bgr=idphoto_json["color_bgr"]))
101
- result_image_hd = np.uint8(add_background(result_image_hd, bgr=idphoto_json["color_bgr"]))
 
 
 
102
  elif idphoto_json["render_mode"] == "上下渐变(白)":
103
  result_image_standard = np.uint8(
104
- add_background(result_image_standard, bgr=idphoto_json["color_bgr"], mode="updown_gradient"))
 
 
 
 
 
105
  result_image_hd = np.uint8(
106
- add_background(result_image_hd, bgr=idphoto_json["color_bgr"], mode="updown_gradient"))
 
 
 
 
 
107
  else:
108
  result_image_standard = np.uint8(
109
- add_background(result_image_standard, bgr=idphoto_json["color_bgr"], mode="center_gradient"))
 
 
 
 
 
110
  result_image_hd = np.uint8(
111
- add_background(result_image_hd, bgr=idphoto_json["color_bgr"], mode="center_gradient"))
 
 
 
 
 
112
 
113
  if idphoto_json["size_mode"] == "只换底":
114
  result_layout_image = gr.update(visible=False)
115
  else:
116
- typography_arr, typography_rotate = generate_layout_photo(input_height=idphoto_json["size"][0],
117
- input_width=idphoto_json["size"][1])
118
-
119
- result_layout_image = generate_layout_image(result_image_standard, typography_arr,
120
- typography_rotate,
121
- height=idphoto_json["size"][0],
122
- width=idphoto_json["size"][1])
123
-
124
- result_messgae = {
125
- img_output_standard: result_image_standard,
126
- img_output_standard_hd: result_image_hd,
127
- img_output_layout: result_layout_image,
128
- notification: gr.update(visible=False)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
  return result_messgae
131
 
132
 
133
  if __name__ == "__main__":
 
134
  HY_HUMAN_MATTING_WEIGHTS_PATH = "./hivision_modnet.onnx"
135
  sess = onnxruntime.InferenceSession(HY_HUMAN_MATTING_WEIGHTS_PATH)
 
136
  size_mode = ["尺寸列表", "只换底", "自定义尺寸"]
137
  size_list = ["一寸", "二寸", "教师资格证", "国家公务员考试", "初级会计考试"]
138
  colors = ["蓝色", "白色", "红色", "自定义底色"]
139
  render = ["纯色", "上下渐变(白)", "中心渐变(白)"]
 
140
 
141
  title = "<h1 id='title'>HivisionIDPhotos</h1>"
142
- description = "<h3>😎6.20更新:新增尺寸选择列表</h3>"
143
- css = '''
144
  h1#title, h3 {
145
  text-align: center;
146
  }
147
- '''
148
 
149
  demo = gr.Blocks(css=css)
150
 
@@ -152,39 +252,90 @@ if __name__ == "__main__":
152
  gr.Markdown(title)
153
  gr.Markdown(description)
154
  with gr.Row():
 
155
  with gr.Column():
156
  img_input = gr.Image().style(height=350)
157
- mode_options = gr.Radio(choices=size_mode, label="证件照尺寸选项", value="尺寸列表", elem_id="size")
 
 
 
 
 
158
  # 预设尺寸下拉菜单
159
  with gr.Row(visible=True) as size_list_row:
160
- size_list_options = gr.Dropdown(choices=size_list, label="预设尺寸", value="一寸", elem_id="size_list")
 
 
 
 
 
161
 
162
  with gr.Row(visible=False) as custom_size:
163
- custom_size_height = gr.Number(value=413, label="height", interactive=True)
164
- custom_size_wdith = gr.Number(value=295, label="width", interactive=True)
165
-
166
- color_options = gr.Radio(choices=colors, label="背景色", value="蓝色", elem_id="color")
 
 
 
 
 
 
 
 
 
167
  with gr.Row(visible=False) as custom_color:
168
  custom_color_R = gr.Number(value=0, label="R", interactive=True)
169
  custom_color_G = gr.Number(value=0, label="G", interactive=True)
170
  custom_color_B = gr.Number(value=0, label="B", interactive=True)
171
 
172
- render_options = gr.Radio(choices=render, label="渲染方式", value="纯色", elem_id="render")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
- img_but = gr.Button('开始制作')
175
  # 案例图片
176
- example_images = gr.Dataset(components=[img_input],
177
- samples=[[path.as_posix()]
178
- for path in sorted(pathlib.Path('images').rglob('*.jpg'))])
179
-
 
 
 
 
 
180
  with gr.Column():
181
  notification = gr.Text(label="状态", visible=False)
182
  with gr.Row():
183
  img_output_standard = gr.Image(label="标准照").style(height=350)
184
  img_output_standard_hd = gr.Image(label="高清照").style(height=350)
185
  img_output_layout = gr.Image(label="六寸排版照").style(height=350)
 
186
 
187
-
188
  def change_color(colors):
189
  if colors == "自定义底色":
190
  return {custom_color: gr.update(visible=True)}
@@ -193,23 +344,69 @@ if __name__ == "__main__":
193
 
194
  def change_size_mode(size_option_item):
195
  if size_option_item == "自定义尺寸":
196
- return {custom_size: gr.update(visible=True),
197
- size_list_row: gr.update(visible=False)}
 
 
198
  elif size_option_item == "只换底":
199
- return {custom_size: gr.update(visible=False),
200
- size_list_row: gr.update(visible=False)}
 
 
 
 
 
 
 
 
 
 
 
201
  else:
202
- return {custom_size: gr.update(visible=False),
203
- size_list_row: gr.update(visible=True)}
204
-
205
- color_options.input(change_color, inputs=[color_options], outputs=[custom_color])
206
- mode_options.input(change_size_mode, inputs=[mode_options], outputs=[custom_size, size_list_row])
207
-
208
- img_but.click(idphoto_inference,
209
- inputs=[img_input, mode_options, size_list_options, color_options, render_options,
210
- custom_color_R, custom_color_G, custom_color_B,
211
- custom_size_height, custom_size_wdith],
212
- outputs=[img_output_standard, img_output_standard_hd, img_output_layout, notification])
213
- example_images.click(fn=set_example_image, inputs=[example_images], outputs=[img_input])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
  demo.launch()
 
5
  from src.layoutCreate import generate_layout_photo, generate_layout_image
6
  import pathlib
7
  import numpy as np
8
+ from image_utils import resize_image_to_kb
9
+
10
+ size_list_dict = {
11
+ "一寸": (413, 295),
12
+ "二寸": (626, 413),
13
+ "教师资格证": (413, 295),
14
+ "国家公务员考试": (413, 295),
15
+ "初级会计考试": (413, 295),
16
+ }
17
+ color_list_dict = {
18
+ "蓝色": (86, 140, 212),
19
+ "白色": (255, 255, 255),
20
+ "红色": (233, 51, 35),
21
+ }
22
 
23
 
24
  # 设置Gradio examples
 
36
  return value
37
 
38
 
39
+ def idphoto_inference(
40
+ input_image,
41
+ mode_option,
42
+ size_list_option,
43
+ color_option,
44
+ render_option,
45
+ image_kb_options,
46
+ custom_color_R,
47
+ custom_color_G,
48
+ custom_color_B,
49
+ custom_size_height,
50
+ custom_size_width,
51
+ custom_image_kb,
52
+ head_measure_ratio=0.2,
53
+ head_height_ratio=0.45,
54
+ top_distance_max=0.12,
55
+ top_distance_min=0.10,
56
+ ):
57
 
58
  idphoto_json = {
59
  "size_mode": mode_option,
60
  "color_mode": color_option,
61
  "render_mode": render_option,
62
+ "image_kb_mode": image_kb_options,
63
  }
64
 
65
  # 如果尺寸模式选择的是尺寸列表
 
69
  elif idphoto_json["size_mode"] == "自定义尺寸":
70
  id_height = int(custom_size_height)
71
  id_width = int(custom_size_width)
72
+ if (
73
+ id_height < id_width
74
+ or min(id_height, id_width) < 100
75
+ or max(id_height, id_width) > 1800
76
+ ):
77
  return {
78
  img_output_standard: gr.update(value=None),
79
  img_output_standard_hd: gr.update(value=None),
80
+ notification: gr.update(
81
+ value="宽度应不大于长度;长宽不应小于100,大于1800", visible=True
82
+ ),
83
+ }
84
  idphoto_json["size"] = (id_height, id_width)
85
  else:
86
  idphoto_json["size"] = (None, None)
87
 
88
  # 如果颜色模式选择的是自定义底色
89
  if idphoto_json["color_mode"] == "自定义底色":
90
+ idphoto_json["color_bgr"] = (
91
+ range_check(custom_color_R),
92
+ range_check(custom_color_G),
93
+ range_check(custom_color_B),
94
+ )
95
  else:
96
  idphoto_json["color_bgr"] = color_list_dict[color_option]
97
 
98
+ # 如果输出KB大小选择的是自定义
99
+ if idphoto_json["image_kb_mode"] == "自定义":
100
+ idphoto_json["custom_image_kb"] = custom_image_kb
101
+ else:
102
+ idphoto_json["custom_image_kb"] = None
103
+
104
+ # 生成证件照
105
+ (
106
+ result_image_hd,
107
+ result_image_standard,
108
+ typography_arr,
109
+ typography_rotate,
110
+ _,
111
+ _,
112
+ _,
113
+ _,
114
+ status,
115
+ ) = IDphotos_create(
116
+ input_image,
117
+ mode=idphoto_json["size_mode"],
118
+ size=idphoto_json["size"],
119
+ head_measure_ratio=head_measure_ratio,
120
+ head_height_ratio=head_height_ratio,
121
+ align=False,
122
+ beauty=False,
123
+ fd68=None,
124
+ human_sess=sess,
125
+ IS_DEBUG=False,
126
+ top_distance_max=top_distance_max,
127
+ top_distance_min=top_distance_min,
128
+ )
129
 
130
  # 如果检测到人脸数量不等于1
131
  if status == 0:
132
  result_messgae = {
133
  img_output_standard: gr.update(value=None),
134
  img_output_standard_hd: gr.update(value=None),
135
+ notification: gr.update(value="人脸数量不等于1", visible=True),
136
  }
137
 
138
  # 如果检测到人脸数量等于1
139
  else:
140
  if idphoto_json["render_mode"] == "纯色":
141
  result_image_standard = np.uint8(
142
+ add_background(result_image_standard, bgr=idphoto_json["color_bgr"])
143
+ )
144
+ result_image_hd = np.uint8(
145
+ add_background(result_image_hd, bgr=idphoto_json["color_bgr"])
146
+ )
147
  elif idphoto_json["render_mode"] == "上下渐变(白)":
148
  result_image_standard = np.uint8(
149
+ add_background(
150
+ result_image_standard,
151
+ bgr=idphoto_json["color_bgr"],
152
+ mode="updown_gradient",
153
+ )
154
+ )
155
  result_image_hd = np.uint8(
156
+ add_background(
157
+ result_image_hd,
158
+ bgr=idphoto_json["color_bgr"],
159
+ mode="updown_gradient",
160
+ )
161
+ )
162
  else:
163
  result_image_standard = np.uint8(
164
+ add_background(
165
+ result_image_standard,
166
+ bgr=idphoto_json["color_bgr"],
167
+ mode="center_gradient",
168
+ )
169
+ )
170
  result_image_hd = np.uint8(
171
+ add_background(
172
+ result_image_hd,
173
+ bgr=idphoto_json["color_bgr"],
174
+ mode="center_gradient",
175
+ )
176
+ )
177
 
178
  if idphoto_json["size_mode"] == "只换底":
179
  result_layout_image = gr.update(visible=False)
180
  else:
181
+ typography_arr, typography_rotate = generate_layout_photo(
182
+ input_height=idphoto_json["size"][0],
183
+ input_width=idphoto_json["size"][1],
184
+ )
185
+
186
+ result_layout_image = generate_layout_image(
187
+ result_image_standard,
188
+ typography_arr,
189
+ typography_rotate,
190
+ height=idphoto_json["size"][0],
191
+ width=idphoto_json["size"][1],
192
+ )
193
+
194
+ # 如果输出KB大小选择的是自定义
195
+ if idphoto_json["custom_image_kb"]:
196
+ # 将标准照大小调整至目标大小
197
+ print("调整kb大小到", idphoto_json["custom_image_kb"], "kb")
198
+ # 输出路径为一个根据时间戳+哈希值生成的随机文件名
199
+ import time
200
+
201
+ output_image_path = f"./output/{int(time.time())}.jpg"
202
+ resize_image_to_kb(
203
+ result_image_standard,
204
+ output_image_path,
205
+ idphoto_json["custom_image_kb"],
206
+ )
207
+ else:
208
+ output_image_path = None
209
+
210
+ if output_image_path:
211
+ result_messgae = {
212
+ img_output_standard: result_image_standard,
213
+ img_output_standard_hd: result_image_hd,
214
+ img_output_layout: result_layout_image,
215
+ notification: gr.update(visible=False),
216
+ file_download: gr.update(visible=True, value=output_image_path),
217
+ }
218
+ else:
219
+ result_messgae = {
220
+ img_output_standard: result_image_standard,
221
+ img_output_standard_hd: result_image_hd,
222
+ img_output_layout: result_layout_image,
223
+ notification: gr.update(visible=False),
224
+ file_download: gr.update(visible=False),
225
+ }
226
 
227
  return result_messgae
228
 
229
 
230
  if __name__ == "__main__":
231
+ # 预加载ONNX模型
232
  HY_HUMAN_MATTING_WEIGHTS_PATH = "./hivision_modnet.onnx"
233
  sess = onnxruntime.InferenceSession(HY_HUMAN_MATTING_WEIGHTS_PATH)
234
+
235
  size_mode = ["尺寸列表", "只换底", "自定义尺寸"]
236
  size_list = ["一寸", "二寸", "教师资格证", "国家公务员考试", "初级会计考试"]
237
  colors = ["蓝色", "白色", "红色", "自定义底色"]
238
  render = ["纯色", "上下渐变(白)", "中心渐变(白)"]
239
+ image_kb = ["不设置", "自定义"]
240
 
241
  title = "<h1 id='title'>HivisionIDPhotos</h1>"
242
+ description = "<h3>😎9.2更新:新增照片大小KB调整</h3>"
243
+ css = """
244
  h1#title, h3 {
245
  text-align: center;
246
  }
247
+ """
248
 
249
  demo = gr.Blocks(css=css)
250
 
 
252
  gr.Markdown(title)
253
  gr.Markdown(description)
254
  with gr.Row():
255
+ # ------------ 左半边UI ----------------
256
  with gr.Column():
257
  img_input = gr.Image().style(height=350)
258
+ mode_options = gr.Radio(
259
+ choices=size_mode,
260
+ label="证件照尺寸选项",
261
+ value="尺寸列表",
262
+ elem_id="size",
263
+ )
264
  # 预设尺寸下拉菜单
265
  with gr.Row(visible=True) as size_list_row:
266
+ size_list_options = gr.Dropdown(
267
+ choices=size_list,
268
+ label="预设尺寸",
269
+ value="一寸",
270
+ elem_id="size_list",
271
+ )
272
 
273
  with gr.Row(visible=False) as custom_size:
274
+ custom_size_height = gr.Number(
275
+ value=413, label="height", interactive=True
276
+ )
277
+ custom_size_wdith = gr.Number(
278
+ value=295, label="width", interactive=True
279
+ )
280
+
281
+ # 左:背景色选项
282
+ color_options = gr.Radio(
283
+ choices=colors, label="背景色", value="蓝色", elem_id="color"
284
+ )
285
+
286
+ # 左:如果选择「自定义底色」,显示RGB输入框
287
  with gr.Row(visible=False) as custom_color:
288
  custom_color_R = gr.Number(value=0, label="R", interactive=True)
289
  custom_color_G = gr.Number(value=0, label="G", interactive=True)
290
  custom_color_B = gr.Number(value=0, label="B", interactive=True)
291
 
292
+ # 左:渲染方式选项
293
+ render_options = gr.Radio(
294
+ choices=render,
295
+ label="渲染方式",
296
+ value="纯色",
297
+ elem_id="render",
298
+ )
299
+
300
+ # 左:输出KB大小选项
301
+ image_kb_options = gr.Radio(
302
+ choices=image_kb,
303
+ label="设置KB大小(结果在右边最底的组件下载)",
304
+ value="不设置",
305
+ elem_id="image_kb",
306
+ )
307
+
308
+ # 自定义KB大小, 滑动条,最小10KB,最大200KB
309
+ with gr.Row(visible=False) as custom_image_kb:
310
+ custom_image_kb_size = gr.Slider(
311
+ minimum=10,
312
+ maximum=1000,
313
+ value=50,
314
+ label="KB大小",
315
+ interactive=True,
316
+ )
317
+
318
+ img_but = gr.Button("开始制作")
319
 
 
320
  # 案例图片
321
+ example_images = gr.Dataset(
322
+ components=[img_input],
323
+ samples=[
324
+ [path.as_posix()]
325
+ for path in sorted(pathlib.Path("images").rglob("*.jpg"))
326
+ ],
327
+ )
328
+
329
+ # ---------------- 右半边UI ----------------
330
  with gr.Column():
331
  notification = gr.Text(label="状态", visible=False)
332
  with gr.Row():
333
  img_output_standard = gr.Image(label="标准照").style(height=350)
334
  img_output_standard_hd = gr.Image(label="高清照").style(height=350)
335
  img_output_layout = gr.Image(label="六寸排版照").style(height=350)
336
+ file_download = gr.File(label="下载调整KB大小后的照片", visible=False)
337
 
338
+ # ---------------- 设置隐藏/显示组件 ----------------
339
  def change_color(colors):
340
  if colors == "自定义底色":
341
  return {custom_color: gr.update(visible=True)}
 
344
 
345
  def change_size_mode(size_option_item):
346
  if size_option_item == "自定义尺寸":
347
+ return {
348
+ custom_size: gr.update(visible=True),
349
+ size_list_row: gr.update(visible=False),
350
+ }
351
  elif size_option_item == "只换底":
352
+ return {
353
+ custom_size: gr.update(visible=False),
354
+ size_list_row: gr.update(visible=False),
355
+ }
356
+ else:
357
+ return {
358
+ custom_size: gr.update(visible=False),
359
+ size_list_row: gr.update(visible=True),
360
+ }
361
+
362
+ def change_image_kb(image_kb_option):
363
+ if image_kb_option == "自定义":
364
+ return {custom_image_kb: gr.update(visible=True)}
365
  else:
366
+ return {custom_image_kb: gr.update(visible=False)}
367
+
368
+ # ---------------- 绑定事件 ----------------
369
+ color_options.input(
370
+ change_color, inputs=[color_options], outputs=[custom_color]
371
+ )
372
+
373
+ mode_options.input(
374
+ change_size_mode,
375
+ inputs=[mode_options],
376
+ outputs=[custom_size, size_list_row],
377
+ )
378
+
379
+ image_kb_options.input(
380
+ change_image_kb, inputs=[image_kb_options], outputs=[custom_image_kb]
381
+ )
382
+
383
+ img_but.click(
384
+ idphoto_inference,
385
+ inputs=[
386
+ img_input,
387
+ mode_options,
388
+ size_list_options,
389
+ color_options,
390
+ render_options,
391
+ image_kb_options,
392
+ custom_color_R,
393
+ custom_color_G,
394
+ custom_color_B,
395
+ custom_size_height,
396
+ custom_size_wdith,
397
+ custom_image_kb_size,
398
+ ],
399
+ outputs=[
400
+ img_output_standard,
401
+ img_output_standard_hd,
402
+ img_output_layout,
403
+ notification,
404
+ file_download,
405
+ ],
406
+ )
407
+
408
+ example_images.click(
409
+ fn=set_example_image, inputs=[example_images], outputs=[img_input]
410
+ )
411
 
412
  demo.launch()
image_utils.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ import io
3
+ import numpy as np
4
+
5
+
6
+ def resize_image_to_kb(input_image: np.ndarray, output_image_path, target_size_kb):
7
+ """
8
+ Resize an image to a target size in KB.
9
+ 将图像调整大小至目标文件大小(KB)。
10
+
11
+ :param input_image_path: Path to the input image. 输入图像的路径。
12
+ :param output_image_path: Path to save the resized image. 保存调整大小后的图像的路径。
13
+ :param target_size_kb: Target size in KB. 目标文件大小(KB)。
14
+
15
+ Example:
16
+ resize_image_to_kb('input_image.jpg', 'output_image.jpg', 50)
17
+ """
18
+
19
+ # Open an image file
20
+ with Image.fromarray(input_image) as img:
21
+ # Convert image to RGB mode if it's not
22
+ if img.mode != "RGB":
23
+ img = img.convert("RGB")
24
+
25
+ # Initial quality value
26
+ quality = 95
27
+
28
+ while True:
29
+ # Create a BytesIO object to hold the image data in memory
30
+ img_byte_arr = io.BytesIO()
31
+
32
+ # Save the image to the BytesIO object with the current quality
33
+ img.save(img_byte_arr, format="JPEG", quality=quality)
34
+
35
+ # Get the size of the image in KB
36
+ img_size_kb = len(img_byte_arr.getvalue()) / 1024
37
+
38
+ # Check if the image size is within the target size
39
+ if img_size_kb <= target_size_kb:
40
+ # If the image is smaller than the target size, add padding
41
+ if img_size_kb < target_size_kb:
42
+ padding_size = int(
43
+ (target_size_kb * 1024) - len(img_byte_arr.getvalue())
44
+ )
45
+ padding = b"\x00" * padding_size
46
+ img_byte_arr.write(padding)
47
+
48
+ # Save the image to the output path
49
+ with open(output_image_path, "wb") as f:
50
+ f.write(img_byte_arr.getvalue())
51
+ break
52
+
53
+ # Reduce the quality if the image is still too large
54
+ quality -= 5
55
+
56
+ # Ensure quality does not go below 1
57
+ if quality < 1:
58
+ quality = 1
output/.gitkeep ADDED
File without changes