डेवलपर्स के लिए··5 मिनट में पढ़ें

Bigjpg API ट्यूटोरियल: Python से एक साथ कई इमेज बड़ी करें

चलाने के लिए तैयार स्क्रिप्ट, जो इमेज अपलोड करती है, एनलार्ज टास्क बनाती है, नतीजे पोल करती है और डाउनलोड करती है — साथ में वह कॉन्करेंसी और एरर हैंडलिंग जिससे 500 इमेज का काम बीच में नहीं अटकता।

Bigjpg API ट्यूटोरियल: Python से एक साथ कई इमेज बड़ी करें

कुछ इमेज के लिए वेब इंटरफ़ेस ठीक है। पाँच सौ फ़ाइलों वाले फ़ोल्डर के लिए API बेहतर है: चार endpoint, कोई ब्राउज़र नहीं, और स्क्रिप्ट जब चाहें दोबारा चलाइए। नीचे वही स्क्रिप्ट है जो हम सीधे किसी साथी को देते हैं, उस एरर हैंडलिंग के साथ जो असल में काम आती है।

शुरू करने से पहले

  • API सिर्फ़ पेड अकाउंट के लिए है। सक्रिय प्लान के साथ लॉग इन करने पर आपकी key API पेज पर मिलती है।
  • Python 3 और इंस्टॉल किया हुआ requests। इसके अलावा कुछ नहीं।
  • एनलार्जिंग हमारे worker पर async चलती है, इसलिए स्क्रिप्ट पहले टास्क बनाती है और फिर पोल करती है। 500 इमेज का काम उतना समय लेता है जितना आपकी कतार में सबसे धीमा टास्क लेता है, इमेज की संख्या का जोड़ नहीं।

स्क्रिप्ट

import json
import os
import time
import requests

API = "https://bigjpg.com"
KEY = "YOUR_API_KEY"
STYLE = "art"          # "art" इलस्ट्रेशन के लिए, "photo" तस्वीरों के लिए
NOISE = "1"            # -1 कोई नहीं, 0 कम, 1 मध्यम, 2 ज़्यादा, 3 सबसे ज़्यादा
X2 = "2"               # 1 = 2x, 2 = 4x, 3 = 8x, 4 = 16x
POLL_SECONDS = 8
MAX_RETRY = 1

HEADERS = {"X-API-KEY": KEY}


def upload(path):
    """Get a presigned URL, PUT the file, return its public URL."""
    name = path.split("/")[-1]
    r = requests.post(
        API + "/api/img_upload",
        headers=HEADERS,
        data={"filename": name, "filetype": "image/jpeg"},
        timeout=60,
    )
    info = r.json()
    if info.get("status") != "ok":
        raise RuntimeError("upload failed: " + str(info))

    with open(path, "rb") as image:
        r = requests.put(
            info["url"],
            data=image,
            headers={"Content-Type": "image/jpeg"},
            timeout=300,
        )
    if r.status_code != 200:
        raise RuntimeError("upload failed with HTTP %s" % r.status_code)
    return info["fileurl"]


def create(image_url):
    """Create an enlargement task, return its task id."""
    payload = {
        "style": STYLE,
        "noise": NOISE,
        "x2": X2,
        "input": image_url,
    }
    r = requests.post(
        API + "/api/task/",
        headers=HEADERS,
        data=json.dumps(payload),
        timeout=60,
    )
    data = r.json()
    if "tid" not in data:
        raise RuntimeError("task failed: " + str(data))
    return data["tid"]


def poll(tids):
    """Query up to 100 task ids at once. Returns task id -> result dict."""
    r = requests.get(API + "/api/task/" + ",".join(tids), timeout=60)
    return r.json()


def download(url, out):
    """Download a finished image, checking the transfer really succeeded."""
    r = requests.get(url, timeout=300)
    if r.status_code != 200:
        raise RuntimeError("download failed with HTTP %s" % r.status_code)
    with open(out, "wb") as f:
        f.write(r.content)
    return out


def main(paths):
    pending = {}
    attempts = {}
    for path in paths:
        try:
            tid = create(upload(path))
        except Exception as e:
            print("skipped", path, e)
            continue
        pending[tid] = path
        attempts[tid] = 0
        print("queued", path, tid)

    while pending:
        for tid, info in poll(list(pending)[:100]).items():
            if info.get("status") == "success":
                out = os.path.splitext(pending[tid])[0] + "_bigjpg.jpg"
                try:
                    download(info["url"], out)
                except Exception as e:
                    print("download failed", pending[tid], e)
                    pending.pop(tid)
                    continue
                print("done", pending.pop(tid), "->", out)

            elif info.get("status") == "error":
                # एक बार और कोशिश, फिर यह फ़ाइल छोड़ दें।
                attempts[tid] += 1
                if attempts[tid] <= MAX_RETRY:
                    requests.post(API + "/api/task/" + tid, headers=HEADERS, timeout=60)
                    print("retrying", pending[tid])
                else:
                    print("giving up on", pending.pop(tid))

        if pending:
            time.sleep(POLL_SECONDS)


if __name__ == "__main__":
    import sys
    main(sys.argv[1:])

हर कॉल क्या करती है

कॉलकामनोट
POST /api/img_uploadसाइन किया हुआ अपलोड URL और इमेज का सार्वजनिक URL लौटाती हैफ़ाइल को उसी Content-Type के साथ PUT कीजिए, फिर fileurl को टास्क के input में दीजिए
POST /api/task/एनलार्ज टास्क बनाती हैtid, अनुमानित minute और remaining_api_calls लौटाती है
GET /api/task/{ids}एक या कई टास्क का स्टेटसid कॉमा से अलग, एक रिक्वेस्ट में 100 तक
POST /api/task/{ids}फेल टास्क दोबारा चलाती हैसिर्फ़ error वाले टास्क कतार में वापस जाते हैं

कॉन्करेंसी और तमीज़

  • सोच से कम बार पोल कीजिए। एनलार्जिंग तुरंत नहीं होती; 5–10 सेकंड का अंतर काफ़ी है, और एक कॉल में 100 id पूछने से रिक्वेस्ट की संख्या कम रहती है।
  • अपलोड सीमित रखिए। एक मशीन के लिए दो से चार अपलोड एक साथ ठीक सीमा है। ज़्यादा थ्रूपुट चाहिए तो हर इंस्टेंस में थ्रेड बढ़ाने की जगह इंस्टेंस बढ़ाइए।
  • बढ़ती देरी के साथ दोबारा कोशिश। नेटवर्क एरर टास्क का फेल होना नहीं है। किसी फ़ाइल को खराब मानने से पहले HTTP कॉल तीन बार तक दोहराइए, हर बार लंबे इंतज़ार के साथ।
  • remaining_api_calls पर नज़र रखिए। बना हर टास्क यह बताता है; एरर की दीवार से सीमा जानने की जगह किसी कम थ्रेशोल्ड पर लूप रोक दीजिए।
  • मैपिंग लिखती रहिए। tid, इनपुट नाम, सेटिंग और आउटपुट नाम वाली एक फ़ाइल रखिए। रातभर चलने वाले काम में यही लॉग बताता है कि क्या पूरा हुआ।

वे एरर जो असल में मिलेंगे

  • valid_api_key_required — हेडर गायब है या key अज्ञात। हेडर का नाम देखिए और यह भी कि key का प्लान एक्सपायर नहीं हुआ।
  • requires_vip — मुफ़्त या एक्सपायर हो चुका अकाउंट। API सक्रिय पेड प्लान के लिए है।
  • month_limit — महीने का कोटा खत्म। हर टास्क बचा हुआ कोटा बताता है, इसलिए उससे पहले रुक सकते हैं।
  • param_error — style art या photo होना चाहिए, noise -1 से 3, x2 1 से 4।
  • input_url_error — input सार्वजनिक रूप से उपलब्ध http या https इमेज URL होना चाहिए। साइन किए निजी URL एक्सपायर हो जाते हैं; पहले अपलोड कीजिए, फिर लौटाया गया सार्वजनिक URL भेजिए।

बैच का खर्च

2x, 4x और 8x पर एक इमेज एक क्रेडिट है; 16x पर दो। यानी 500 इमेज 4x पर 500 क्रेडिट, और 16x पर 1000। चूँकि ज़्यादातर तस्वीरों के लिए 4x ही सही फैक्टर है, सस्ता विकल्प आम तौर पर ज़्यादा अच्छा दिखता भी है — पूरा तर्क फैक्टर गाइड में है।

पैरामीटर और हर एरर स्टेटस समेत पूरा endpoint रेफ़रेंस API पेज पर है। स्क्रिप्ट में कुछ आपको मिलने वाले जवाब से मेल न खाए, तो वही पेज हमारी अपडेटेड वर्शन है।

मूल बातें·

प्रिंट साइज़ टेबल: A4, A3 और पोस्टर के लिए कितने पिक्सेल चाहिए

300 DPI और 200 DPI पर A5 से A1 तक और 10×15 के लिए पिक्सेल की संख्या — और “72 DPI की इमेज प्रिंट नहीं होती” वाला नियम गलत क्यों है।

लेख पढ़ें →

मूल बातें·

2x, 4x, 8x या 16x: कौन-सा अपस्केल फैक्टर चुनें?

फैक्टर सिर्फ़ एक चीज़ तय करता है: आउटपुट में कितने पिक्सेल आएँगे। टारगेट साइज़ से उलटा हिसाब कैसे लगाएँ, और ऊँचा फैक्टर कब नतीजा बड़ा करने के बजाय खराब कर देता है।

लेख पढ़ें →

गाइड·

एनिमे आर्ट, वॉलपेपर और मांगा स्कैन को बड़ा करने का तरीका

रेखा-चित्र और सपाट रंग फोटो से ज़्यादा टिकते क्यों हैं, 4K और 8K वॉलपेपर को असल में कितने पिक्सेल चाहिए, और कौन-सी सेटिंग किनारे को साफ़ रखती है, ग्रे नहीं।

लेख पढ़ें →

← सभी लेख