Node.js: розмір зображення без ImageMagick


85

Я розробляю веб-додаток на Node.js (+ express 4), де користувачі можуть встановити своє зображення профілю, завантаживши його на сервер. Ми вже обмежуємо mimeype та max розмір файлу, тому користувач не може завантажувати більше 200 КБ зображень у форматі png або jpeg.

Проблема полягає в тому, що ми хотіли б зменшити розмір (на стороні сервера) роздільної здатності завантаженого зображення до 200x200, щоб покращити завантаження сторінки та заощадити місце на диску. Після деяких досліджень усі відповіді вказували на використання будь-якого модуля на основі ImageMagick або GraphicsMagick.

Однак установка ImageMagick / GraphicsMagick для простого зміни розміру зображення здається мені занадто надмірною, тож, чи є якесь інше рішення, крім цього, для Node.js?

Редагувати: Я прийняв прийняте рішення на різке, оскільки попереднє рішення (lwip) більше не підтримується. Дякуємо за всі Ваші відгуки!


Привіт. У мене питання. Як зменшити розмір зображення нижче 200 КБ? Поясніть, будь ласка, шлях. Дякую.
C.Petrescu

Привіт, це питання варто опублікувати як нове, якщо ви не знайдете жодного пов’язаного, яке було опубліковано раніше. Щоб дати вам трохи світла, спробуйте шукати методи стиснення та зміни розміру в API, наданому для інструментів, які ви можете знайти в цьому питанні.
zacr0

Відповіді:


92

Я б проголосував за різке :

sharp('input.jpg')
  .resize(200, 200)
  .toFile('ouput.jpg', function(err) {
    // output.jpg is a 200 pixels wide and 200 pixels high image
    // containing a scaled and cropped version of input.jpg
  });

Це швидко, як правило, в 6 разів швидше, ніж найшвидші прив'язки вузлів на основі imagemagick , і працює в дуже невеликій пам'яті, можливо, в 10 разів менше . різкі посилання на бібліотеку зображень libvips безпосередньо, немає обстрілу із зовнішньою програмою, а сама бібліотека швидше та ефективніше * magick при виконанні цього завдання. Він підтримує корисні речі, такі як введення та виведення потоку, буфера та файлової системи, управління кольором, прозорість, обіцянки, накладання, WebP, SVG тощо.

Починаючи з різкого значення 0.20, npm автоматично завантажує всі попередньо скомпільовані двійкові файли на більшості платформ, тому немає необхідності в node-gyp. Просто введіть:

npm install sharp

або:

yarn add sharp

І вперед.


7
Починаючи з v0.12.0, він sharpбільше не має жодних зовнішніх залежностей виконання для користувачів Linux та Windows, оскільки він об’єднує попередньо скомпільовану версію libvips. Ви знайдете, що операції зі зміною розміру в ~ 10 разів швидші, ніж LWIP, і частково використовують пам'ять.
Ловелл Фуллер

4
додано підтримку рідного gif та svg з версією 0.15 sharp.dimens.io/en/stable/changelog
jcupitt

1
Це сотні файлів, але всі вони управляються автоматично для вас до npm, вам не потрібно думати про це.
jcupitt

4
@CoDEmanX Можливо, спробуйте запустити npm install --global --production windows-build-toolsспочатку. Див. Також github.com/Microsoft/nodejs-guidelines/blob/master/…
Ловелл Фуллер

1
Я створив невеликий скрипт, який дозволяє легко зрозуміти, що роблять речі, і як це буде виглядати в такому вмісті, як картки boostrap і фон: обкладинка для найкращої оптимізації параметрів, можливо, її інтересу github.com/lcherone/sharp-test
Лоуренс Черон

71

Нещодавно я розпочав розробку модуля обробки зображень для NodeJS без будь-яких залежностей виконання ( прочитайте чому ). Це все ще на ранніх стадіях, але вже придатне для використання.

Те, про що ви просите, буде виконано наступним чином:

image.resize(200, 200, function(err, image){
    // encode resized image to jpeg and get a Buffer object
    image.toBuffer('jpg', function(err, buffer){
        // save buffer to disk / send over network / etc.
    });
});

Більше інформації в репозиторії Github модуля .


7
Ваш модуль чудовий. Однак для цього потрібно так багато пам’яті. Я спробував writeFile створити 1.8Mbзображення, і воно вимагає 130 Мб пам’яті. Після цього я роблю тест, 4MB, 11000x6000змінивши розмір зображення на кілька ескізів (640 560 480, ..., 160), і це займає приблизно 1,7 Гб пам'яті. Це помилка?
Льюїс

2
Привіт @Orion, дякую за відгук. Будь ласка, перейдіть до репозитарію Github і відкрийте випуск із деякими деталями (ОС, версії, код для відтворення цього). Спробуємо вирішити це разом :)
EyalAr

@EyalAr Гей, Еяле, як змінити розмір і зберегти аспект? (змінити розмір до максимально можливого розміру ширини, висоти) без розтягування
Даніель Кром

10
Я б порадив не використовувати lwip у 2017 році. Пакет, здається, більше не підтримується, і він має значні проблеми з установкою в Windows, а тепер навіть на платформах Unix.
zerefel

9
На жаль, lwip - мертвий проект. різкий, однак, здається, активно підтримується.
Лоран,

16

Погляньте на lwip: https://github.com/EyalAr/lwip

Дуже простий і простий у використанні

npm install lwip

а потім у коді вашого вузла,

// obtain an image object:
require('lwip').open('image.jpg', function(err, image){

  // check err...
  // define a batch of manipulations and save to disk as JPEG:
  image.batch()
    .scale(0.75)          // scale to 75%
    .rotate(45, 'white')  // rotate 45degs clockwise (white fill)
    .crop(200)            // crop a 200X200 square from center
    .blur(5)              // Gaussian blur with SD=5
    .writeFile('output.jpg', function(err){
      // check err...
      // done.
    });

});

Я успішно застосував це у своєму завантажувачі файлів, і це працює як шарм.


1
Це те, що я шукав, не потрібно встановлювати надмірні, важкі зовнішні залежності для пари функцій, пов’язаних із зміною розміру зображення.
zacr0

3
До речі, @EyalAr є автором цього вузлового модуля. Його коментар також наведений нижче.
Арвінд

Дуже інтуїтивно зрозумілий для встановлення та роботи. Мені дуже подобається, що від вас не вимагається реалізація будь-яких двійкових бібліотек, таких як ImageMagick.
ChrisRich

Це точно так само, як і ця відповідь (власник LWIP), але пізніше: stackoverflow.com/a/24543924/1525495
Хорхе Фуентес Гонсалес,

12

Існує хороша бібліотека для обробки зображень, повністю написана на JavaScript, без залежностей від інших бібліотек, Jimp. https://github.com/oliver-moran/jimp

Приклад використання:

var Jimp = require("jimp");

// open a file called "lenna.png"
Jimp.read("lenna.png", function (err, lenna) {
    if (err) throw err;
    lenna.resize(256, 256)            // resize
         .quality(60)                 // set JPEG quality
         .write("lena-small.jpg"); // save
});

Наскільки це швидко в порівнянні з ImageMagik?
Крістофер Грігг,

2
Sharp має набір орієнтирів: sharp.dimens.io/en/stable/performance --- У цьому тесті Jimp в 5 разів повільніший, ніж IM, і в 30 разів повільніший, ніж Sharp. Звичайно, досить швидко є досить швидким, і швидкість - не єдиний фактор, який слід враховувати.
jcupitt

У реальному часі, можливо, ні, але Jimp є чудовим для простого написання багатозначних файлів мініатюр (а потім отримати їх як кешовані файли).
coderofsalvation

jimp не підтримує webp і не підтримуватиме його найближчим часом. Див .: github.com/oliver-moran/jimp/issues/144
Вячеслав Добромислов

8

Sharp нещодавно користується деякою популярністю, але це та сама ідея, що і * Магічні прив’язки.

Однак установка ImageMagick / GraphicsMagick для простого зміни розміру зображення здається мені занадто надмірною

Зміна розміру зображення - це все, але не просто. Формат JPEG є особливо складним, і існує кілька способів масштабування графіки з різною якістю результатів, лише деякі з них легко реалізувати. Для виконання цієї роботи існують бібліотеки обробки зображень, тому, якщо немає іншої причини, чому ви не можете їх встановити, перейдіть до цього.


13
Можливо, я ледачий розробник, але як тільки я побачив процес встановлення ImageMagick і здивувався, скільки я витратив би на його встановлення на своєму екземплярі Amazon AWS EC2, я відразу ж почав шукати інші варіанти - особливо враховуючи, що все, що мені потрібно було можливість зміни розміру зображень для мініатюр.
ChrisRich

7

Полотно в 2,3 рази швидше, ніж ImageMagic.

Ви можете спробувати порівняти модулі Node.js для обробки зображень - https://github.com/ivanoff/images-manipulation-performance

author's results:
 sharp.js : 9.501 img/sec; minFreeMem: 929Mb
 canvas.js : 8.246 img/sec; minFreeMem: 578Mb
 gm.js : 4.433 img/sec; minFreeMem: 791Mb
 gm-imagemagic.js : 3.654 img/sec; minFreeMem: 804Mb
 lwip.js : 1.203 img/sec; minFreeMem: 54Mb
 jimp.js : 0.445 img/sec; minFreeMem: 82Mb

3

Якщо вам не потрібно велике зображення, ви можете змінити його розмір на стороні клієнта перед завантаженням:

Читання файлів у JavaScript за допомогою файлових API

Змінення розміру на стороні клієнта за допомогою JavaScript перед завантаженням на сервер

Багато користувачів можуть мати хороше уявлення про себе зі смартфона, і багато з них мають розмір понад 200 кБ. Зауважте, що надані клієнтом дані не можна довіряти, тому перевірки на стороні сервера все ще застосовуються.


2
Ви ніколи не можете довіряти клієнту, користувач просто повинен знати кінцеву точку завантаження, щоб відправити туди все, що він хоче. Отже, такі перевірки, як розмір файлу, все ще застосовуються. Але, зміна розміру на стороні клієнта - це хороша ідея.
Kev,

1

Я використовував lwip (як раніше пропонував arvind), але перейшов на png-crop . Здається, це працює трохи швидше для мене (Win 8.1 x64, Node v0.12.7). Код у репозиторії виглядає неймовірно легким, і в експлуатації він простий у використанні.

var pngcrop = require('png-crop');
var config = {left: 10, top: 100, height: 150, width: 150};
pngcrop.crop('cats.png','cats-cropped.png',config);

Звичайно, це буде робити лише файли PNG ...


0

Sharp працює дуже добре і простий у використанні з потоками, працює як шарм, але вам потрібно скомпілювати його з версією вузла, це є мінусом. Я використовував Sharp для обробки зображень із зображенням із сегмента AWS S3 і працював чудово, але мені довелося використовувати інший модуль. GM не працював у мене, але Jimp працював дуже добре!

Ви повинні звернути увагу на шлях написаного малюнка, це може привести до помилок, якщо ви почнете шлях з "/".

Ось як я використовував Jimp у nodeJS:

const imageUrl = `SOME_URL`;
let imgExported = 'EXPORTED_PIC.png';

Jimp.read(imageUrl)
    .then(image => {
        image   
            .resize(X, Y) 
            .write(`tmp/`+ imgExported, err => { 
                if(err) 
                    console.error('Write error: ', err);
                else { ... // don't forget to put a callback() } }

            });

Також стежте за порядком виконання, поставте зворотний дзвінок, щоб інші речі не відбувалися, коли ви цього не хочете. Спробував використати "await" для Jimp.read (), але це не справило роботу добре.


Починаючи з різкого значення 0.20, він автоматично завантажує попередньо скомпільований двійковий файл для вашої точної версії вузла на більшості платформ, тому не потрібно нічого створювати.
jcupitt

На жаль, це не спрацювало у мене. Мені потрібно було використовувати Sharp у файловій системі лише для читання з різними версіями node.js, і мені довелося завантажити модуль різкості для кожної версії вузла, яку я використовував, і це зайняло занадто багато часу.
Алекс Сечелеану,

0

Ви можете зробити це за допомогою jimp (node_module)

Місцевий запис:

Jimp.read(path) // this can be url or local location
      .then(image=> {
          image
            .resize(size, Jimp.AUTO) // jimp.AUTO automatically sets the width so that the image doesnot looks odd
            .write('path-to-save');
      })
      .catch(err => {
        console.log(err);
      });

Завантажити на s3 або де завгодно.

Jimp.read(urls) // this can be url or local location
          .then(image=> {
              image
                .resize(size, Jimp.AUTO) // jimp.AUTO automatically sets the width so that the image doesnot looks odd
                .getBase64(Jimp.AUTO, (err, res) => {
                  const buf = new Buffer(
                    res.replace(/^data:image\/\w+;base64,/, ""),
                    "base64"
                  );
                  var data = {
                    Key: key,
                    Bucket: bucket,
                    Body: body,
                    ContentEncoding: "base64",
                    ContentType: "image/jpeg"
                  };
                  s3.putObject(data, function(err, data) {
                    if (err) {
                      throw err;
                    } else {
                      console.log("succesfully uploaded the image!");
                    }
                  });
                });
          })
          .catch(err => {
            console.log(err);
          });

0

Мені подобається бібліотека resize-img за її простоту.

const fs = require('fs');
const resizeImg = require('resize-img');

(async () => {
    const image = fs.readFileSync('unicorn.png');

    const newImage = await resizeImg(image, { width: 128, height: 128 });

    fs.writeFileSync('unicorn-128x128.png', newImage);
})();

0

Змінено розмір зображення за допомогою API Google Drive v3 . Цей метод рекомендується для Google Apps Script для вставки зображень у Google Таблиці.

Алгоритм:

  1. Завантажте зображення в папку Google Drive.
  2. Отримати загальнодоступну URL-адресу ескізу зображення.
  3. Замініть параметр "змінити розмір" у URL-адресі необхідною шириною та / або висотою. (Розмір ескізу за замовчуванням - 220 пікселів).
  4. Завантажте зменшений ескіз із Google Диска.

Див. Приклад тут: https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150

І остерігайтеся квот GDrive:

  • запитів на день: 1000000000
  • запитів на 100 секунд на користувача: 1000
  • запитів за 100 сек: 10000
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.