2025, Oct 31 15:02
tkinter और PIL के साथ 900×900 इमेज पर टेक्स्ट को 1/3 और 2/3 पर रखना
जानें कैसे tkinter और PIL/ImageTk में 900×900 इमेज पर टेक्स्ट को 2×2 ग्रिड में रखें: (dimension/2)+1 नहीं, dimension/(n+1) स्टेप से 1/3 व 2/3 पर सटीक पोज़िशनिंग.
tkinter के जरिए दिखाए गए PIL इमेज पर टेक्स्ट को बिल्कुल सही जगह रखना देखने में आसान लगता है, लेकिन गणित इसमें अड़चन डाल देता है। एक सामान्य स्थिति: आप 900×900 की इमेज पर तय अंतरालों पर टेक्स्ट रखना चाहते हैं—उम्मीद है कि बिंदु 300×300, 300×600, 600×300 और 600×600 होंगे। मगर नतीजा यह निकलता है कि सब कुछ केंद्र के आसपास जमा हो जाता है। वजह PIL और ImageTk के कोऑर्डिनेट सिस्टम का फर्क नहीं, बल्कि गणना को समूहित करने का तरीका है।
समस्या की रूपरेखा
नीचे एक संक्षिप्त उदाहरण है जो इमेज के आयामों से स्टेप का हिसाब लगाता है और 2×2 ग्रिड में वही लेबल बनाता है। नाम सामान्य हैं, और यही तर्क गलती भरे प्लेसमेंट तक ले जाता है।
global painter, tk_img
painter = ImageDraw.Draw(pil_img)
face = ImageFont.load_default()
for row in range(1, int(2)+1):
print(tk_img.height() / int(2) + 1)
y_step = (tk_img.height() / int(2) + 1) * row
for col in range(1, int(2)+1):
x_step = (tk_img.width() / int(2) + 1) * col
print(x_step)
painter.text(xy=(x_step, y_step), text="TESTER", fill=(255,255,255), font=face)
tk_img = ImageTk.PhotoImage(pil_img)
image_holder.image = tk_img
image_holder.config(image=tk_img)
असल में गड़बड़ी कहाँ है
समस्या पूरी तरह अंकगणित की है। x और y के लिए जो अभिव्यक्तियाँ हैं, वे 2 से भाग देकर स्टेप बनाती हैं और फिर 1 जोड़ देती हैं। यानी स्टेप (dimension / 2) + 1 के रूप में निकाला जा रहा है। 900×900 इमेज के लिए यह लगभग 451 होता है। जब लूप इस स्टेप को 1 और 2 से गुणा करते हैं, तो हर अक्ष पर निर्देशांक 451 और 902 बनते हैं। इससे कोशिश की गई जगहें (451,451), (451,902), (902,451), (902,902) हो जाती हैं। इनमें सिर्फ पहला बिंदु इमेज के अंदर आता है; बाकी निचली/दाहिनी सीमाओं पर या उनके बाहर पड़ते हैं, इसलिए दिखते नहीं। यह PIL बनाम ImageTk यूनिट्स की समस्या नहीं है; असल कारण ऑपरेशनों को समूहित करने का तरीका है।
इरादा यह था कि जगह को तीन हिस्सों में बाँटा जाए और टेक्स्ट 1/3 और 2/3 पर रखा जाए। इसलिए स्टेप dimension / 3 होना चाहिए, न कि (dimension / 2) + 1. यहाँ +1 भाग देने के बाद नहीं, बल्कि भाजक में होना चाहिए, जो सेगमेंट्स की कुल संख्या तय करता है।
समाधान
कोष्ठक अर्थ बदल देते हैं। जिस संख्या में आप हिस्से करना चाहते हैं, उसी से भाग दें—2 से भाग देकर 1 जोड़ने के बजाय। सही ग्रुपिंग (2 + 1) से भाग देती है, जिससे आयाम का साफ एक-तिहाई मिल जाता है।
global painter, tk_img
painter = ImageDraw.Draw(pil_img)
face = ImageFont.load_default()
for row in range(1, int(2)+1):
y_step = (tk_img.height() / (int(2) + 1)) * row
for col in range(1, int(2)+1):
x_step = (tk_img.width() / (int(2) + 1)) * col
painter.text(xy=(x_step, y_step), text="TESTER", fill=(255,255,255), font=face)
tk_img = ImageTk.PhotoImage(pil_img)
image_holder.image = tk_img
image_holder.config(image=tk_img)
900×900 इमेज पर स्टेप 300 हो जाता है। लूप दोनों अक्षों पर 300 और 600 पर टेक्स्ट रखता है, और अपेक्षित चार स्थान—300×300, 300×600, 600×300 और 600×600—मिल जाते हैं।
यह क्यों मायने रखता है
गणना करते समय ऑपरेटर की प्राथमिकता और ग्रुपिंग ग्राफिक्स में निर्देशांक पर तुरंत असर डालते हैं। कोष्ठक में जरा-सा बदलाव भी सामग्री को ड्रॉएबल एरिया से बाहर पहुँचा सकता है, बिना किसी त्रुटि के संकेत के। GUI स्टैक के शोर में फँसकर tkinter, ImageTk और PIL के बीच यूनिट के फर्क पर शक करना भी आसान है। ऐसे मामलों में दोनों लाइब्रेरी पिक्सेल यूनिट पर सहमत हैं; ध्यान गणित पर होना चाहिए।
एक और व्यावहारिक पहलू है इटरेशन नियंत्रण। अगर लक्ष्य 2×2 लेआउट में चार बार ड्रॉ करना है, तो लूप को हर अक्ष पर ठीक दो स्टेप ही बनाने चाहिए। रेंज बढ़ाने से प्लेसमेंट की संख्या बढ़ती है और कई बिंदु सीमा से बाहर चले जाते हैं। इच्छित विभाजन के अनुसार भाजक को बाँधकर रखना कैनवास से बाहर जाने से बचाता है।
मुख्य बातें
जब किसी इमेज में तत्वों को बाँटना हो, तो हिस्सों में सोचें। अगर 1/3 और 2/3 पर स्थिति चाहिए, तो स्टेप को आयाम को हिस्सों की कुल संख्या से भाग देकर निकालें, फिर इंडेक्स से गुणा करें। भाजक को कोष्ठक के भीतर रखें ताकि आप पूरे विभाजन की संख्या से भाग दें, न कि किसी आंशिक मान में 1 जोड़कर। और हर अक्ष पर जितने प्लेसमेंट चाहिए, लूप की गिनती उसी के अनुरूप रखें।