xython 4.3.9__tar.gz → 4.3.10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {xython-4.3.9/src/xython.egg-info → xython-4.3.10}/PKG-INFO +1 -1
- {xython-4.3.9 → xython-4.3.10}/pyproject.toml +1 -1
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_color.py +174 -10
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_edge.py +35 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_excel.py +403 -128
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_outlook.py +569 -87
- xython-4.3.10/src/xython/xy_re.py +1041 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_time.py +181 -25
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_util.py +255 -59
- {xython-4.3.9 → xython-4.3.10/src/xython.egg-info}/PKG-INFO +1 -1
- xython-4.3.9/src/xython/xy_re.py +0 -1097
- {xython-4.3.9 → xython-4.3.10}/MANIFEST.in +0 -0
- {xython-4.3.9 → xython-4.3.10}/README.md +0 -0
- {xython-4.3.9 → xython-4.3.10}/requirements.txt +0 -0
- {xython-4.3.9 → xython-4.3.10}/setup.cfg +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/__init__.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_auto.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_chrome.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_common.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_db.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_excel_event.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_hwp.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_list.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_map.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython/xy_word.py +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython.egg-info/SOURCES.txt +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython.egg-info/dependency_links.txt +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython.egg-info/requires.txt +0 -0
- {xython-4.3.9 → xython-4.3.10}/src/xython.egg-info/top_level.txt +0 -0
|
@@ -1210,7 +1210,7 @@ class xy_color:
|
|
|
1210
1210
|
return result
|
|
1211
1211
|
|
|
1212
1212
|
def rgb_to_hex(self, input_rgb, option="#"):
|
|
1213
|
-
return change_rgb_to_hex(input_rgb, option)
|
|
1213
|
+
return self.change_rgb_to_hex(input_rgb, option)
|
|
1214
1214
|
|
|
1215
1215
|
def change_rgb_to_hex(self, input_rgb, option="#"):
|
|
1216
1216
|
"""
|
|
@@ -1406,15 +1406,8 @@ class xy_color:
|
|
|
1406
1406
|
return result
|
|
1407
1407
|
|
|
1408
1408
|
def change_xcolor_to_hex(self, input_xcolor):
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
xcolor형식 : 12, "red", "red45", "red++"
|
|
1412
|
-
|
|
1413
|
-
:param input_xcolor: solor형태의 색깔입력, (12, "red", "red45", "red++")
|
|
1414
|
-
:return:
|
|
1415
|
-
"""
|
|
1416
|
-
my_rgb_color = self.change_xcolor_to_rgb(input_xcolor)
|
|
1417
|
-
result = self.xcolor_alpha_to_rgba(my_rgb_color)
|
|
1409
|
+
rgb = self.change_xcolor_to_rgb(input_xcolor)
|
|
1410
|
+
result = self.change_rgb_to_hex(rgb)
|
|
1418
1411
|
return result
|
|
1419
1412
|
|
|
1420
1413
|
def change_xcolor_to_hsl(self, input_xcolor):
|
|
@@ -2504,3 +2497,174 @@ class xy_color:
|
|
|
2504
2497
|
"""
|
|
2505
2498
|
return self.xcolor_to_rgbint(input_xcolor)
|
|
2506
2499
|
|
|
2500
|
+
def get_text_color_for_background(self, bg_rgb):
|
|
2501
|
+
"""
|
|
2502
|
+
배경색이 주어지면 텍스트를 흰색/검정 중 어느 쪽으로 할지 자동 결정
|
|
2503
|
+
WCAG 명도 기준 사용
|
|
2504
|
+
"""
|
|
2505
|
+
r, g, b = [x / 255 for x in bg_rgb]
|
|
2506
|
+
luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
2507
|
+
return [255, 255, 255] if luminance < 0.5 else [0, 0, 0]
|
|
2508
|
+
|
|
2509
|
+
def get_contrast_ratio(self, rgb1, rgb2):
|
|
2510
|
+
"""
|
|
2511
|
+
두 색의 WCAG 명암비 계산 (1~21)
|
|
2512
|
+
4.5 이상이면 텍스트로 사용 가능 (AA 기준)
|
|
2513
|
+
"""
|
|
2514
|
+
def lum(rgb):
|
|
2515
|
+
c = [x / 255 for x in rgb]
|
|
2516
|
+
c = [x / 12.92 if x <= 0.04045 else ((x + 0.055) / 1.055) ** 2.4 for x in c]
|
|
2517
|
+
return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]
|
|
2518
|
+
l1, l2 = lum(rgb1), lum(rgb2)
|
|
2519
|
+
lighter, darker = max(l1, l2), min(l1, l2)
|
|
2520
|
+
return round((lighter + 0.05) / (darker + 0.05), 2)
|
|
2521
|
+
|
|
2522
|
+
def hex_to_rgb(self, hex_color):
|
|
2523
|
+
"""
|
|
2524
|
+
"#ff5733" 또는 "ff5733" → [255, 87, 51]
|
|
2525
|
+
"""
|
|
2526
|
+
hex_color = hex_color.lstrip("#")
|
|
2527
|
+
return [int(hex_color[i:i+2], 16) for i in (0, 2, 4)]
|
|
2528
|
+
|
|
2529
|
+
def hex_to_hsl(self, hex_color):
|
|
2530
|
+
"""
|
|
2531
|
+
hex → hsl 직접 변환
|
|
2532
|
+
"""
|
|
2533
|
+
return self.rgb_to_hsl(self.hex_to_rgb(hex_color))
|
|
2534
|
+
|
|
2535
|
+
def rgb_to_cmyk(self, input_rgb):
|
|
2536
|
+
"""
|
|
2537
|
+
RGB → CMYK 변환 (인쇄용)
|
|
2538
|
+
반환: [c, m, y, k] (0~100 정수)
|
|
2539
|
+
"""
|
|
2540
|
+
r, g, b = [x / 255 for x in input_rgb]
|
|
2541
|
+
k = 1 - max(r, g, b)
|
|
2542
|
+
if k == 1:
|
|
2543
|
+
return [0, 0, 0, 100]
|
|
2544
|
+
c = (1 - r - k) / (1 - k)
|
|
2545
|
+
m = (1 - g - k) / (1 - k)
|
|
2546
|
+
y = (1 - b - k) / (1 - k)
|
|
2547
|
+
return [round(c*100), round(m*100), round(y*100), round(k*100)]
|
|
2548
|
+
|
|
2549
|
+
def cmyk_to_rgb(self, c, m, y, k):
|
|
2550
|
+
"""
|
|
2551
|
+
CMYK → RGB 변환
|
|
2552
|
+
입력: 0~100 정수
|
|
2553
|
+
"""
|
|
2554
|
+
c, m, y, k = c/100, m/100, y/100, k/100
|
|
2555
|
+
r = int(255 * (1 - c) * (1 - k))
|
|
2556
|
+
g = int(255 * (1 - m) * (1 - k))
|
|
2557
|
+
b = int(255 * (1 - y) * (1 - k))
|
|
2558
|
+
return [r, g, b]
|
|
2559
|
+
|
|
2560
|
+
def rgb_to_hsv(self, input_rgb):
|
|
2561
|
+
"""
|
|
2562
|
+
RGB → HSV 변환 (포토샵 등에서 사용하는 방식)
|
|
2563
|
+
반환: [h(0~360), s(0~100), v(0~100)]
|
|
2564
|
+
"""
|
|
2565
|
+
r, g, b = [x / 255 for x in input_rgb]
|
|
2566
|
+
mx, mn = max(r, g, b), min(r, g, b)
|
|
2567
|
+
v = mx
|
|
2568
|
+
s = 0 if mx == 0 else (mx - mn) / mx
|
|
2569
|
+
if mx == mn:
|
|
2570
|
+
h = 0
|
|
2571
|
+
elif mx == r:
|
|
2572
|
+
h = (60 * ((g - b) / (mx - mn))) % 360
|
|
2573
|
+
elif mx == g:
|
|
2574
|
+
h = 60 * ((b - r) / (mx - mn)) + 120
|
|
2575
|
+
else:
|
|
2576
|
+
h = 60 * ((r - g) / (mx - mn)) + 240
|
|
2577
|
+
return [round(h), round(s * 100), round(v * 100)]
|
|
2578
|
+
|
|
2579
|
+
def get_analogous_colors(self, input_xcolor, angle=30, count=2):
|
|
2580
|
+
"""
|
|
2581
|
+
유사색 생성 (색상환에서 ±angle도 이내의 색)
|
|
2582
|
+
count=2이면 양쪽 1개씩, count=4이면 양쪽 2개씩
|
|
2583
|
+
반환: [[rgb...], ...]
|
|
2584
|
+
"""
|
|
2585
|
+
hsl = self._change_xcolor_to_hsl(input_xcolor)
|
|
2586
|
+
result = []
|
|
2587
|
+
for i in range(1, count // 2 + 1):
|
|
2588
|
+
for sign in [-1, 1]:
|
|
2589
|
+
new_h = (hsl[0] + sign * angle * i) % 360
|
|
2590
|
+
result.append(self.hsl_to_rgb([new_h, hsl[1], hsl[2]]))
|
|
2591
|
+
return result
|
|
2592
|
+
|
|
2593
|
+
def get_triadic_colors(self, input_xcolor):
|
|
2594
|
+
"""
|
|
2595
|
+
3색 배색 (120도 간격)
|
|
2596
|
+
"""
|
|
2597
|
+
hsl = self._change_xcolor_to_hsl(input_xcolor)
|
|
2598
|
+
return [self.hsl_to_rgb([(hsl[0] + i * 120) % 360, hsl[1], hsl[2]]) for i in range(3)]
|
|
2599
|
+
|
|
2600
|
+
def get_split_complementary_colors(self, input_xcolor, angle=150):
|
|
2601
|
+
"""
|
|
2602
|
+
분리 보색 (보색에서 ±30도)
|
|
2603
|
+
"""
|
|
2604
|
+
hsl = self._change_xcolor_to_hsl(input_xcolor)
|
|
2605
|
+
h = hsl[0]
|
|
2606
|
+
return [
|
|
2607
|
+
self.hsl_to_rgb([h, hsl[1], hsl[2]]),
|
|
2608
|
+
self.hsl_to_rgb([(h + angle) % 360, hsl[1], hsl[2]]),
|
|
2609
|
+
self.hsl_to_rgb([(h - angle) % 360, hsl[1], hsl[2]]),
|
|
2610
|
+
]
|
|
2611
|
+
|
|
2612
|
+
def get_monochromatic_colors(self, input_xcolor, count=5):
|
|
2613
|
+
"""
|
|
2614
|
+
단색 배색: 같은 색상(H)에서 명도만 달리한 count개 색
|
|
2615
|
+
"""
|
|
2616
|
+
hsl = self._change_xcolor_to_hsl(input_xcolor)
|
|
2617
|
+
step = 100 // (count + 1)
|
|
2618
|
+
return [self.hsl_to_rgb([hsl[0], hsl[1], step * (i + 1)]) for i in range(count)]
|
|
2619
|
+
|
|
2620
|
+
def is_dark_color(self, input_rgb):
|
|
2621
|
+
"""
|
|
2622
|
+
어두운 색인지 여부 (True/False)
|
|
2623
|
+
luminance 0.5 기준
|
|
2624
|
+
"""
|
|
2625
|
+
r, g, b = [x / 255 for x in input_rgb]
|
|
2626
|
+
luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
2627
|
+
return luminance < 0.5
|
|
2628
|
+
|
|
2629
|
+
def is_warm_color(self, input_rgb):
|
|
2630
|
+
"""
|
|
2631
|
+
따뜻한 색(빨강~노랑 계열)인지 여부
|
|
2632
|
+
HSL 기준 H가 0~60 또는 300~360이면 따뜻한 색
|
|
2633
|
+
"""
|
|
2634
|
+
hsl = self.rgb_to_hsl(input_rgb)
|
|
2635
|
+
h = hsl[0]
|
|
2636
|
+
return h <= 60 or h >= 300
|
|
2637
|
+
|
|
2638
|
+
def get_color_temperature(self, input_rgb):
|
|
2639
|
+
"""
|
|
2640
|
+
색 온도 분류 반환: "warm" / "cool" / "neutral"
|
|
2641
|
+
"""
|
|
2642
|
+
hsl = self.rgb_to_hsl(input_rgb)
|
|
2643
|
+
h = hsl[0]
|
|
2644
|
+
if h <= 60 or h >= 300:
|
|
2645
|
+
return "warm"
|
|
2646
|
+
elif 150 <= h <= 270:
|
|
2647
|
+
return "cool"
|
|
2648
|
+
else:
|
|
2649
|
+
return "neutral"
|
|
2650
|
+
|
|
2651
|
+
def get_color_info(self, input_rgb):
|
|
2652
|
+
"""
|
|
2653
|
+
RGB 색상의 종합 정보를 딕셔너리로 반환
|
|
2654
|
+
{"rgb", "hsl", "hsv", "hex", "cmyk", "is_dark", "temperature"}
|
|
2655
|
+
"""
|
|
2656
|
+
return {
|
|
2657
|
+
"rgb": input_rgb,
|
|
2658
|
+
"hsl": self.rgb_to_hsl(input_rgb),
|
|
2659
|
+
"hsv": self.rgb_to_hsv(input_rgb),
|
|
2660
|
+
"hex": self.change_rgb_to_hex(input_rgb),
|
|
2661
|
+
"cmyk": self.rgb_to_cmyk(input_rgb),
|
|
2662
|
+
"is_dark": self.is_dark_color(input_rgb),
|
|
2663
|
+
"temperature": self.get_color_temperature(input_rgb),
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
|
|
2667
|
+
|
|
2668
|
+
|
|
2669
|
+
|
|
2670
|
+
|
|
@@ -2955,3 +2955,38 @@ class xy_edge:
|
|
|
2955
2955
|
else:
|
|
2956
2956
|
print("❌ PDF 데이터를 생성하지 못했습니다.")
|
|
2957
2957
|
|
|
2958
|
+
|
|
2959
|
+
def write_by_xpath(self, xpath: str, value: str) -> bool:
|
|
2960
|
+
try:
|
|
2961
|
+
element = self.page.ele(f'xpath:{xpath}')
|
|
2962
|
+
|
|
2963
|
+
if element is None:
|
|
2964
|
+
print(f"[ERROR] 요소를 찾을 수 없습니다: {xpath}")
|
|
2965
|
+
return False
|
|
2966
|
+
|
|
2967
|
+
element.clear() # 기존 내용 초기화
|
|
2968
|
+
element.input(value) # 값 입력
|
|
2969
|
+
|
|
2970
|
+
print(f"[OK] 입력 완료")
|
|
2971
|
+
return True
|
|
2972
|
+
|
|
2973
|
+
except Exception as e:
|
|
2974
|
+
print(f"[ERROR] 입력 실패 - {e}")
|
|
2975
|
+
return False
|
|
2976
|
+
|
|
2977
|
+
def write_by_id(self, element_id: str, value: str) -> bool:
|
|
2978
|
+
try:
|
|
2979
|
+
element = self.page.ele(f'#{element_id}')
|
|
2980
|
+
if element is None:
|
|
2981
|
+
print(f"[ERROR] 요소를 찾을 수 없습니다: #{element_id}")
|
|
2982
|
+
return False
|
|
2983
|
+
|
|
2984
|
+
element.clear()
|
|
2985
|
+
element.input(value)
|
|
2986
|
+
|
|
2987
|
+
print(f"[OK] 입력 완료")
|
|
2988
|
+
return True
|
|
2989
|
+
|
|
2990
|
+
except Exception as e:
|
|
2991
|
+
print(f"[ERROR] 입력 실패 - {e}")
|
|
2992
|
+
return False
|