Node.js: การปรับขนาดรูปภาพโดยไม่มี ImageMagick


86

ฉันกำลังพัฒนาเว็บแอปบน Node.js (+ express 4) ซึ่งผู้ใช้สามารถตั้งค่ารูปโปรไฟล์ได้โดยการอัปโหลดไปยังเซิร์ฟเวอร์ เรา จำกัด ประเภทไฟล์และขนาดไฟล์สูงสุดไว้แล้วดังนั้นผู้ใช้จึงไม่สามารถอัปโหลดภาพ png หรือ jpeg เกิน 200KB ได้

ปัญหาคือเราต้องการปรับขนาด (ด้านเซิร์ฟเวอร์) ความละเอียดของภาพที่อัปโหลดเป็น 200x200 เพื่อปรับปรุงการโหลดหน้าเว็บและประหยัดเนื้อที่บนดิสก์ หลังจากการวิจัยบางส่วนคำตอบทั้งหมดชี้ไปที่การใช้โมดูลใด ๆ ที่ใช้ ImageMagick หรือ GraphicsMagick

อย่างไรก็ตามการต้องติดตั้ง ImageMagick / GraphicsMagick เพื่อทำการปรับขนาดภาพอย่างง่ายดูเหมือนจะมากเกินไปสำหรับฉันดังนั้นมีวิธีอื่นนอกเหนือจากนี้สำหรับ Node.js หรือไม่

แก้ไข:ฉันได้เปลี่ยนวิธีการแก้ปัญหาที่ยอมรับเป็นความคมชัดเนื่องจากโซลูชันก่อนหน้า (lwip) ไม่ได้รับการดูแลอีกต่อไป ขอบคุณสำหรับความคิดเห็นของคุณ!


สวัสดี. ฉันมีคำถาม จะลดขนาดภาพให้ต่ำกว่า 200KB ได้อย่างไร? กรุณาอธิบายเกี่ยวกับวิธีการ ขอบคุณ.
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
  });

มันรวดเร็วมักจะ 6x เร็วกว่าที่เร็วที่สุด 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 เวอร์ชันที่คอมไพล์ไว้ล่วงหน้า คุณจะพบว่าการปรับขนาดเร็วกว่า LWIP ประมาณ 10 เท่าและใช้หน่วยความจำเพียงเล็กน้อย
Lovell Fuller

4
เพิ่มความคมชัดรองรับ gif และ svg ดั้งเดิมด้วยเวอร์ชัน 0.15 sharp.dimens.io/en/stable/changelog
jcupitt

1
เป็น 100 ไฟล์ แต่ทั้งหมดได้รับการจัดการให้คุณโดยอัตโนมัติโดย npm คุณไม่จำเป็นต้องคิดถึงมัน
jcupitt

4
@CoDEmanX บางทีลองวิ่งnpm install --global --production windows-build-toolsก่อน โปรดดูที่github.com/Microsoft/nodejs-guidelines/blob/master/…
Lovell Fuller

1
ฉันสร้างสคริปต์เล็ก ๆ น้อย ๆ ทำให้ง่ายต่อการดูว่าสิ่งต่างๆกำลังทำอะไรอยู่และจะมีลักษณะอย่างไรในเนื้อหาเช่นการ์ดบูสแทรปและพื้นหลัง: ครอบคลุมเพื่อปรับพารามิเตอร์ให้เหมาะสมที่สุดอาจจะเป็น intrest github.com/lcherone/sharp-test
Lawrence Cherone

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 repo


7
โมดูลของคุณยอดเยี่ยมมาก อย่างไรก็ตามต้องใช้หน่วยความจำมาก ฉันได้ลองwriteFile ใช้1.8Mbรูปภาพแล้วและต้องใช้หน่วยความจำ 130Mb หลังจากนั้นฉันทำการทดสอบโดยการปรับขนาด4MB, 11000x6000ภาพเป็นภาพขนาดย่อหลาย ๆ ภาพ (640,560,480, ... , 160) และใช้หน่วยความจำประมาณ 1.7GB เป็นบั๊กหรือเปล่า
Lewis

2
สวัสดี @Orion ขอบคุณสำหรับคำติชม โปรดไปที่ repo ของ Github และเปิดปัญหาพร้อมรายละเอียดเพิ่มเติมบางอย่าง (ระบบปฏิบัติการเวอร์ชันรหัสเพื่อสร้างซ้ำ) เราจะพยายามแก้ปัญหานี้ด้วยกัน :)
EyalAr

@EyalAr เฮ้ Eyal วิธีปรับขนาดและเก็บภาพ (ปรับขนาดเป็นขนาดความกว้างความสูงสูงสุดที่เป็นไปได้) โดยไม่ต้องยืด
Daniel Krom

10
ฉันไม่แนะนำให้ใช้ lwip ในปี 2017 ดูเหมือนว่าแพ็คเกจจะไม่ได้รับการสนับสนุนอีกต่อไปและมีปัญหาการติดตั้งจำนวนมากบน Windows และตอนนี้แม้แต่บนแพลตฟอร์ม Unix
zerefel

9
lwip น่าเสียดายที่เป็นโครงการที่ตายแล้ว คมแต่ดูเหมือนจะยังคงได้รับการดูแลอย่างแข็งขัน
laurent

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
นี่คือสิ่งที่ฉันกำลังมองหาโดยไม่ต้องติดตั้ง overkill การพึ่งพาภายนอกที่หนักหน่วงสำหรับฟังก์ชันสองสามอย่างที่เกี่ยวข้องกับการปรับขนาดภาพ
zacr0

3
Btw @EyalAr เป็นผู้สร้างโมดูลโหนดนี้ ความคิดเห็นของเขายังระบุไว้ด้านล่าง
Arvind

ติดตั้งและใช้งานได้ง่ายมาก ฉันชอบมากที่คุณไม่จำเป็นต้องใช้ไลบรารีไบนารีใด ๆ เช่น ImageMagick
ChrisRich

นั่นเหมือนกับคำตอบนี้ทุกประการ (เจ้าของ lwip) แต่ในภายหลัง: stackoverflow.com/a/24543924/1525495
Jorge Fuentes González

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?
Christopher Grigg

2
sharp มีชุดมาตรฐาน: sharp.dimens.io/en/stable/performance --- ในการทดสอบนั้น jimp ช้ากว่า IM 5 เท่าและช้ากว่า sharp 30 เท่า แน่นอนว่าเร็วพอก็เร็วเพียงพอและความเร็วไม่ใช่ปัจจัยเดียวที่ต้องพิจารณา
jcupitt

อาจจะไม่ใช่แบบเรียลไทม์ แต่ Jimp นั้นยอดเยี่ยมสำหรับการเขียนไฟล์ภาพขนาดย่อหลายขนาด (และเรียกคืนเป็นไฟล์แคชในภายหลัง)
coderofsalvation

jimp ไม่รองรับ webp และจะไม่รองรับในอนาคตอันใกล้ ดู: github.com/oliver-moran/jimp/issues/144
Viacheslav Dobromyslov

8

Sharpได้รับความนิยมเมื่อเร็ว ๆ นี้ แต่ก็เป็นแนวคิดเดียวกับ * Magick bindings

อย่างไรก็ตามการต้องติดตั้ง ImageMagick / GraphicsMagick เพื่อทำการปรับขนาดภาพอย่างง่ายดูเหมือนจะมากเกินไปสำหรับฉัน

การปรับขนาดภาพเป็นเรื่องง่าย รูปแบบ JPEG มีความซับซ้อนเป็นพิเศษและมีหลายวิธีในการปรับขนาดกราฟิกด้วยผลลัพธ์ที่มีคุณภาพที่แตกต่างกันซึ่งมีเพียงไม่กี่วิธีที่สามารถนำไปใช้งานได้อย่างง่ายดาย ไลบรารีการประมวลผลภาพมีไว้เพื่อทำงานนี้ดังนั้นหากไม่มีเหตุผลอื่นที่คุณไม่สามารถติดตั้งได้ให้ไปหามัน


13
บางทีฉันอาจเป็นนักพัฒนาที่ขี้เกียจ แต่ทันทีที่ฉันเห็นขั้นตอนการติดตั้งสำหรับ ImageMagick และสงสัยว่าฉันจะใช้จ่ายเท่าไรในการติดตั้งบนอินสแตนซ์ Amazon AWS EC2 ของฉันฉันก็เริ่มมองหาตัวเลือกอื่น ๆ ทันทีโดยเฉพาะอย่างยิ่งเมื่อพิจารณาว่าสิ่งที่ฉันต้องการคือ ความสามารถในการปรับขนาดภาพสำหรับภาพขนาดย่อ
ChrisRich

7

Canvas เร็วกว่า ImageMagic 2.3 เท่า

คุณสามารถลองเปรียบเทียบโมดูล 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 โดยใช้ File API

การปรับขนาดภาพฝั่งไคลเอ็นต์ด้วยจาวาสคริปต์ก่อนอัปโหลดไปยังเซิร์ฟเวอร์

ผู้ใช้หลายคนอาจมีภาพที่ดีของตัวเองจากสมาร์ทโฟนและหลายคนมีขนาดเกิน 200kB โปรดทราบว่าข้อมูลที่ไคลเอ็นต์ให้มาไม่น่าเชื่อถือดังนั้นการตรวจสอบฝั่งเซิร์ฟเวอร์จึงยังใช้


2
คุณไม่สามารถเชื่อใจไคลเอนต์ได้ผู้ใช้เพียงแค่ต้องรู้จุดสิ้นสุดการอัปโหลดเพื่อส่งสิ่งที่เขาต้องการไปที่นั่น ดังนั้นการตรวจสอบความถูกต้องเช่นขนาดไฟล์ยังคงมีผลบังคับใช้ แต่การปรับขนาดในฝั่งไคลเอ็นต์เป็นความคิดที่ดี
เคฟ

1

ผมใช้ lwip (แนะนำให้เป็นก่อนหน้านี้โดย Arvind) แต่เปลี่ยนPNG พืช ดูเหมือนว่าจะทำงานได้เร็วขึ้นเล็กน้อยสำหรับฉัน (Win 8.1 x64, Node v0.12.7) โค้ดใน repo ดูมีน้ำหนักเบาอย่างไม่น่าเชื่อและใช้งานง่าย

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 สำหรับการประมวลผลภาพด้วยภาพจากที่เก็บข้อมูล 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 () แต่มันทำงานได้ไม่ดี


จาก sharp 0.20 มันจะดาวน์โหลดไบนารีที่คอมไพล์ไว้ล่วงหน้าสำหรับเวอร์ชันโหนดที่แน่นอนของคุณบนแพลตฟอร์มส่วนใหญ่โดยอัตโนมัติดังนั้นจึงไม่จำเป็นต้องสร้างอะไรเลย
jcupitt

น่าเสียดายที่มันไม่ได้ผลสำหรับฉัน ฉันจำเป็นต้องใช้ sharp ในระบบไฟล์แบบอ่านอย่างเดียวโดยมี node.js หลายเวอร์ชันและฉันต้องดาวน์โหลดโมดูล sharp สำหรับโหนดแต่ละเวอร์ชันที่ฉันใช้และใช้เวลามากเกินไป
Alex Seceleanu

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

ปรับขนาดรูปภาพที่ใช้งานโดยใช้Google Drive API v3v3 แนะนำให้ใช้วิธีนี้สำหรับ Google Apps Script เพื่อแทรกรูปภาพลงใน Google ชีต

อัลกอริทึม:

  1. ที่อัพโหลดภาพไปยังโฟลเดอร์ Google Drive
  2. รับ URL สาธารณะของภาพขนาดย่อ
  3. แทนที่พารามิเตอร์ 'resize' ใน URL ด้วยความกว้างและ / หรือความสูงที่จำเป็น (ขนาดภาพย่อเริ่มต้นคือ 220px)
  4. ดาวน์โหลดภาพขนาดย่อที่ปรับขนาดจาก Google Drive

ดูตัวอย่างที่นี่: https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150

และระวังโควต้า GDrive:

  • คำค้นหาต่อวัน: 1000000000
  • คำค้นหาต่อ 100 วินาทีต่อผู้ใช้: 1,000
  • คำค้นหาต่อ 100 วินาที: 10,000
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.