অধিকাংশ ওয়েব অ্যাপ এখনও ইমেজ আপলোডকে একটি ব্ল্যাক বক্সের মতো হ্যান্ডেল করে। একজন ব্যবহারকারী একটি ফাইল ড্রপ করেন, ব্রাউজার সেটি পাঠিয়ে দেয়, এবং সার্ভার হয় পেলোডটি গ্রহণ করে অথবা এমন একটি 413 এরর দেয় যার জন্য কেউ প্রস্তুত ছিল না। ব্রাউজার-সাইড কম্প্রেশন এই সমীকরণ বদলে দেয়। এটি আপনাকে ডেটা পাঠানোর আগেই পেলোড ছোট করার সুযোগ দেয়, যার অর্থ হলো দ্রুত আপলোড, কম ব্যান্ডউইথ খরচ এবং সার্ভার টাইমআউট কম হওয়া। কিন্তু এই কাজটি ভুল করা খুব সহজ। আপনি যদি কম্প্রেশনকে কেবল একটি "quality" লেবেলযুক্ত ম্যাজিক স্লাইডার হিসেবে বিবেচনা করেন, তবে আপনি ত্রুটিপূর্ণ ছবি, প্রসারিত থাম্বনেইল এবং বিভ্রান্তিকর ইউজার এক্সপেরিয়েন্স প্রদান করবেন। আরও ভালো পদ্ধতি হলো পুরো প্রক্রিয়াটিকে একটি পাইপলাইন হিসেবে বিবেচনা করা।
স্লাইডার নয়, পাইপলাইনের কথা ভাবুন
কাজটিকে আলাদা আলাদা ধাপে ভাগ করুন। ইনপুট এলিমেন্ট থেকে ফাইলটি পড়ুন। ইমেজটিকে আপনার টার্গেট ডাইমেনশনে স্কেল ডাউন করুন। একটি নতুন Blob এনকোড করুন। তারপর ফলাফলটি ব্যবহারকারীর কাছে রেন্ডার করুন। প্রতিটি ধাপ একটি নির্দিষ্ট কাজ করে এবং তার আউটপুট পরবর্তী ধাপে পাঠিয়ে দেয়। এই বিভাজন কেবল কোডকে পরিচ্ছন্নই করে না, এটি ইউনিট টেস্টিংকেও সহজ করে তোলে। আপনি ফাইল ইনপুট স্পর্শ না করেই স্কেলিং ধাপে একটি পরিচিত বাফার ইনপুট হিসেবে দিতে পারেন। সার্ভার রাউন্ড ট্রিপের জন্য অপেক্ষা না করেই আপনি যাচাই করতে পারেন যে আপনার এনকোডার ২০০ KB-এর নিচে একটি JPEG তৈরি করছে কি না।
এই দায়িত্বগুলো আলাদা রাখলে আপলোডের সময় অপ্রত্যাশিত সমস্যাও এড়ানো যায়। আপনি যদি স্কেলিং এবং এনকোডিংকে একটি জটিল ফাংশনে মিলিয়ে ফেলেন, তবে মাঝপথে একটি ডিকোডিং এরর আপনার আপলোড কিউ-কে একটি অসামঞ্জস্যপূর্ণ অবস্থায় ফেলে দিতে পারে। একটি পাইপলাইন আপনাকে প্রতিটি সীমানায় যাচাই করতে বাধ্য করে। যদি ফাইলটি ডিকোড করা না যায়, তবে ক্যানভাস তৈরি করার আগেই আপনি তা ধরতে পারবেন। যদি এনকোড করা Blob খুব বড় হয়, তবে সার্ভারকে এটি সংরক্ষণ করতে বলার আগেই আপনি তা ধরতে পারবেন।
কোড লেখার আগেই একটি চুক্তি (Contract) নির্ধারণ করুন
কেউ ক্যানভাস ড্র কল (canvas draw call) লেখার আগে, নিয়মগুলো লিখে ফেলুন এবং টিমের সাথে শেয়ার করুন। গ্রহণযোগ্য MIME টাইপগুলো বেছে নিন। আপনি কি JPEG, PNG, WebP, নাকি AVIF অনুমতি দেবেন? আলফা চ্যানেল, ব্রাউজার সাপোর্ট এবং CPU খরচের ক্ষেত্রে প্রতিটির আলাদা প্রভাব রয়েছে। একটি সর্বোচ্চ ইনপুট সাইজ নির্ধারণ করুন। একটি ফ্ল্যাগশিপ ফোন থেকে আসা ৩০ MB-এর র (raw) ছবি যদি আপনি সম্পূর্ণ মেমরিতে ডিকোড করার চেষ্টা করেন, তবে এটি একটি পুরনো ল্যাপটপকে ফ্রিজ বা ক্র্যাশ করতে পারে। সর্বোচ্চ আউটপুট ডাইমেনশন নির্ধারণ করুন। আপনার UI যদি কখনোই ২০৪৮ পিক্সেলের বেশি চওড়া ছবি প্রদর্শন না করে, তবে পাইপলাইনের মাধ্যমে ৬০০০ পিক্সেল চওড়া ছবি যাওয়ার কোনো প্রয়োজন নেই।
সবচেয়ে গুরুত্বপূর্ণ হলো, ডিকোডিং ব্যর্থতার জন্য পরিকল্পনা রাখা। একটি ক্ষতিগ্রস্ত ফাইল, একটি অদ্ভুত কালার প্রোফাইল, বা একটি অসম্পূর্ণ আপলোড Image কনস্ট্রাক্টরে এরর ছুড়ে দিতে পারে। আপনার পাইপলাইনে একটি স্পষ্ট catch block এবং মানুষের পড়ার উপযোগী এরর মেসেজ থাকা প্রয়োজন। ব্রাউজারকে নীরবে কাজ বন্ধ করতে দেবেন না এবং ব্যবহারকারীকে একটি স্পিনারের দিকে তাকিয়ে থাকতে বাধ্য করবেন না যেখানে আসলে কিছুই ঘটছে না।
ইমেজের প্রতি যত্নশীল হোন
ইমেজের বিকৃতি (Distortion) অপেশাদার দেখায়। অ্যাসপেক্ট রেশিও বজায় রাখুন এবং দীর্ঘতম পাশটি সীমাবদ্ধ রাখুন। আপনার টার্গেট বক্স যদি ১০২৪ বাই ১০২৪ পিক্সেল হয়, তবে একটি ৪০০০ বাই ৩০০০ পিক্সেলের ছবি ১০২৪ বাই ৭৬৮ সাইজে আসা উচিত, ১০২৪ বাই ১০২৪ নয়। দীর্ঘতম প্রান্ত থেকে স্কেল ফ্যাক্টর গণনা করুন এবং ছোট প্রান্তটিকে অনুসরণ করতে দিন। এটি ছবিগুলোকে অদ্ভুত আকৃতিতে প্রসারিত হওয়া থেকে রক্ষা করে।
প্রকৃত এক্সপোর্টের জন্য, ক্যানভাস toBlob মেথড ব্যবহার করুন। এটি আপনাকে আউটপুট ফরম্যাট এবং কোয়ালিটি সেটিংয়ের ওপর সরাসরি নিয়ন্ত্রণ দেয় এবং এটি অ্যাসিনক্রোনাসলি চলে যাতে মেইন থ্রেড ব্লক না হয়। একটি অফস্ক্রিন ক্যানভাস তৈরি করুন, রিসাইজ করা ছবিটি তার ওপর আঁকুন, তারপর আপনার পছন্দের টাইপ এবং কোয়ালিটি ভ্যালু দিয়ে canvas.toBlob কল করুন। সেই নতুন Blob-টিই আপনি আপনার আপলোড লজিক বা স্টোরেজ API-তে প্রদান করবেন।
প্রমাণ দেখান
কম্প্রেশন হলো একটি অদৃশ্য কাজ। আপনি যদি সংখ্যাগুলো প্রদর্শন না করেন, তবে ব্যবহারকারীরা এই প্রক্রিয়ার ওপর আস্থা রাখবে না। এমন একটি ইন্টারফেস তৈরি করুন যা তাদের আসল ফাইলের সাথে ফলাফলের তুলনা করতে দেয়। আসল ফাইলের সাইজ, নতুন ফাইলের সাইজ, নতুন ডাইমেনশন এবং চূড়ান্ত ফরম্যাট টাইপ প্রদর্শন করুন। একটি ৪.২ MB ফোনের ছবি কমে ৩৮০ KB WebP হওয়া দেখলে ব্যবহারকারীর এই ভয় কেটে যাবে যে আপনি গোপনে তাদের ছবি নষ্ট করছেন।
এই স্বচ্ছতা সমস্যা সমাধানেও (troubleshooting) সাহায্য করে। যখন কোনো ব্যবহারকারী আপলোড ব্যর্থ হওয়ার অভিযোগ করেন, তখন প্রথম যে বিষয়টি আপনি পরীক্ষা করবেন তা হলো আউটপুট ডাইমেনশন আপনার সার্ভার লিমিট অতিক্রম করেছে কি না, অথবা ফরম্যাট PNG থেকে JPEG-তে পরিবর্তিত হয়ে আলফা চ্যানেল হারিয়ে গেছে কি না। সেই ডেটা UI-তে রাখুন যাতে ব্যবহারকারী সাপোর্ট টিকিট খোলার আগেই নিজেই সমস্যাটি শনাক্ত করতে পারেন।
রিকম্প্রেশনের চেয়ে প্রিসেট ব্যবহার করা ভালো
কখনও একই ছবি দুবার কমপ্রেস করবেন না। লসি (lossy) এনকোডারের মাধ্যমে প্রতিটি পাস ডিটেইল কমিয়ে দেয় এবং ব্লক আকৃতির আর্টিফ্যাক্ট তৈরি করে। আপনি যদি ব্যবহারকারীকে বারবার "optimize" বাটনে ক্লিক করতে দেন, তবে তৃতীয় প্রজন্মের ছবিটি একটি ফটোকপির ফটোকপির মতো দেখাবে। পরিবর্তে, মূল সোর্স ফাইল থেকে প্রতিটি আউটপুট তৈরি করুন এবং প্রিসেট অফার করুন:
- Smaller file: Push quality lower and cap dimensions aggressively for thumbnails or fast previews.
- Balanced: Target a moderate quality level with sensible dimensions, suitable for social feeds and galleries.
- More detail: Keep quality high and preserve larger dimensions for photography, artwork, or print previews.
Store the original Blob in memory so the user can switch between presets without stacking generations of loss. Always generate from the source, never from the last output.
Test Like Your Users Upload
Your development machine with a fiber connection and 32 GB of RAM is not reality. Test with the actual files real users carry. Phone photos from iOS and Android use different metadata orientations and may originate from HEIC sources. Transparent assets such as logos and icons behave differently under JPEG conversion because JPEG simply does not support alpha channels. Huge files will expose memory limits on devices with 2 GB of RAM. Slow mobile CPUs will reveal exactly how long that toBlob call really takes.
Use Chrome DevTools to throttle the CPU and network. Try a five-year-old Android phone. If your pipeline locks the UI for three seconds while encoding, you need to move the heavy work into a Web Worker so the interface stays responsive.
Ship the Basics First
It is tempting to support every format and
