Skip to content

प्रदर्शन अनुकूलन

Sharp पहले से ही एक उच्च प्रदर्शन छवि प्रसंस्करण लाइब्रेरी है, लेकिन कुछ अनुकूलन तकनीकों के माध्यम से, आप प्रदर्शन को और बेहतर बना सकते हैं।

बेंचमार्क परीक्षण

अन्य छवि प्रसंस्करण लाइब्रेरी की तुलना में Sharp का प्रदर्शन लाभ:

  • ImageMagick से 4-5 गुना तेज़
  • GraphicsMagick से 4-5 गुना तेज़
  • कम मेमोरी उपयोग
  • स्ट्रीम प्रसंस्करण समर्थन

मेमोरी अनुकूलन

स्ट्रीम प्रसंस्करण का उपयोग

बड़ी फ़ाइलों के लिए, स्ट्रीम प्रसंस्करण का उपयोग मेमोरी उपयोग को काफी कम कर सकता है:

javascript
import fs from 'fs';

// ❌ अनुशंसित नहीं: पूरी फ़ाइल को मेमोरी में लोड करें
const buffer = fs.readFileSync('large-image.jpg');
await sharp(buffer).resize(800, 600).toFile('output.jpg');

// ✅ अनुशंसित: स्ट्रीम प्रसंस्करण का उपयोग करें
fs.createReadStream('large-image.jpg')
  .pipe(sharp().resize(800, 600).jpeg())
  .pipe(fs.createWriteStream('output.jpg'));

चंक प्रसंस्करण

बहुत बड़ी फ़ाइलों के लिए, चंक प्रसंस्करण किया जा सकता है:

javascript
import fs from 'fs';

async function processLargeFile(inputPath, outputPath, chunkSize = 1024 * 1024) {
  const pipeline = sharp()
    .resize(800, 600)
    .jpeg({ quality: 80 });

  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(inputPath, { highWaterMark: chunkSize });
    const writeStream = fs.createWriteStream(outputPath);

    readStream
      .pipe(pipeline)
      .pipe(writeStream)
      .on('finish', resolve)
      .on('error', reject);
  });
}

await processLargeFile('large-input.jpg', 'output.jpg');

समय पर मेमोरी मुक्त करना

javascript
// प्रसंस्करण पूर्ण होने के बाद समय पर साफ़ करें
async function processImage(inputPath, outputPath) {
  const sharpInstance = sharp(inputPath);
  
  try {
    await sharpInstance
      .resize(800, 600)
      .jpeg({ quality: 80 })
      .toFile(outputPath);
  } finally {
    // मैन्युअल सफाई (हालांकि Node.js स्वचालित रूप से गार्बेज कलेक्ट करेगा)
    sharpInstance.destroy();
  }
}

समवर्ती अनुकूलन

समवर्ती संख्या नियंत्रण

javascript
async function processWithConcurrency(files, concurrency = 3) {
  const results = [];
  
  for (let i = 0; i < files.length; i += concurrency) {
    const batch = files.slice(i, i + concurrency);
    const batchPromises = batch.map(file => 
      sharp(file)
        .resize(300, 200)
        .jpeg({ quality: 80 })
        .toFile(`processed-${file}`)
    );
    
    const batchResults = await Promise.all(batchPromises);
    results.push(...batchResults);
  }
  
  return results;
}

const files = ['file1.jpg', 'file2.jpg', 'file3.jpg', 'file4.jpg'];
await processWithConcurrency(files, 2);

Worker थ्रेड का उपयोग

CPU-गहन कार्यों के लिए, Worker थ्रेड का उपयोग किया जा सकता है:

javascript
import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';

if (isMainThread) {
  // मुख्य थ्रेड
  async function processWithWorkers(files, numWorkers = 4) {
    const workers = [];
    const results = [];
    
    for (let i = 0; i < numWorkers; i++) {
      const worker = new Worker('./image-worker.js', {
        workerData: { files: files.slice(i * Math.ceil(files.length / numWorkers), (i + 1) * Math.ceil(files.length / numWorkers)) }
      });
      
      worker.on('message', (result) => {
        results.push(result);
      });
      
      workers.push(worker);
    }
    
    await Promise.all(workers.map(worker => new Promise(resolve => worker.on('exit', resolve))));
    return results;
  }
  
  const files = ['file1.jpg', 'file2.jpg', 'file3.jpg'];
  await processWithWorkers(files);
} else {
  // Worker थ्रेड
  const { files } = workerData;
  
  for (const file of files) {
    await sharp(file)
      .resize(300, 200)
      .jpeg({ quality: 80 })
      .toFile(`processed-${file}`);
  }
  
  parentPort.postMessage('done');
}

कैश अनुकूलन

प्रसंस्करण परिणाम कैश करना

javascript
import crypto from 'crypto';
import fs from 'fs';

class ImageCache {
  constructor(cacheDir = './cache') {
    this.cacheDir = cacheDir;
    if (!fs.existsSync(cacheDir)) {
      fs.mkdirSync(cacheDir, { recursive: true });
    }
  }

  generateCacheKey(inputPath, options) {
    const content = JSON.stringify({ inputPath, options });
    return crypto.createHash('md5').update(content).digest('hex');
  }

  async getCachedResult(cacheKey) {
    const cachePath = `${this.cacheDir}/${cacheKey}.jpg`;
    if (fs.existsSync(cachePath)) {
      return cachePath;
    }
    return null;
  }

  async setCachedResult(cacheKey, resultPath) {
    const cachePath = `${this.cacheDir}/${cacheKey}.jpg`;
    fs.copyFileSync(resultPath, cachePath);
  }

  async processImage(inputPath, options) {
    const cacheKey = this.generateCacheKey(inputPath, options);
    const cached = await this.getCachedResult(cacheKey);
    
    if (cached) {
      console.log('कैश परिणाम का उपयोग करें');
      return cached;
    }

    const outputPath = `output-${Date.now()}.jpg`;
    await sharp(inputPath)
      .resize(options.width, options.height)
      .jpeg({ quality: options.quality })
      .toFile(outputPath);

    await this.setCachedResult(cacheKey, outputPath);
    return outputPath;
  }
}

const cache = new ImageCache();
await cache.processImage('input.jpg', { width: 300, height: 200, quality: 80 });

एल्गोरिदम अनुकूलन

उपयुक्त आकार समायोजन एल्गोरिदम चुनना

javascript
// फोटो के लिए, lanczos3 कर्नेल का उपयोग करें
await sharp('photo.jpg')
  .resize(800, 600, { kernel: sharp.kernel.lanczos3 })
  .toFile('photo-resized.jpg');

// आइकन या लाइन आरेख के लिए, nearest कर्नेल का उपयोग करें
await sharp('icon.png')
  .resize(32, 32, { kernel: sharp.kernel.nearest })
  .toFile('icon-resized.png');

// तेज़ प्रसंस्करण की आवश्यकता वाली छवियों के लिए, cubic कर्नेल का उपयोग करें
await sharp('image.jpg')
  .resize(300, 200, { kernel: sharp.kernel.cubic })
  .toFile('image-resized.jpg');

JPEG गुणवत्ता अनुकूलन

javascript
// छवि सामग्री के अनुसार गुणवत्ता समायोजित करें
async function optimizeJPEGQuality(inputPath, outputPath) {
  const metadata = await sharp(inputPath).metadata();
  
  // छवि आकार के अनुसार गुणवत्ता समायोजित करें
  let quality = 80;
  if (metadata.width > 1920 || metadata.height > 1080) {
    quality = 85; // बड़ी छवियों के लिए उच्च गुणवत्ता का उपयोग करें
  } else if (metadata.width < 800 && metadata.height < 600) {
    quality = 75; // छोटी छवियों के लिए कम गुणवत्ता का उपयोग कर सकते हैं
  }
  
  await sharp(inputPath)
    .jpeg({ 
      quality,
      progressive: true, // प्रगतिशील JPEG
      mozjpeg: true      // mozjpeg अनुकूलन का उपयोग करें
    })
    .toFile(outputPath);
}

नेटवर्क अनुकूलन

विभिन्न आकार पूर्व-उत्पन्न करना

javascript
const sizes = [
  { width: 320, suffix: 'sm' },
  { width: 640, suffix: 'md' },
  { width: 1024, suffix: 'lg' },
  { width: 1920, suffix: 'xl' }
];

async function pregenerateSizes(inputPath) {
  const promises = sizes.map(size => 
    sharp(inputPath)
      .resize(size.width, null, { fit: 'inside' })
      .jpeg({ quality: 80 })
      .toFile(`output-${size.suffix}.jpg`)
  );
  
  await Promise.all(promises);
}

await pregenerateSizes('input.jpg');

आधुनिक प्रारूप का उपयोग

javascript
// विभिन्न ब्राउज़रों का समर्थन करने के लिए कई प्रारूप उत्पन्न करें
async function generateModernFormats(inputPath) {
  const promises = [
    // JPEG बैकअप के रूप में
    sharp(inputPath)
      .resize(800, 600)
      .jpeg({ quality: 80 })
      .toFile('output.jpg'),
    
    // WebP आधुनिक ब्राउज़रों के लिए
    sharp(inputPath)
      .resize(800, 600)
      .webp({ quality: 80 })
      .toFile('output.webp'),
    
    // AVIF नवीनतम ब्राउज़रों के लिए
    sharp(inputPath)
      .resize(800, 600)
      .avif({ quality: 80 })
      .toFile('output.avif')
  ];
  
  await Promise.all(promises);
}

निगरानी और डीबगिंग

प्रदर्शन निगरानी

javascript
import { performance } from 'perf_hooks';

async function measurePerformance(fn) {
  const start = performance.now();
  const result = await fn();
  const end = performance.now();
  
  console.log(`निष्पादन समय: ${end - start}ms`);
  return result;
}

await measurePerformance(async () => {
  await sharp('input.jpg')
    .resize(800, 600)
    .jpeg({ quality: 80 })
    .toFile('output.jpg');
});

मेमोरी उपयोग निगरानी

javascript
import { performance } from 'perf_hooks';

function getMemoryUsage() {
  const usage = process.memoryUsage();
  return {
    rss: `${Math.round(usage.rss / 1024 / 1024)}MB`,
    heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
    heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
    external: `${Math.round(usage.external / 1024 / 1024)}MB`
  };
}

console.log('प्रसंस्करण से पहले मेमोरी उपयोग:', getMemoryUsage());

await sharp('input.jpg')
  .resize(800, 600)
  .jpeg({ quality: 80 })
  .toFile('output.jpg');

console.log('प्रसंस्करण के बाद मेमोरी उपयोग:', getMemoryUsage());

सर्वोत्तम अभ्यास सारांश

  1. बड़ी फ़ाइलों के लिए स्ट्रीम प्रसंस्करण का उपयोग करें
  2. समवर्ती संख्या नियंत्रित करें
  3. प्रसंस्करण परिणाम कैश करें
  4. उपयुक्त आकार समायोजन एल्गोरिदम चुनें
  5. आउटपुट प्रारूप और गुणवत्ता अनुकूलित करें
  6. सामान्य आकार पूर्व-उत्पन्न करें
  7. प्रदर्शन मेट्रिक्स निगरानी करें

प्रदर्शन तुलना

ऑपरेशनSharpImageMagickGraphicsMagick
आकार बदलना100ms450ms420ms
प्रारूप रूपांतरण80ms380ms360ms
फ़िल्टर लागू करना120ms520ms480ms
मेमोरी उपयोगकमउच्चउच्च

अगला कदम

Apache 2.0 लाइसेंस के तहत जारी किया गया।