Не беспокойтесь об обработке изображений, я дам вам десять маленьких помощников.

внешний интерфейс JavaScript
Не беспокойтесь об обработке изображений, я дам вам десять маленьких помощников.

В этой статье брат Абао познакомит своих друзей с десятью методами обработки изображений.""маленький помощник""У каждого из них у каждого есть уникальные навыки, с размытым, сжатием, обрезкой, вращением, синтезом, сравнением и другими навыками. Я считаю, что после того, как узнать их, вы сможете справиться с большинством сценариев обработки изображений с легкостью.

Прочитайте последние популярные статьи брата А Бао (спасибо за вашу поддержку и поддержку 🌹🌹🌹):

Но представляя""маленький помощник""Перед этим брат Абао сначала познакомит с некоторыми базовыми знаниями, связанными с изображениями. Кроме того, чтобы позволить друзьям узнать больше о картинках, брат А Бао тщательно подготовил"«Брат Бао хочет что-то сказать»"глава. В этой главе вы узнаете следующее:

  • Как отличить тип картинки (не суффикс файла);
  • Как получить размер картинки (не щелкнуть правой кнопкой мыши для просмотра информации о картинке);
  • Как просматривать локальные картинки (не для чтения картинок);
  • Как реализовать сжатие изображений (инструмент для сжатия изображений);
  • Как работать с пиксельными данными растрового изображения (не PS и другое программное обеспечение для обработки изображений);
  • Как реализовать стеганографию изображений (не видно невооруженным глазом).

Десять «маленьких помощников» по ​​обработке изображений не могут дождаться встречи с вами, о чем вы все еще сомневаетесь? Давайте же теперь!

Во-первых, основы

1.1 Растровое изображение

"Растровые изображения, также известные как растровые или растровые изображения, состоят из отдельных точек, называемых пикселями (элементами изображения)."Точки могут быть расположены и окрашены по-разному, чтобы сформировать узор. Когда вы увеличиваете растровое изображение, вы можете увидеть бесчисленное количество отдельных квадратов, составляющих все изображение. Эффект увеличения размера растрового изображения заключается в увеличении отдельных пикселей, в результате чего линии и фигуры выглядят зубчатыми.

"Фотографии, сделанные цифровыми камерами, изображения, отсканированные сканерами, и снимки экрана компьютера — все это растровые изображения."Отличительной чертой растрового изображения является то, что оно может отображать изменения цвета и тонкие переходы цветов, создавая реалистичные эффекты. Недостаток заключается в том, что при сохранении необходимо записывать положение и значение цвета каждого пикселя, что занимает много места для хранения. Обычно используемое программное обеспечение для обработки растровых изображений включает Photoshop, Painter и инструменты рисования, поставляемые с системами Windows.

Разрешение является непреодолимым барьером для растровых изображений: при масштабировании, вращении и других операциях над растровыми изображениями новые пиксели не могут быть получены, поэтому исходные пиксели будут увеличены, чтобы заполнить пробелы, что сделает изображение нечетким.

(Источник изображения: https://zh.wikipedia.org/wiki/%E4%BD%8D%E5%9B%BE)

Маленькие квадратики на картинке называются пикселями.Эти квадратики имеют четкое положение и присвоенное значение цвета.Цвет и положение квадратиков определяют внешний вид изображения.

Пиксель можно рассматривать как неделимую единицу или элемент всего изображения."Неделимый означает, что его нельзя разрезать на более мелкие единицы или элементы, он существует как единая цветовая сетка."Каждое растровое изображение содержит определенное количество пикселей, определяющих размер изображения на экране.

1.2 Векторы

Так называемая векторная графика — это графика, описываемая прямыми линиями и кривыми Элементами, из которых состоит эта графика, являются некоторые точки, линии, прямоугольники, многоугольники, окружности и дуги и т. д."Все они получают посредством математического расчета формулы и имеют характеристики без искажений после редактирования."Например, векторная графика картины на самом деле является контуром внешней рамки, образованной отрезками линий, а цвет, отображаемый картиной, определяется цветом внешней рамки и цветом, заключенным во внешней рамке.

"Векторная графика — это в основном геометрические фигуры, которые можно бесконечно увеличивать без изменения цвета или размытия."Обычно используется при разработке узоров, логотипов, VI, текста и других дизайнов. Обычное программное обеспечение включает: CorelDraw, Illustrator, Freehand, XARA, CAD и т. д.

Здесь мы используем те, с которыми веб-разработчики более знакомы.SVG("Масштабируемая векторная графика - Масштабируемая векторная графика") в качестве примера для понимания структуры SVG:

Масштабируемая векторная графика (SVG) — это графический формат, основанный на расширяемом языке разметки (XML) для описания двумерной векторной графики. SVG был разработан W3C и является открытым стандартом.

SVG в основном поддерживает следующие объекты отображения:

  • Векторные объекты отображения, основные объекты векторного отображения включают прямоугольники, окружности, эллипсы, многоугольники, прямые линии, произвольные кривые и т.д.;
  • Встроенные внешние изображения, в том числе PNG, JPEG, SVG и др.;
  • текстовый объект.

Поняв разницу между растровыми изображениями и векторной графикой, давайте познакомимся с математическим представлением растровых изображений.

1.3 Математическое представление растровых изображений

Пикселям растрового изображения назначаются определенные позиции и значения цвета. Информация о цвете каждого пикселя представлена ​​комбинацией RGB или значением серого.

согласно сбитовая глубина, который может классифицировать растровые изображения на 1, 4, 8, 16, 24 и 32-битные изображения и т. д. Чем больше битов информации использует каждый пиксель, тем больше цветов доступно, тем реалистичнее цветовое представление и тем больше соответствующий объем данных.

"1.3.1 Бинарное изображение"

Растровое изображение пикселя с разрядностью 1 имеет только два возможных значения (черное и белое), поэтому его еще называют бинарным изображением. Пиксели бинарного изображения только черные и белые, поэтому каждый пиксель может быть представлен 0 и 1.

Например, бинарное изображение 4*4:

1 1 0 1
1 1 0 1
1 0 0 0
1 0 1 0

"1.3.2 RGB изображения"

Изображение RGB состоит из трех цветовых каналов, где RGB представляет собой цвет красного, зеленого и синего каналов. Каждый канал в 8-битном/канальном изображении RGB имеет 256 возможных значений, что означает, что изображение имеет более 16 миллионов возможных цветовых значений. Изображения RGB с 8 битами на канал (bpc) иногда называют 24-битными изображениями (8 бит x 3 канала = 24 бита данных/пиксель). Растровые изображения, представленные с использованием 24 комбинированных битов данных RGB, часто называют растровыми изображениями с истинным цветом.

Цветное изображение RGB может быть представлено тремя матрицами: одна представляет интенсивность красного цвета в пикселях, одна представляет зеленый цвет, а третья представляет синий цвет.

(Источник изображения: https://freecontent.manning.com/the-computer-vision-pipeline-part-2-input-images/)

"Суть обработки изображения состоит в том, чтобы вычислить эти пиксельные матрицы."На самом деле, тип растрового изображения, в дополнение к изображению RGB и бинарному изображению, есть изображение в градациях серого и индексное изображение YUV. Здесь мы не делаем слишком много введения, мало заинтересованные партнеры могут получить доступ к соответствующей информации самостоятельно.

Во-вторых, библиотека обработки изображений.

2.1 AlloyImage

Движок с открытым исходным кодом для профессиональной обработки изображений на основе HTML 5.

https://github.com/AlloyTeam/AlloyImage

AlloyImageПрофессиональная библиотека обработки изображений на основе технологии HTML5 от команды Tencent AlloyTeam. Он имеет следующие особенности:

  • На основании многослойных операций - обработка одного слоя не влияет на другие слои;
  • 17 режимов наложения слоев, соответствующих PS — для плавного переноса туториалов по обработке PS;
  • Разнообразие базовых эффектов обработки фильтров — базовые фильтры постоянно дополняются и расширяются;
  • Основные функции настройки изображения - Оттенок, Насыщенность, Контрастность, Яркость, Кривые и т.д.;
  • Простой и быстрый API - обработка цепочек, простой и удобный в использовании API, гибкая передача параметров;
  • Инкапсуляция нескольких комбинированных эффектов — один код может легко создать стиль;
  • Последовательный единый интерфейс, поддержка многопоточности — одно- и многопотоковое переключение без изменения строки кода для поддержки быстрых многопоточных функций API.

Сценарии использования, рекомендуемые для команды ALLOYTEAM библиотеки, следующие:

  • Режим работы встроенной веб-страницы клиента программного обеспечения для настольных ПК >>> Ядро пакета Webkit: обработка стиля загрузки увеличенного аватара пользователя, обработка стиля альбома пользователя (среднее время обработки
  • Приложение Win8 Metro >>> Пользователь загружает аватары и загружает их после обработки уменьшенных стилей изображения (IE 10 под Win8 поддерживает многопоточность);
  • Мобильное приложение >>> Платформа Android, платформа iOS, стиль эскизов, требования к веб-обработке, такие как приложение PhoneGap, обработка стилей при загрузке онлайн-аватаров, обработка стилей при публикации изображений в мобильной сети и т. д.

"Пример использования"

// $AI或AlloyImage初始化一个AlloyImage对象
var ps = $AI(img, 600).save('jpg', 0.6);

// save将合成图片保存成base64格式字符串
var string = AlloyImage(img).save('jpg', 0.8);

// saveFile将合成图片下载到本地
img.onclick = function(){
  AlloyImage(this).saveFile('处理后图像.jpg', 0.8);
}

"Онлайн-пример"

http://alloyteam.github.io/AlloyImage/

(Источник изображения: http://alloyteam.github.io/AlloyImage/)

2.2 blurify

blurify.js is a tiny(~2kb) library to blurred pictures, support graceful downgrade from css mode to canvas mode.

https://github.com/JustClear/blurify

blurify.jsпредставляет собой небольшую библиотеку JavaScript (около 2 КБ) для размытия изображений и поддерживает плавную деградацию из режима CSS в режим Canvas. Плагин поддерживает три режима:

  • режим css: использоватьfilterсвойство, режим по умолчанию;
  • режим холста: использоватьcanvasэкспорт base64;
  • автоматический режим: сначала используйте режим css, в противном случае автоматически переключайтесь в режим холста.

"Пример использования"

import blurify from 'blurify';

new blurify({
    images: document.querySelectorAll('.blurify'),
    blur: 6,
    mode: 'css',
});

// or in shorthand

blurify(6, document.querySelectorAll('.blurify'));

"Онлайн-пример"

https://justclear.github.io/blurify/

(Источник изображения: https://justclear.github.io/blurify/)

Посмотрите, если некоторые друзья здесь думают, что это просто размывание, они не думают, что это весело, вы можете придумать что-нибудь охладитель. Эй, тебе это нужно! Брат апо прийти сразу""Холодная хватка""библиотека-midori, библиотека для анимации фоновых изображений, написанная на three.js и использующая WebGL. Изначально я хотел дать демонстрационную анимацию, но, к сожалению, один Gif слишком велик, поэтому я могу указать только адрес опыта, а заинтересованные друзья могут сделать свой собственный.опытодин раз.

адрес примера мидори: https://aeroheim.github.io/midori/

2.3 cropperjs

JavaScript image cropper.

https://github.com/fengyuanchen/cropperjs

Cropper.jsЭто очень мощный, но простой инструмент для обрезки изображений, который можно очень гибко настраивать, он поддерживает использование мобильных телефонов и поддерживает современные браузеры, включая IE9 и выше. Его можно использовать для удовлетворения таких потребностей, как загрузка обрезанного аватара, редактирование изображения продукта и т. д.

Cropper.js поддерживает следующие функции:

  • Поддерживает 39 вариантов конфигурации;
  • поддерживается 27 методов;
  • Поддержка 6 видов событий;
  • Поддержка касания (мобильный терминал);
  • Поддержка масштабирования, поворота и переворота;
  • Поддержка обрезки на холсте;
  • Поддержка обрезки изображений через холст на стороне браузера;
  • Поддержка обработки информации о направлении Exif;
  • Кроссбраузерная поддержка.

Формат файла сменного изображения (англ. Exchangeable image file format, официальная аббревиатура Exif) — это формат файла, специально установленный для фотографий с цифровых камер, который может записывать информацию об атрибутах и ​​данные съемки цифровых фотографий. Exif можно прикрепить к файлам JPEG, TIFF, RIFF и другим файлам, чтобы добавить контент, относящийся к информации о съемке цифровой камерой, а также индексную карту или информацию о версии программного обеспечения для обработки изображений.

Информация Exif помечается как начало 0xFFE1, а последние два байта указывают длину информации Exif. Таким образом, информация Exif имеет размер до 64 КБ, а для внутреннего использования используется формат TIFF.

"Пример использования"

// import 'cropperjs/dist/cropper.css';
import Cropper from 'cropperjs';

const image = document.getElementById('image');
const cropper = new Cropper(image, {
  aspectRatio: 16 / 9,
  crop(event) {
    console.log(event.detail.x);
    console.log(event.detail.y);
    console.log(event.detail.width);
    console.log(event.detail.height);
    console.log(event.detail.rotate);
    console.log(event.detail.scaleX);
    console.log(event.detail.scaleY);
  },
});

"Онлайн-пример"

https://fengyuanchen.github.io/cropperjs/

2.4 compressorjs

JavaScript image compressor.

https://github.com/fengyuanchen/compressorjs

compressorjsэто компрессор изображений JavaScript. Используйте браузер нативныйcanvas.toBlobAPI выполняет сжатие, что означает сжатие с потерями. Распространенным сценарием использования является предварительное сжатие изображений в браузере перед их загрузкой.

Чтобы добиться сжатия изображения на стороне браузера, в дополнение к использованиюcanvas.toBlobВ дополнение к API вы также можете использовать другой API, предоставляемый Canvas, а именноtoDataURLAPI, который получаетtypeа такжеencoderOptionsДва необязательных параметра.

вtypeУказывает формат изображения, по умолчаниюimage/png. а такжеencoderOptionsИспользуется для обозначения качества изображения в указанном формате изображения.image/jpegилиimage/webpВ случае качество изображения можно выбрать в диапазоне от 0 до 1. Если оно превышает диапазон значений, будет использоваться значение по умолчанию.0.92, другие параметры игнорируются.

в сравнении сcanvas.toDataURLДля API,canvas.toBlobAPI асинхронный, поэтомуcallbackпараметр, этоcallbackПервый параметр метода обратного вызова по умолчанию — преобразованный.blobинформация о файле.canvas.toBlobПодпись следующая:

canvas.toBlob(callback, mimeType, qualityArgument)

"Пример использования"

import axios from 'axios';
import Compressor from 'compressorjs';

// <input type="file" id="file" accept="image/*">
document.getElementById('file').addEventListener('change', (e) => {
  const file = e.target.files[0];

  if (!file) {
    return;
  }
  new Compressor(file, {
    quality: 0.6,
    success(result) {
      const formData = new FormData();
      // The third parameter is required for server
      formData.append('file', result, result.name);

      // Send the compressed image file to server with XMLHttpRequest.
      axios.post('/path/to/upload', formData).then(() => {
        console.log('Upload success');
      });
    },
    error(err) {
      console.log(err.message);
    },
  });
});

"Онлайн-пример"

https://fengyuanchen.github.io/compressorjs/

2.5 fabric.js

Javascript Canvas Library, SVG-to-Canvas (& canvas-to-SVG) Parser.

https://github.com/fabricjs/fabric.js

Fabric.js— это фреймворк, позволяющий легко работать с элементами Canvas HTML5. Это интерактивная объектная модель, расположенная поверх элемента Canvas, а также"SVG-to-canvas"парсер.

С помощью Fabric.js вы можете создавать и заполнять объекты на холсте. Объекты могут быть простыми геометрическими формами, такими как прямоугольники, круги, эллипсы, многоугольники, или более сложными формами, содержащими сотни или тысячи простых путей. Затем вы можете использовать мышь для масштабирования, перемещения и вращения этих объектов. и изменять их свойства - цвет, прозрачность, z-индекс и т.д. Кроме того, вы можете манипулировать этими объектами вместе, то есть группировать их простым выбором мыши.

Fabric.js поддерживает все основные браузеры, конкретная совместимость следующая:

  • Firefox 2+
  • Safari 3+
  • Opera 9.64+
  • Хром (все версии)
  • IE10, IE11, пограничный

"Пример использования"

<!DOCTYPE html>
<html>
<head></head>
<body>
    <canvas id="canvas" width="300" height="300"></canvas>
    <script src="lib/fabric.js"></script>
    <script>
        var canvas = new fabric.Canvas('canvas');
        var rect = new fabric.Rect({
            top : 100,
            left : 100,
            width : 60,
            height : 70,
            fill : 'red'
        });

        canvas.add(rect);
    </script>
</body>
</html>

"Онлайн-пример"

http://fabricjs.com/kitchensink

(Источник изображения: https://github.com/fabricjs/fabric.js)

2.6 Resemble.js

Image analysis and comparison

https://github.com/rsmbl/Resemble.js

Resemble.jsИспользуйте HTML Canvas и JavaScript для анализа и сравнения изображений. Совместимость с версиями Node.js выше 8.0.

"Пример использования"

// 比较两张图片
var diff = resemble(file)
    .compareTo(file2)
    .ignoreColors()
    .onComplete(function(data) {
        console.log(data);
     /*
     {
        misMatchPercentage : 100, // %
        isSameDimensions: true, // or false
        dimensionDifference: { width: 0, height: -1 }, 
        getImageDataUrl: function(){}
     }
    */
});

"Онлайн-пример"

http://rsmbl.github.io/Resemble.js/

2.7 Pica

Resize image in browser with high quality and high speed

https://github.com/nodeca/pica

PicaМожно использовать для изменения размера изображений в браузере без пикселизации и довольно быстро. Он автоматически выбирает лучшие из доступных технологий: веб-воркеры, веб-сборки, createImageBitmap, чистый JS.

С помощью Pica вы можете:

  • Уменьшите размер загрузки больших изображений и сэкономьте время загрузки;
  • Экономьте ресурсы сервера на обработке изображений;
  • Создание миниатюр в браузере.

"Пример использования"

const pica = require('pica')();

// 调整画布/图片的大小
pica.resize(from, to, {
  unsharpAmount: 80,
  unsharpRadius: 0.6,
  unsharpThreshold: 2
})
.then(result => console.log('resize done!'));

// 调整大小并转换为Blob
pica.resize(from, to)
  .then(result => pica.toBlob(result, 'image/jpeg', 0.90))
  .then(blob => console.log('resized to canvas & created blob!'));

"Онлайн-пример"

http://nodeca.github.io/pica/demo/

2.8 tui.image-editor

🍞🎨 Полнофункциональный редактор фотоизображений с использованием холста. Это очень просто и поставляется с отличными фильтрами.

https://github.com/nhn/tui.image-editor

tui.image-editor— полнофункциональный редактор изображений, использующий HTML5 Canvas. Он прост в использовании и предлагает мощные фильтры. В то же время он поддерживает такие операции, как обрезка, переворачивание, вращение, рисование, форма, текст, маска и фильтрация изображений на изображениях.

Браузерная совместимость tui.image-editor следующая:

  • Chrome
  • Edge
  • Safari
  • Firefox
  • IE 10+

"Пример использования"

// Image editor
var imageEditor = new tui.ImageEditor("#tui-image-editor-container", {
     includeUI: {
       loadImage: {
         path: "img/sampleImage2.png",
         name: "SampleImage",
       },
       theme: blackTheme, // or whiteTheme
         initMenu: "filter",
         menuBarPosition: "bottom",
       },
       cssMaxWidth: 700,
       cssMaxHeight: 500,
       usageStatistics: false,
});

window.onresize = function () {
  imageEditor.ui.resizeEditor();
};

Онлайн-пример

https://ui.toast.com/tui-image-editor/

2.9 gif.js

JavaScript GIF encoding library

https://github.com/jnordberg/gif.js

gif.jsэто кодировщик GIF JavaScript, который работает на стороне браузера. Он использует типизированные массивы и веб-воркер для очень быстрой визуализации каждого кадра в фоновом режиме. Библиотека работает в браузерах, которые поддерживают: Web Workers, File API и Typed Arrays.

Браузерная совместимость gif.js следующая:

  • Google Chrome
  • Firefox 17
  • Safari 6
  • Internet Explorer 10
  • Mobile Safari iOS 6

"Пример использования"

var gif = new GIF({
  workers: 2,
  quality: 10
});

// add an image element
gif.addFrame(imageElement);

// or a canvas element
gif.addFrame(canvasElement, {delay: 200});

// or copy the pixels from a canvas context
gif.addFrame(ctx, {copy: true});

gif.on('finished', function(blob) {
  window.open(URL.createObjectURL(blob));
});

gif.render();

"Онлайн-пример"

http://jnordberg.github.io/gif.js/

2.10 Sharp

High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images. Uses the libvips library.

https://github.com/lovell/sharp

SharpТипичный пример использования домена .com — преобразование больших изображений распространенных форматов в более мелкие, удобные для Интернета форматы JPEG, PNG и WebP. из-за внутреннего использованияlibvips, что делает изменение размера изображений обычно в 4-5 раз быстрее, чем при использовании настроек ImageMagick и GraphicsMagick. Помимо поддержки изменения размера изображения, Sharp также поддерживает такие функции, как вращение, извлечение, компоновка и гамма-коррекция.

Sharp поддерживает чтение изображений JPEG, PNG, WebP, TIFF, GIF и SVG. Выходные изображения могут быть в форматах JPEG, PNG, WebP и TIFF или несжатыми необработанными пиксельными данными.

"Пример использования"

// 改变图像尺寸
sharp(inputBuffer)
  .resize(320, 240)
  .toFile('output.webp', (err, info) => { ... });
       
// 旋转输入图像并改变图片尺寸                                         
sharp('input.jpg')
  .rotate()
  .resize(200)
  .toBuffer()
  .then( data => { ... })
  .catch( err => { ... });                                         

"Онлайн-пример"

https://segmentfault.com/a/1190000012903787

Этот пример из «Баогэ написал в 2018 году».Викторина Sharp генерирует эксклюзивные изображения для обмена"В этой статье в основном используется функция синтеза изображений, предоставляемая Sharp, для создания эксклюзивного плаката для обмена для каждого пользователя. Заинтересованные друзья могут прочитать исходный текст.

const sharp = require("sharp");
const TextToSVG = require("text-to-svg");
const path = require("path");

// 加载字体文件
const textToSVG = TextToSVG.loadSync(path.join(__dirname, "./simhei.ttf"));

// 创建圆形SVG,用于实现头像裁剪
const roundedCorners = new Buffer(
  '<svg><circle r="90" cx="90" cy="90"/></svg>'
);

// 设置SVG文本元素相关参数
const attributes = { fill: "white" };
const svgOptions = {
  x: 0,
  y: 0,
  fontSize: 32,
  anchor: "top",
  attributes: attributes
};

/**
 * 使用文本生成SVG
 * @param {*} text 
 * @param {*} options 
 */
function textToSVGFn(text, options = svgOptions) {
  return textToSVG.getSVG(text, options);
}

/**
 * 图层叠加生成分享图片
 * @param {*} options 
 * 
 */
async function genShareImage(options) {
  const { backgroudPath, avatarPath, qrcodePath, 
    userName, words, likes, outFilePath
  } = options;

  // 背景图片
  const backgroudBuffer = sharp(path.join(__dirname, backgroudPath)).toBuffer({
    resolveWithObject: true
  });

  const backgroundImageInfo = await backgroudBuffer;
  // 头像图片
  const avatarBuffer = await genCircleAvatar(path.join(__dirname, avatarPath));

  // 二维码图片
  const qrCodeBuffer = await sharp(path.join(__dirname, qrcodePath))
    .resize(180)
    .toBuffer({
      resolveWithObject: true
    });

  // 用户名
  const userNameSVG = textToSVGFn(userName);
  // 用户数据
  const userDataSVG = textToSVGFn(`写了${words}个字   收获${likes}个赞`);
  const userNameBuffer = await sharp(new Buffer(userNameSVG)).toBuffer({
    resolveWithObject: true
  });
  const userDataBuffer = await sharp(new Buffer(userDataSVG)).toBuffer({
    resolveWithObject: true
  });

  const buffers = [avatarBuffer, qrCodeBuffer, userNameBuffer, userDataBuffer];
  // 图层叠加参数列表
  const overlayOptions = [
    { top: 150, left: 230 },
    { top: 861, left: 227 },
    {
      top: 365,
      left: (backgroundImageInfo.info.width - userNameBuffer.info.width) / 2
    },
    {
      top: 435,
      left: (backgroundImageInfo.info.width - userDataBuffer.info.width) / 2
    }
  ];

  // 组合多个图层:图片+文字图层
  return buffers
    .reduce((input, overlay, index) => {
      return input.then(result => {
        console.dir(overlay.info);
        return sharp(result.data)
          .overlayWith(overlay.data, overlayOptions[index])
          .toBuffer({ resolveWithObject: true });
      });
    }, backgroudBuffer)
    .then((data) => {
      return sharp(data.data).toFile(outFilePath);
    }).catch(error => {
      throw new Error('Generate Share Image Failed.');
    });
}

/**
 * 生成圆形的头像
 * @param {*} avatarPath 头像路径
 */
function genCircleAvatar(avatarPath) {
  return sharp(avatarPath)
    .resize(180, 180)
    .overlayWith(roundedCorners, { cutout: true })
    .png()
    .toBuffer({
      resolveWithObject: true
    });
}

module.exports = {
  genShareImage
};

3. Брату А Бао есть что сказать

3.1 Как различать типы картинок

"Компьютер различает разные типы изображений не по суффиксу имени изображения, а по «магическому номеру»."Для некоторых типов файлов содержимое первых нескольких байтов фиксировано, и о типе файла можно судить по содержимому этих нескольких байтов.

Магические числа, соответствующие распространенным типам изображений, показаны в следующей таблице:

тип файла Расширение файла магическое число
JPEG jpg/jpeg 0xFFD8FF
PNG png 0x89504E47
GIF gif 0x47494638 (GIF8)
BMP bmp 0x424D

Здесь мы берем аватар брата Абао (abao.png) в качестве примера, чтобы проверить, имеет ли изображение правильный тип:

В процессе ежедневной разработки, если мы сталкиваемся со сценой обнаружения типов изображений, мы можем напрямую использовать некоторые готовые сторонние библиотеки. Например, если вы хотите определить, относится ли изображение к типу PNG, вы можете использоватьis-pngЭта библиотека, которая поддерживает как браузеры, так и Node.js, использует следующие примеры:

"Node.js"

// npm install read-chunk
const readChunk = require('read-chunk'); 
const isPng = require('is-png');
const buffer = readChunk.sync('unicorn.png', 0, 8);

isPng(buffer);
//=> true

"Browser"

(async () => {
 const response = await fetch('unicorn.png');
 const buffer = await response.arrayBuffer();

 isPng(new Uint8Array(buffer));
 //=> true
})();

3.2 Как получить размер изображения

Размер, битовая глубина, тип цвета и алгоритм сжатия изображения хранятся в двоичных данных файла.Давайте продолжим использовать аватар брата Абао (abao.png) в качестве примера, чтобы понять реальную ситуацию:

528 (десятичное) => 0x0210 (шестнадцатеричное)

560 (десятичное) => 0x0230 (шестнадцатеричное)

Поэтому, если мы хотим получить размер изображения, нам нужно проанализировать двоичные данные изображения в соответствии с различными форматами изображения. К счастью, нам не нужно делать это самим,image-sizeЭта библиотека Node.js помогла нам получить функцию получения размера файла основных типов изображений:

"Синхронно"

var sizeOf = require('image-size');

var dimensions = sizeOf('images/abao.png');
console.log(dimensions.width, dimensions.height);

"Асинхронный способ"

var sizeOf = require('image-size');

sizeOf('images/abao.png', function (err, dimensions) {
  console.log(dimensions.width, dimensions.height);
});

image-sizeЭта функция библиотеки все еще довольно сильна, в дополнение к поддержке формата PNG, поддержки BMP, GIF, ICO, JPEG, SVG и WebP, форматов WebP.

3.3 Как просмотреть локальные изображения

Используя HTML FileReader API, мы также можем легко реализовать функцию предварительного просмотра локального изображения. Конкретный код выглядит следующим образом:

<input type="file" accept="image/*" onchange="loadFile(event)">
<img id="output"/>
<script>
  const loadFile = function(event) {
    const reader = new FileReader();
    reader.onload = function(){
      const output = document.querySelector('output');
      output.src = reader.result;
    };
    reader.readAsDataURL(event.target.files[0]);
  };
</script>

После завершения локального предварительного просмотра изображения вы можете напрямую отправить данные URL-адресов данных, соответствующие изображению, на сервер. Ввиду этой ситуации серверу необходимо выполнить некоторую связанную обработку, чтобы нормально сохранить загруженные изображения.ExpressНапример, конкретный код обработки выглядит следующим образом:

const app = require('express')();

app.post('/upload', function(req, res){
    let imgData = req.body.imgData; // 获取POST请求中的base64图片数据
    let base64Data = imgData.replace(/^data:image\/\w+;base64,/, "");
    let dataBuffer = Buffer.from(base64Data, 'base64');
    fs.writeFile("image.png", dataBuffer, function(err) {
        if(err){
          res.send(err);
        }else{
          res.send("图片上传成功!");
        }
    });
});

3.4 Как реализовать сжатие изображений

В некоторых случаях мы надеемся, что при загрузке локального изображения изображение сначала сжимается до определенной степени, а затем отправляется на сервер, тем самым уменьшая объем передаваемых данных. Чтобы добиться сжатия изображения во внешнем интерфейсе, мы можем использовать предоставленный объект Canvas.toDataURL()метод, который получаетtypeа такжеencoderOptionsДва необязательных параметра.

вtypeУказывает формат изображения, по умолчаниюimage/png. а такжеencoderOptionsИспользуется для обозначения качества изображения в указанном формате изображения.image/jpegилиimage/webpВ случае качество изображения можно выбрать в диапазоне от 0 до 1. Если оно превышает диапазон значений, будет использоваться значение по умолчанию.0.92, другие параметры игнорируются.

Давайте посмотрим, как добиться сжатия изображения:

function compress(base64, quality, mimeType) {
  let canvas = document.createElement("canvas");
  let img = document.createElement("img");
  img.crossOrigin = "anonymous";
  return new Promise((resolve, reject) => {
    img.src = base64;
    img.onload = () => {
      let targetWidth, targetHeight;
      if (img.width > MAX_WIDTH) {
        targetWidth = MAX_WIDTH;
        targetHeight = (img.height * MAX_WIDTH) / img.width;
      } else {
        targetWidth = img.width;
        targetHeight = img.height;
      }
      canvas.width = targetWidth;
      canvas.height = targetHeight;
      let ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, targetWidth, targetHeight); // 清除画布
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      let imageData = canvas.toDataURL(mimeType, quality / 100);
      resolve(imageData);
    };
  });
}

Для возвращаемых данных изображения в формате Data URL, чтобы еще больше уменьшить объем передаваемых данных, мы можем преобразовать их в объект Blob:

function dataUrlToBlob(base64, mimeType) {
  let bytes = window.atob(base64.split(",")[1]);
  let ab = new ArrayBuffer(bytes.length);
  let ia = new Uint8Array(ab);
  for (let i = 0; i < bytes.length; i++) {
    ia[i] = bytes.charCodeAt(i);
  }
  return new Blob([ab], { type: mimeType });
}

После завершения преобразования мы можем инкапсулировать объект Blob, соответствующий сжатому изображению, в объект FormData, а затем отправить его на сервер через AJAX:

function uploadFile(url, blob) {
  let formData = new FormData();
  let request = new XMLHttpRequest();
  formData.append("image", blob);
  request.open("POST", url, true);
  request.send(formData);
}

3.5 Как манипулировать пиксельными данными растрового изображения

Если вы хотите работать с пиксельными данными изображения, мы можем использовать CanvasRenderingContext2D, предоставленныйgetImageDataчтобы получить пиксельные данные изображения, где getImageData() возвращает объект ImageData, который используется для описания пиксельных данных, подразумеваемых областью холста.Эта область представлена ​​​​прямоугольником, начальная точка (sx, sy), ширина sw, а высота sh. вgetImageDataСинтаксис метода следующий:

ctx.getImageData(sx, sy, sw, sh);

Соответствующие параметры описываются следующим образом:

  • sx: x-координата левого верхнего угла прямоугольной области данных изображения, которые необходимо извлечь.
  • sy: Y-координата левого верхнего угла прямоугольной области данных изображения, которые необходимо извлечь.
  • sw: ширина извлекаемой прямоугольной области данных изображения.
  • sh: высота прямоугольной области данных изображения, которые необходимо извлечь.

После получения пиксельных данных изображения мы можем обработать полученные пиксельные данные, такие как оттенки серого или инверсная обработка цвета. Когда обработка завершена, для отображения эффекта обработки на странице нам нужно использовать другой API, предоставляемый CanvasRenderingContext2D —putImageData.

С помощью этого API Canvas 2D API рисует данные из существующего объекта ImageData в растровое изображение. Если предоставляется нарисованный прямоугольник, отрисовываются только пиксели этого прямоугольника. На этот метод не влияет матрица преобразования холста. Синтаксис метода putImageData следующий:

void ctx.putImageData(imagedata, dx, dy);
void ctx.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);

Соответствующие параметры описываются следующим образом:

  • изображениеДанные:ImageData, объект массива, содержащий значения пикселей.
  • dx: смещение положения данных исходного изображения на целевом холсте (смещение в направлении оси X).
  • dy: смещение положения данных исходного изображения на целевом холсте (смещение в направлении оси Y).
  • dirtyX (необязательно): в данных исходного изображения положение левого верхнего угла прямоугольной области. По умолчанию используется верхний левый угол (координата x) всех данных изображения.
  • dirtyY (необязательно): в данных исходного изображения положение левого верхнего угла прямоугольной области. По умолчанию используется верхний левый угол (координата Y) всех данных изображения.
  • dirtyWidth (необязательно): в данных исходного изображения ширина прямоугольной области. По умолчанию используется ширина данных изображения.
  • dirtyHeight (необязательно): высота прямоугольной области в данных исходного изображения. По умолчанию используется высота данных изображения.

После представления соответствующего API давайте рассмотрим практический пример:

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>图片反色和灰度化处理</title>
  </head>
  <body onload="loadImage()">
    <div>
      <button id="invertbtn">反色</button>
      <button id="grayscalebtn">灰度化</button>
    </div>
    <canvas id="canvas" width="800" height="600"></canvas>
    <script>
      function loadImage() {
        var img = new Image();
        img.crossOrigin = "";
        img.onload = function () {
          draw(this);
        };
        // 这是阿宝哥的头像哟
        img.src = "https://avatars3.githubusercontent.com/u/4220799";
      }

      function draw(img) {
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        img.style.display = "none";
        var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        var data = imageData.data;

        var invert = function () {
          for (var i = 0; i < data.length; i += 4) {
            data[i] = 255 - data[i]; // red
            data[i + 1] = 255 - data[i + 1]; // green
            data[i + 2] = 255 - data[i + 2]; // blue
          }
          ctx.putImageData(imageData, 0, 0);
        };

        var grayscale = function () {
          for (var i = 0; i < data.length; i += 4) {
            var avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
            data[i] = avg; // red
            data[i + 1] = avg; // green
            data[i + 2] = avg; // blue
          }
          ctx.putImageData(imageData, 0, 0);
        };

        var invertbtn = document.getElementById("invertbtn");
        invertbtn.addEventListener("click", invert);
        var grayscalebtn = document.getElementById("grayscalebtn");
        grayscalebtn.addEventListener("click", grayscale);
      }
    </script>
  </body>
</html>

Обратите внимание, что при вызовеgetImageDataПри использовании метода для получения данных о пикселях изображения вы можете столкнуться с междоменными проблемами, такими как:

Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.

По этому вопросу вы можете прочитать"Чжан Синьсюй"Бог "Решить междоменную проблему изображения холста getImageData, toDataURL"Эта статья.

3.6 Как реализовать стеганографию изображений

"Стеганография — это метод и наука о сокрытии информации.Так называемое сокрытие информации означает, что никто, кроме предполагаемого получателя, не узнает о событии передачи или содержании информации."Стеганография по-английски называется стеганографией и происходит от Steganographia, книги Тритемиуса о криптографии и стеганографии.

На изображении ниже показан онлайн-инструмент стеганографии изображений, используемый Abaoge для"«Путь к бессмертному совершенствованию с полным стеком»"Эти 6 слов скрыты в исходной картинке, а затем для расшифровки результата скрытой информации используется соответствующий инструмент расшифровки:

(Адрес онлайн-стеганографии изображений: https://c.p2hp.com/yinxietu/)

В настоящее время существует множество схем реализации стеганографии изображений, вот несколько распространенных схем:

  • Стеганография дополнительных изображений;
  • Стеганография изображений на основе файловой структуры;
  • Стеганография изображений на основе принципа LSB;
  • Стеганография изображений JPG на основе домена DCT;
  • Стеганография цифровых водяных знаков;
  • Стеганография для толерантности изображения.

В связи с ограниченным пространством мы не будем здесь продолжать расширяться, а представлять каждую схему отдельно. Заинтересованные партнеры могут прочитать »Стеганография изображений (1)" Эта статья.

4. Справочные ресурсы

В этой статье используетсяmdniceнабор текста