Rzx008 commited on
Commit
685b61f
verified
1 Parent(s): 785585e

Create iphone.py

Browse files
Files changed (1) hide show
  1. iphone.py +238 -0
iphone.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import pytesseract
3
+ from PIL import Image, ImageDraw, ImageFont
4
+ import numpy as np
5
+ import argparse
6
+ import io
7
+ import base64
8
+
9
+ class AndroidEditor:
10
+ def __init__(self, font_path="Roboto-Regular.ttf"):
11
+ self.font_path = font_path
12
+
13
+ @staticmethod
14
+ def find_text_position(text_list, target_text, start_idx=0):
15
+ """Mencari posisi teks target dalam list teks"""
16
+ for i in range(start_idx, len(text_list)):
17
+ if target_text in text_list[i]:
18
+ return i
19
+ return None
20
+
21
+ @staticmethod
22
+ def get_position_data(extracted_data, idx):
23
+ """Mendapatkan data posisi dari indeks tertentu"""
24
+ if idx is None or idx >= len(extracted_data['left']):
25
+ return None
26
+ return {
27
+ "left": extracted_data['left'][idx],
28
+ "top": extracted_data['top'][idx],
29
+ "width": extracted_data['width'][idx],
30
+ "height": extracted_data['height'][idx],
31
+ }
32
+
33
+ @staticmethod
34
+ def is_dark_mode(bg_color):
35
+ """Mendeteksi apakah background menggunakan dark mode berdasarkan kecerahan warna"""
36
+ r, g, b = float(bg_color[0]), float(bg_color[1]), float(bg_color[2])
37
+ brightness = (r * 299 + g * 587 + b * 114) / 1000
38
+ return brightness < 128
39
+
40
+ def process_image(self, image_path, anggota):
41
+ image = cv2.imread(image_path)
42
+ if image is None:
43
+ return
44
+ result = self._process_core(image, anggota, show_preview=True)
45
+ return result
46
+
47
+ def process_image_bytes(self, image_bytes, anggota):
48
+ image_stream = io.BytesIO(image_bytes)
49
+ pil_image = Image.open(image_stream).convert('RGB')
50
+ image = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
51
+ result, theme = self._process_core(image, anggota, show_preview=False, return_theme=True)
52
+ if result is not None:
53
+ pil_result = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
54
+ output_io = io.BytesIO()
55
+ pil_result.save(output_io, format='PNG')
56
+ img_b64 = base64.b64encode(output_io.getvalue()).decode('utf-8')
57
+ return img_b64, theme
58
+ return None, None
59
+
60
+ def _process_core(self, image, anggota, show_preview=False, return_theme=False):
61
+ # Ekstrak teks dari gambar
62
+ extracted_data = pytesseract.image_to_data(image, output_type=pytesseract.Output.DICT)
63
+ text_list = extracted_data['text']
64
+
65
+ # Inisialisasi variabel posisi
66
+ group_position = None
67
+ split_position = None
68
+ member_position = None
69
+ member_count_position = None
70
+ second_member_position = None
71
+ second_member_count_position = None
72
+ lang = ''
73
+
74
+ group_idx = self.find_text_position(text_list, "Grup")
75
+ if group_idx is None:
76
+ group_idx = self.find_text_position(text_list, "Group")
77
+
78
+ if group_idx is not None:
79
+ lang = 'id' if "Grup" in text_list[group_idx] else 'en'
80
+ group_position = self.get_position_data(extracted_data, group_idx)
81
+
82
+ split_idx = self.find_text_position(text_list, "路", group_idx)
83
+ if split_idx is None:
84
+ split_idx = self.find_text_position(text_list, "-", group_idx)
85
+ split_position = self.get_position_data(extracted_data, split_idx)
86
+
87
+ member_idx = self.find_text_position(text_list, "anggota", group_idx)
88
+ if member_idx is None:
89
+ member_idx = self.find_text_position(text_list, "member", group_idx)
90
+ member_position = self.get_position_data(extracted_data, member_idx)
91
+
92
+ for i in range(group_idx, min(group_idx + 5, len(text_list))):
93
+ if text_list[i].isdigit():
94
+ member_count_position = self.get_position_data(extracted_data, i)
95
+ break
96
+
97
+ second_member_idx = self.find_text_position(text_list, "Anggota", group_idx + 4)
98
+ if second_member_idx is not None:
99
+ second_member_position = self.get_position_data(extracted_data, second_member_idx)
100
+ for i in range(second_member_idx - 3, second_member_idx):
101
+ if i >= 0 and text_list[i].isdigit():
102
+ second_member_count_position = self.get_position_data(extracted_data, i)
103
+ break
104
+ else:
105
+ return None
106
+
107
+ if member_position is None:
108
+ return None
109
+
110
+ x = member_position['left'] + member_position['width'] + 100
111
+ y = member_position['top'] + member_position['height'] - 100
112
+ bg_color = image[y, x]
113
+ rgb = (int(bg_color[0]), int(bg_color[1]), int(bg_color[2]))
114
+
115
+ is_dark = self.is_dark_mode(bg_color)
116
+ theme = 'Dark Mode' if is_dark else 'Light Mode'
117
+ text_color = (147,151,154,255) if is_dark else (90, 94, 95, 255)
118
+
119
+ for position in [group_position, split_position, member_position, member_count_position,
120
+ second_member_position, second_member_count_position]:
121
+ if position:
122
+ margin_horizontal = 100
123
+ cv2.rectangle(
124
+ image,
125
+ (position['left'] - margin_horizontal, position['top']),
126
+ (position['left'] + position['width'] + margin_horizontal, position['top'] + position['height']),
127
+ rgb,
128
+ -1,
129
+ )
130
+
131
+ if member_count_position:
132
+ updated_member_count = {
133
+ 'id': f"Grup 路 {anggota} anggota",
134
+ 'en': f"Group 路 {anggota} members"
135
+ }.get(lang)
136
+
137
+ original_height = member_count_position['height']
138
+ original_width = member_count_position['width']
139
+
140
+ font_size = int(original_height * 2.0)
141
+ font = ImageFont.truetype(self.font_path, font_size)
142
+
143
+ image_pil = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
144
+ draw = ImageDraw.Draw(image_pil)
145
+
146
+ min_size = int(original_height * 1.5)
147
+ max_size = int(original_height * 2.5)
148
+ max_iterations = 10
149
+ iteration = 0
150
+
151
+ while min_size <= max_size and iteration < max_iterations:
152
+ font = ImageFont.truetype(self.font_path, font_size)
153
+ text_bbox = draw.textbbox((0, 0), updated_member_count, font=font)
154
+ text_height = text_bbox[3] - text_bbox[1]
155
+ text_width = text_bbox[2] - text_bbox[0]
156
+
157
+ if abs(text_height - original_height) <= 2 and text_width <= original_width * 1.5:
158
+ break
159
+
160
+ if text_height > original_height or text_width > original_width * 1.5:
161
+ font_size = int(font_size * 0.95)
162
+ else:
163
+ font_size = int(font_size * 1.05)
164
+
165
+ font_size = max(min_size, min(max_size, font_size))
166
+ iteration += 1
167
+
168
+ text_width = text_bbox[2] - text_bbox[0]
169
+ image_width = image.shape[1]
170
+ text_x = (image_width - text_width) // 2
171
+ text_y = member_count_position['top'] - 2
172
+
173
+ draw.text((text_x, text_y), updated_member_count, font=font, fill=text_color)
174
+ image = cv2.cvtColor(np.array(image_pil), cv2.COLOR_RGB2BGR)
175
+
176
+ if second_member_count_position:
177
+ updated_second_member_count = {
178
+ 'id': f"{anggota} Anggota",
179
+ 'en': f"{anggota} Members"
180
+ }.get(lang)
181
+
182
+ original_height = second_member_count_position['height']
183
+ original_width = second_member_count_position['width']
184
+
185
+ font_size = int(original_height * 2.0)
186
+ font = ImageFont.truetype(self.font_path, font_size)
187
+
188
+ image_pil = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
189
+ draw = ImageDraw.Draw(image_pil)
190
+
191
+ min_size = int(original_height * 1.5)
192
+ max_size = int(original_height * 2.5)
193
+ max_iterations = 10
194
+ iteration = 0
195
+
196
+ while min_size <= max_size and iteration < max_iterations:
197
+ font = ImageFont.truetype(self.font_path, font_size)
198
+ text_bbox = draw.textbbox((0, 0), updated_second_member_count, font=font)
199
+ text_height = text_bbox[3] - text_bbox[1]
200
+ text_width = text_bbox[2] - text_bbox[0]
201
+
202
+ if abs(text_height - original_height) <= 2 and text_width <= original_width * 1.5:
203
+ break
204
+
205
+ if text_height > original_height or text_width > original_width * 1.5:
206
+ font_size = int(font_size * 0.95)
207
+ else:
208
+ font_size = int(font_size * 1.05)
209
+
210
+ font_size = max(min_size, min(max_size, font_size))
211
+ iteration += 1
212
+
213
+ text_width = text_bbox[2] - text_bbox[0]
214
+ text_x = second_member_count_position['left']
215
+ text_y = second_member_count_position['top'] - 2
216
+
217
+ draw.text((text_x, text_y), updated_second_member_count, font=font, fill=text_color)
218
+ image = cv2.cvtColor(np.array(image_pil), cv2.COLOR_RGB2BGR)
219
+
220
+ if show_preview:
221
+ cv2.imshow('Preview (Tekan q untuk keluar)', image)
222
+ while True:
223
+ key = cv2.waitKey(1) & 0xFF
224
+ if key == ord('q'):
225
+ break
226
+ cv2.destroyAllWindows()
227
+ if return_theme:
228
+ return image, theme
229
+ return image
230
+
231
+ if __name__ == '__main__':
232
+ parser = argparse.ArgumentParser(description='Proses gambar grup')
233
+ parser.add_argument('image_path', help='Path ke file gambar')
234
+ parser.add_argument('anggota', help='Jumlah anggota')
235
+
236
+ args = parser.parse_args()
237
+ editor = AndroidEditor()
238
+ editor.process_image(args.image_path, args.anggota)