Как динамически находить параметр качества в compressjs

#javascript #html #jquery #math #compression

#javascript #HTML #jquery #математика #сжатие

Вопрос:

Размер моего файла составляет 500 КБ (он будет динамически приходить в любом размере). И моя цель — 150 КБ.

По некоторым причинам я могу выбрать только качество

 new Compressor(selectedFile1, {
            quality: targetRatio,
 

т.Е., Если я передам targetRatio на 0.7, это уменьшит изображение до 159 КБ ~

Чтобы динамически находить целевое значение, я сделал следующее

 var targetRatio = fileSize / 150;
 

Но я не могу понять, как найти целевое значение, чтобы получить точное значение, т. Е. Уменьшить до 150 КБ

Вот место для тестирования

Ответ №1:

Изменение качества до 150 КБ не будет работать для каждого изображения.

Степень сжатия JPEG обычно измеряется в процентах от уровня качества. Изображение со 100% качеством не имеет (почти) потерь, а качество 1% — это изображение очень низкого качества. В общем, уровни качества 90% или выше считаются «высоким качеством», 80% -90% — «среднее качество», а 70% -80% — низкое качество.

Если вы будете использовать формат jpg размером 15,594 x 3,936 (пример), который может составлять ~ 2,5 Мб в зависимости от сохраненной информации, вы не сможете достичь 150 КБ в формате jpg.

Таким образом, таргетинг на 150 КБ будет 150.000 / 2.500.000 = 0.06 .

введите описание изображения здесь

Как вы можете видеть из размера результата на скриншоте, это невозможно, вам нужно выполнить несколько преобразований и проверить, соответствует ли размер результата точно или меньше 150 КБ, уменьшив ширину и высоту. Но сжатие исходного изображения из моего примера с использованием качества 0,06 приведет к получению изображения размером около 800 КБ.

 fetch('https://i.imgur.com/mw7BsYS.jpg')
  .then(response => response.blob())
  .then(async blob => {
    let {
      size
    } = blob;

    console.log("Startingsize", size, 'B');
    let img = document.createElement("img");
    img.src = URL.createObjectURL(blob);

    await new Promise((r) => img.onload = r);
    let {
      naturalWidth,
      naturalHeight
    } = img;
    
    console.log(naturalWidth, naturalHeight, size);
    const targetByte = 150 * 1024;
    // in case first picture is smaller than 150kb
    let compressed = { result: blob };
    // speeds up large pictures
    if (targetByte / size < 0.15) {
      naturalWidth *= 0.15;
      naturalHeight *= 0.15;
    } else if (targetByte / size < 0.25) {
      naturalWidth *= 0.25;
      naturalHeight *= 0.25;
    } else if (targetByte / size < 0.5) {
      naturalWidth *= 0.5;
      naturalHeight *= 0.5;
    } else if (targetByte / size < 0.75) {
      naturalWidth *= 0.75;
      naturalHeight *= 0.75;
    }

    // generate thumbnails
    while (size > targetByte) {
      if (blob.size > targetByte) {
        // the bigger the steps, the faster it will be.
        naturalWidth *= 0.99;
        naturalHeight *= 0.99;
      }
      let res = await new Promise((resolve, reject) => {
        const res = new Compressor(blob, {
          maxWidth: naturalWidth,
          maxHeight: naturalHeight,
          success(blob) {
            size = blob.size;
            console.log(naturalWidth, naturalHeight, size);
            compressed = res;
            resolve();
          },
          error: reject
        })
      });
    }

    // replace the compressed with the original image from above
    const original = img.src;
    img.onclick = () => { if (confirm("sure?")) img.src = original; };

    // compressed.result contains the final blob now
    img.src = URL.createObjectURL(compressed.result);

    await new Promise((r) => img.onload = r);
    console.log(compressed.result, img.naturalWidth, img.naturalHeight)

    document.body.append(img);
  }) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/compressorjs/1.1.1/compressor.js"></script>