العمل مع الصور في TypeScript: تغيير الحجم والقص
\nفي تطوير الويب الحديث، تعد معالجة الصور واحدة من أكثر المهام طلبًا. TypeScript، بفضل الكتابة الصارمة والتكامل مع Node.js، يتيح إنشاء أدوات موثوقة وعالية الأداء لتغيير حجم (resize) وقص (crop) الصور. في هذه المقالة، سنستعرض مكتبتين شائعتين: Sharp (معالجة من جانب الخادم) وJimp (JavaScript خالص)، بالإضافة إلى النهج الأصلي باستخدام Canvas API للمتصفح.
\n\n1. تثبيت وإعداد مشروع TypeScript
\nللبدء، أنشئ مشروعًا وقم بتثبيت التبعيات اللازمة:
\nnpm init -y\nnpm install typescript @types/node sharp jimp\nnpx tsc --init\nفي ملف tsconfig.json، تأكد من أن "module": "commonjs" و "target": "ES2020".
2. مكتبة Sharp — معالجة سريعة من جانب الخادم
\nتستخدم Sharp الوحدة النمطية الأصلية libvips وتوفر أداءً عاليًا. مناسبة لتطبيقات الخادم (NestJS، Express).
\n\n2.1. تغيير الحجم (resize) باستخدام Sharp
\nتأخذ طريقة resize() العرض والارتفاع. يمكن تحديد معامل واحد فقط وسيتم حساب الثاني بشكل نسبي.
import sharp from 'sharp';\n\nasync function resizeImage(inputPath: string, outputPath: string, width: number, height?: number): Promise<void> {\n try {\n await sharp(inputPath)\n .resize(width, height, {\n fit: 'cover', // 'cover', 'contain', 'fill', 'inside', 'outside'\n position: 'center' // موضع القص عند استخدام cover\n })\n .toFile(outputPath);\n console.log(`تم تغيير حجم الصورة: ${outputPath}`);\n } catch (error) {\n console.error('خطأ في تغيير الحجم:', error);\n }\n}\n\n// مثال على الاستخدام\nresizeImage('input.jpg', 'output_800x600.jpg', 800, 600);\n\n2.2. القص (crop) باستخدام Sharp
\nتتيح طريقة extract() قص منطقة مستطيلة. المعاملات: left، top، width، height.
async function cropImage(\n inputPath: string,\n outputPath: string,\n left: number,\n top: number,\n cropWidth: number,\n cropHeight: number\n): Promise<void> {\n try {\n await sharp(inputPath)\n .extract({ left, top, width: cropWidth, height: cropHeight })\n .toFile(outputPath);\n console.log(`تم القص: ${outputPath}`);\n } catch (error) {\n console.error('خطأ في القص:', error);\n }\n}\n\n// مثال: قص المنتصف 400x400 من صورة 800x600\ncropImage('input.jpg', 'cropped_center.jpg', 200, 100, 400, 400);\n\n2.3. الجمع بين تغيير الحجم والقص
\nيتيح Sharp دمج العمليات في سلسلة. على سبيل المثال، التصغير أولاً ثم القص:
\nasync function resizeAndCrop(inputPath: string, outputPath: string): Promise<void> {\n await sharp(inputPath)\n .resize(500, 500, { fit: 'inside' }) // تصغير إلى 500x500 بدون قص\n .extract({ left: 50, top: 50, width: 400, height: 400 }) // قص المنتصف\n .toFile(outputPath);\n}\n\nresizeAndCrop('input.jpg', 'processed.jpg');\n\n3. مكتبة Jimp — JavaScript خالص بدون تبعيات أصلية
\nتعمل Jimp على JavaScript خالص، ولا تتطلب تثبيت مكتبات نظام إضافية. مثالية للبيئات المعزولة (مثل AWS Lambda).
\n\n3.1. تثبيت Jimp
\nnpm install jimp\nnpm install @types/jimp // لـ TypeScript\n\n3.2. تغيير الحجم باستخدام Jimp
\nimport Jimp from 'jimp';\n\nasync function resizeWithJimp(inputPath: string, outputPath: string, width: number, height: number): Promise<void> {\n try {\n const image = await Jimp.read(inputPath);\n image.resize(width, height, Jimp.RESIZE_BILINEAR); // الخوارزميات: BILINEAR, BICUBIC, NEAREST_NEIGHBOR\n awa