In this article, We will introduce ten “little helpers” for image processing. They are all skilled in blurring, compression, cutting, rotation, composition, comparison and other skills. Once you get to know them, you’ll be able to handle most photoshop scenarios with ease.

Read Po’s recent popular articles (thanks to Digg friends for their encouragement and support 🌹🌹🌹) :

  • 1.2 W word | great TypeScript introductory tutorial (1100 + πŸ‘)
  • Top 10 TS Projects (660+ πŸ‘)
  • Understanding TypeScript generics and applications (7.8k words) (519+ πŸ‘)
  • Front-end storage in addition to localStorage what else (380+ πŸ‘)
  • You don’t know the Web Workers (on) [7.8 K words | multiple warning] (253 + πŸ‘)

❞

But before introducing “Little Helper”, He will first introduce some basic knowledge about pictures. In addition, in order to let the friends can learn more pictures related knowledge, Po Ge carefully prepared “Po Ge has to say” chapter. In this chapter you will learn:

  • How to distinguish the types of images (non-file name extensions);
  • How to get the size of the picture (not right-click to view the picture information);
  • How to preview local images (non-image readers);
  • How to implement image compression (non-image compression tools);
  • How to manipulate bitmap pixel data (not photoshop and other image processing software);
  • How to implement steganography of images (not visible to the naked eye).

Ten picture processing “little helper” already can’t wait to meet with you, still hesitate what? Let’s get going!

First, basic knowledge

1.1 the bitmap

“A bitmap, also known as a lattice image or raster image, is made up of single points called pixels (picture elements).” These points can be arranged and dyed differently to form a pattern. When you zoom in on the bitmap, you can see the countless individual squares that make up the entire image. Enlarging the size of a bitmap has the effect of increasing the size of a single pixel, making lines and shapes appear uneven.

“Bitmaps include photos taken with digital cameras, images scanned by scanners and computer screenshots.” The characteristic of bitmap is that it can show the change of color and the subtle transition of color, producing realistic effect. The disadvantage is that the position and color value of each pixel need to be recorded when saving, occupying a large storage space. The commonly used bitmap processing software includes Photoshop, Painter and Windows system’s own drawing tools.

Resolution is an insurmountable barrier for bitmaps. When zooming and rotating bitmaps, new pixels cannot be produced, so the original pixels will be enlarged to fill the gaps, which will make the picture appear unclear.


(photo: https://zh.wikipedia.org/wiki/%E4%BD%8D%E5%9B%BE)

The squares in the image are called pixels, and each of these squares has a specific location and assigned a number of colors that determine what the image looks like.

You can think of pixels as indivisible units or elements in the entire image. “Indivisible means it can’t be cut into smaller units or elements, it exists as a single color cell.” Each dot matrix image contains a number of pixels that determine the size of the image on the screen.

1.2 the vector diagram

The so-called vector graph, is the use of straight lines and curves to describe the graph, the elements of these graphs are some points, lines, rectangles, polygons, circles and arcs, “they are obtained through mathematical formula calculation, with the characteristics of editing without losing the truth.” For example, the vector graph of a painting is actually formed by line segments to form the outline of the outer frame, and the color of the outer frame and the color enclosed by the outer frame determine the color displayed by the painting.

“Vector drawings are dominated by geometric shapes, which can be infinitely magnified without discoloration or blurring.” Commonly used in design, logo, VI, text and so on. Commonly used software: CorelDraw, Illustrator, Freehand, XARA, CAD and so on.

To understand the structure of SVG (Scalable Vector Graphics), which is well known to Web developers:


Scalable Vector Graphics (English: Scalable Vector Graphics (SVG) is a Graphics format based on extensible Markup Language (XML) for describing two-dimensional Vector Graphics. SVG, developed by the W3C, is an open standard.

SVG mainly supports the following display objects:

  • Vector display object, the basic vector display object includes rectangle, circle, ellipse, polygon, straight line, arbitrary curve, etc.
  • Embedded external images, including PNG, JPEG, SVG, etc.
  • Text object.

After understanding the difference between bitmap and vector map, let’s introduce the mathematical representation of bitmap.

1.3 Mathematical representation of bitmaps

Bitmap pixels are assigned specific positions and color values. The color information of each pixel is represented by RGB combinations or grayscale values.

According to the bit depth, bitmaps can be divided into 1, 4, 8, 16, 24 and 32 bit images. The more bits of information each pixel uses, the more colors available, the more realistic the color representation, and the greater the corresponding amount of data.

1.3.1 Binary image

A pixel bitmap with bit depth of 1 has only two possible values (black and white), so it is also called a binary image. Binary images have only black and white pixels, so each pixel can be represented by 0 and 1.

For example, a 4 * 4 binary image:

1 1 0 1
1 1 0 1
1 0 0 0
1 0 1 0
Copy the code

1.3.2 RGB image

RGB images are composed of three color channels, in which RGB represents the colors of red, green and blue channels. Each channel in an 8-bit/channel RGB image has 256 possible values, which means that the image has more than 16 million possible color values. RGB images with 8-bit/channel (BPC) are sometimes referred to as 24-bit images (8-bit x 3-channel = 24-bit data/pixel). Bitmaps that use 24-bit RGB combined data bits are usually referred to as true color bitmaps.

RGB color images can be represented by three matrices: one that represents the intensity of red in pixels, one that represents green, and one that represents blue.


(photo: https://freecontent.manning.com/the-computer-vision-pipeline-part-2-input-images/)

“The essence of image processing is really computing these pixel matrices.” In fact, in bitmap image types, in addition to binary image and RGB image, there are gray image, index image and YUV image. Here we do not do too much introduction, interested partners, you can refer to the relevant information.

Second, image processing library

2.1 AlloyImage

❝

HTML 5 – based professional image processing open source engine.

https://github.com/AlloyTeam/AlloyImage

❞

AlloyImage professional image processing library based on HTML5 technology, from Tencent AlloyTeam team. It has the following features:

  • Multi-layer operation – one layer does not affect the other layers;
  • 17 layer blending modes corresponding to Photoshop — easy for seamless migration of PHOTOSHOP tutorials;
  • A variety of basic filter processing effects — the basic filter is constantly rich and extensible;
  • Basic image adjustment functions — hue, saturation, contrast, brightness, curve, etc.
  • Simple and fast API — chain processing, SIMPLE and easy to use API, flexible parameter transfer;
  • Multiple combination effect encapsulation – one line of code to easily achieve a style;
  • Interface consistent single, multithreading support – single, multithreading switching without changing a line of code, multithreading maintains fast API features.

The AlloyTeam suggests the following usage scenarios for this library:

  • Desktop software client embedded webpage running mode >>> Package Webkit kernel: large user profile picture uploading style processing, user album style processing (processing time < 1s on average);
  • Win8 δΈ‹ IE 10 support multithreading; Win8 δΈ‹ IE 10 support multithreading;
  • Requirements for Web processing of small image style on Android platform and iOS platform, such as PhoneGap application, style processing when uploading online profile picture, style processing when sharing pictures on Mobile Web terminal, etc.

Use the sample

$AI or AlloyImage initializes an AlloyImage object
var ps = $AI(img, 600).save('jpg'.0.6);

// save Saves the composite image as a Base64 format string
var string = AlloyImage(img).save('jpg'.0.8);
 // saveFile downloads the composite image locally img.onclick = function(){  AlloyImage(this).saveFile('Processed image.jpg'.0.8); } Copy the code

Online sample

❝

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

❞


(photo: 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 is a small JavaScript library (about 2 KB) for image blur and supports elegant degradation from CSS mode to Canvas mode. The plug-in supports three modes:

  • CSS mode: UsedfilterProperty, default mode;
  • Canvas mode: UsecanvasExport base64;
  • Auto mode: CSS mode is preferred; otherwise, canvas mode is automatically switched to.

Use the sample

import blurify from 'blurify';

new blurify({
    images: document.querySelectorAll('.blurify'),
    blur: 6. mode: 'css'.});  // or in shorthand  blurify(6.document.querySelectorAll('.blurify')); Copy the code

Online sample

❝

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

❞


(photo: https://justclear.github.io/blurify/)

See if some of your friends think it’s just a blur, think it’s not enough, can you come to something cooler? Hey, hey, whatever you want! I immediately came up with midori, a library for creating animations for background images, written in three.js and using WebGL. Originally wanted to give a demo Gif, but a single Gif is too large, can only put an experience address, interested partners to experience.

❝

Midori sample address: https://aeroheim.github.io/midori/

❞

2.3 cropperjs

❝

JavaScript image cropper.

https://github.com/fengyuanchen/cropperjs

❞

Cropper.js is a very powerful and simple image cropping tool, it can be configured very flexible, support mobile terminal use, support including IE9 and modern browsers. It can be used to meet needs such as cropping profile picture uploads and product image editing.

Cropper.js supports the following features:

  • Supports 39 configuration options;
  • 27 methods are supported;
  • Six events are supported;
  • Support touch (mobile terminal);
  • Supports zooming, rotation, and flipping;
  • Support clipping on canvas;
  • Supports clipping images from canvas in the browser;
  • Support Exif direction information processing;
  • Cross-browser support.

❝

Exchangeable Image File Format (Exif) is a file format specially set for digital camera photos, which can record the attribute information and shooting data of digital photos. Exif can be attached to JPEG, TIFF, RIFF and other files to increase the content of the digital camera shooting information and the version information of the index map or image processing software.

The Exif message starts with 0xFFE1, and the last two bytes indicate the length of the Exif message. So Exif information is up to 64 kB in size and TIFF format internally.

❞

Use the sample

// 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);  }, }); Copy the code

Online sample

❝

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

❞


2.4 compressorjs

❝

JavaScript image compressor.

https://github.com/fengyuanchen/compressorjs

❞

Compressorjs is a JavaScript image compressor. Compression is done using the browser’s native Canvas.toblob API, which means it is lossy compression. A common usage scenario is to precompress images on the browser before they are uploaded.

To achieve image compression on the browser side, besides using canvas.toBlob API, you can also use another API provided by Canvas, namely toDataURL API, which takes two optional parameters, Type and encoderOptions.

Type indicates the image format. The default value is image/ PNG. EncoderOptions is used to indicate the quality of the image. If the image format is image/ JPEG or image/webp, the quality of the image can be selected from 0 to 1. If the value is outside the range, the default value of 0.92 will be used and other parameters will be ignored.

The Canvas. toBlob API is asynchronous compared to canvas.toDataURL API, so it has a callback parameter. The default first parameter of this callback method is the converted blob file information. Canvas. toBlob’s signature is as follows:

canvas.toBlob(callback, mimeType, qualityArgument)
Copy the code

Use the sample

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((a)= > {  console.log('Upload success');  });  },  error(err) {  console.log(err.message);  },  }); }); Copy the code

Online sample

❝

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 is a framework that makes it easy to use the HTML5 Canvas element. It is an interactive object model that sits on top of the Canvas element and is also an “SVG-to-Canvas” parser.

With fabric.js, you can create and fill objects on the canvas. Objects can be simple geometric shapes, such as rectangles, circles, ellipses, polygons, or more complex shapes with hundreds or thousands of simple paths. You can then use the mouse to scale, move and rotate these objects. And modify their properties — color, transparency, Z-index, etc. You can also manipulate these objects together, grouping them with a simple mouse selection.

Fabric.js supports all major browsers. The compatibility is as follows:

  • Firefox 2+
  • Safari 3+
  • Opera 9.64 +
  • Chrome (all versions)
  • IE10, IE11, Edge

Use the sample


      
<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> Copy the code

Online sample

❝

http://fabricjs.com/kitchensink

❞


(photo: https://github.com/fabricjs/fabric.js)

2.6 Resemble.js

❝

Image analysis and comparison

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

❞

Eplay.js uses HTML Canvas and JavaScript to analyze and compare images. Compatible with Node.js versions later than 8.0.

Use the sample

// Compare two images
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(){}  } * / }); Copy the code

Online sample

❝

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 can be used to resize images in a browser, without pixelation and fairly quickly. It automatically selects the best available technology: Webworkers, WebAssembly, createImageBitmap, pure JS.

With Pica, you can:

  • Reduce the upload size of large images to save upload time;
  • Save server resources in image processing;
  • Generate thumbnails in your browser.

Use the sample

const pica = require('pica') ();
// Resize the canvas/image
pica.resize(from, to, {
  unsharpAmount: 80. unsharpRadius: 0.6. unsharpThreshold: 2 }) .then(result= > console.log('resize done! '));  // Resize and convert to Blob pica.resize(from, to)  .then(result= > pica.toBlob(result, 'image/jpeg'.0.90))  .then(blob= > console.log('resized to canvas & created blob! ')); Copy the code

Online sample

❝

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

❞


2.8 tui.image-editor

❝

🍞🎨 Full-featured photo image editor using canvas. It is really easy, and it comes with great filters.

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

❞

Tui. image-Editor is a full-featured image editor using HTML5 Canvas. It is easy to use and provides powerful filters. It also supports cropping, flipping, rotating, drawing, shape, text, masking and image filtering.

The browser compatibility of tui.image-editor is as follows:

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

Use the sample

// 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(); }; Copy the code

Online sample

❝

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

❞


2.9 gif.js

❝

JavaScript GIF encoding library

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

❞

GIF. Js is a JavaScript GIF encoder that runs on the browser side. It uses typed arrays and Web workers to render every frame in the background, which is really fast. The library works in browsers that support: Web Workers, File apis, and Typed Arrays.

GIF. Js is compatible with the following browsers:

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

Use the sample

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(); Copy the code

Online sample

❝

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 is typically used to convert large images in common formats to smaller, web-friendly JPEG, PNG, and WebP formats. Due to the internal use of libvips, resizing images is usually 4-5 times faster than using ImageMagick and GraphicsMagick Settings. In addition to resizing images, Sharp supports rotation, extraction, composition, and gamma correction.

Sharp supports reading JPEG, PNG, WebP, TIFF, GIF and SVG images. Output images can be in JPEG, PNG, WebP and TIFF formats, as well as raw, uncompressed pixel data.

Use the sample

// Change the image size
sharp(inputBuffer)
  .resize(320.240)
  .toFile('output.webp', (err, info) => { ... });
       
// Rotate the input image and change the image size sharp('input.jpg')  .rotate()  .resize(200)  .toBuffer()  .then( data= >{... }) .catch( err= >{... });Copy the code

Online sample

❝

https://segmentfault.com/a/1190000012903787

❞

This example is from an article written by Sharp in 2018. It mainly uses the image composition function provided by Sharp to create exclusive sharing posters for each user. Interested parties can read the original article.

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

// Load the font file
const textToSVG = TextToSVG.loadSync(path.join(__dirname, "./simhei.ttf"));  // Create a circular SVG to crop your avatar const roundedCorners = new Buffer(  '<svg><circle r="90" cx="90" cy="90"/></svg>' );  // Set the SVG text element parameters const attributes = { fill: "white" }; const svgOptions = {  x: 0. y: 0. fontSize: 32. anchor: "top". attributes: attributes };  / * ** Generate SVG using text * @param {*} text  * @param {*} options * / function textToSVGFn(text, options = svgOptions) {  return textToSVG.getSVG(text, options); }  / * ** Overlay layers to generate shared images * @param {*} options  * * / async function genShareImage(options) {  const { backgroudPath, avatarPath, qrcodePath,  userName, words, likes, outFilePath  } = options;   // Background image  const backgroudBuffer = sharp(path.join(__dirname, backgroudPath)).toBuffer({  resolveWithObject: true  });   const backgroundImageInfo = await backgroudBuffer;  // The profile picture  const avatarBuffer = await genCircleAvatar(path.join(__dirname, avatarPath));   //  const qrCodeBuffer = await sharp(path.join(__dirname, qrcodePath))  .resize(180)  .toBuffer({  resolveWithObject: true  });   / / user name  const userNameSVG = textToSVGFn(userName);  // User data  const userDataSVG = textToSVGFn(` wrote${words}A word to harvest${likes}A great `);  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];  // Layer overlay parameter list  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  }  ];   // Combine multiple layers: image + text layer  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.');  }); }  / * ** Generates a round avatar* @param {*} avatarPath avatarPath* / function genCircleAvatar(avatarPath) {  return sharp(avatarPath)  .resize(180.180)  .overlayWith(roundedCorners, { cutout: true })  .png()  .toBuffer({  resolveWithObject: true  }); }  module.exports = {  genShareImage }; Copy the code

Third, Po Ge has something to say

3.1 How to distinguish the types of pictures

“Computers do not discriminate between image types by their name suffixes, but by ‘Magic numbers’.” For some types of files, the first few bytes are fixed, and the file type can be determined based on the contents of these few bytes.

The magic numbers corresponding to common image types are shown in the following table:

The file type The file suffix The magic number
JPEG jpg/jpeg 0xFFD8FF
PNG png 0x89504E47
GIF gif 0 x47494638 (GIF8)
BMP bmp 0x424D

Here we use the image of Abao.png as an example to verify that the image type is correct:


In the daily development process, if we encounter a scenario to detect image types, we can directly use some ready-made third-party libraries. For example, if you want to determine if an image is PNG, you can use the IS-png library, which supports both browser and Node.js, as shown in the following example:

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 Copy the code

Browser

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

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

3.2 How to obtain the picture size

The size, bit depth, color type and compression algorithm of the image are all stored in the binary data of the file. Let’s continue to use the image of Abao.png as an example to understand the actual situation:


❝

528 (decimal) => 0x0210 (hexadecimal)

560 (decimal) => 0x0230 (hexadecimal)

❞

So if we want to get the size of the image, we need to parse the image binary data according to different image formats. Fortunately, we don’t have to do this ourselves. The image-size node. js library already provides us with the ability to get file sizes for major image types:

synchronously

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

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

asynchronous

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

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

Image-size is a powerful library that supports BMP, GIF, ICO, JPEG, SVG and WebP formats in addition to PNG.

3.3 How Do I Preview a Local Image

Using the HTML FileReader API, we can also easily implement the local image preview function, the code is as follows:

<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> Copy the code

After the local image preview is complete, you can submit the Data URLs for the image directly to the server. In this case, the server needs to do some related processing to save the uploaded image normally. Here, Express is used as an example. The specific processing code is as follows:

const app = require('express') ();
app.post('/upload'.function(req, res){
    let imgData = req.body.imgData; // Get base64 image data in the POST request
    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("Picture uploaded successfully!");  }  }); }); Copy the code

3.4 How to Compress pictures

In some cases, we want to compress the image before submitting it to the server to reduce the amount of data transferred. To achieve image compression on the front end, we can use the toDataURL() method provided by the Canvas object, which takes two optional parameters, Type and encoderOptions.

Type indicates the image format. The default value is image/ PNG. EncoderOptions is used to indicate the quality of the image. If the image format is image/ JPEG or image/webp, the quality of the image can be selected from 0 to 1. If the value is outside the range, the default value of 0.92 will be used and other parameters will be ignored.

Let’s take a look at how to implement image compression:

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 = (a)= > {  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); // Clear the canvas  ctx.drawImage(img, 0.0, canvas.width, canvas.height);  let imageData = canvas.toDataURL(mimeType, quality / 100);  resolve(imageData);  };  }); } Copy the code

To further reduce the amount of Data transferred, we can convert the returned image Data in the Data URL format to a Blob object:

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 }); } Copy the code

After the transformation is complete, the Blob object corresponding to the compressed image can be wrapped in a FormData object and then submitted to the server via 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); } Copy the code

3.5 How do I Operate Bitmap Pixel Data

If we want to manipulate image pixel data, we can retrieve image pixel data using getImageData provided by CanvasRenderingContext2D, where getImageData() returns an ImageData object, It is used to describe the pixel data hidden in the Canvas area, which is represented by a rectangle with the starting point (sx, SY), width (SW) and height (sh). The syntax of getImageData is as follows:

ctx.getImageData(sx, sy, sw, sh);
Copy the code

The parameters are described as follows:

  • Sx: The upper-left x-coordinate of the rectangular region of the image data to be extracted.
  • Sy: Y coordinates of the upper-left corner of the rectangular region of the image data to be extracted.
  • Sw: Width of the rectangular area of image data to be extracted.
  • Sh: height of the rectangle region of image data to be extracted.

After obtaining the pixel data of the picture, we can process the obtained pixel data, such as grayscale or invert color processing. When the processing is complete, to display the processing effect on the page, we need to make use of putImageData, another API provided by CanvasRenderingContext2D.

This API is the Canvas 2D API’s way of drawing data from an existing ImageData object. If a drawn rectangle is provided, only the pixels of that rectangle are drawn. This method is not affected by the canvas transformation matrix. The syntax of the putImageData method is as follows:

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

The parameters are described as follows:

  • ImageData: imageData, an array object containing pixel values.
  • Dx: The offset (X-axis offset) of the source image data in the destination canvas.
  • Dy: The offset of the position of the source image data in the target canvas (the offset in the y direction).
  • DirtyX (Optional) : Position of the upper-left corner of the rectangle in the source image data. The default is the upper left corner (x-coordinate) of the entire image data.
  • DirtyY (Optional) : Position of the upper-left corner of the rectangle in the source image data. The default is the upper left corner (y-coordinate) of the entire image data.
  • DirtyWidth (Optional) : Width of the rectangular region in the source image data. The default is the width of the image data.
  • DirtyHeight (Optional) : Height of the rectangular region in the source image data. The default is the height of image data.

Having introduced the relevant API, let’s take a practical example:


      
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
 <title>Image reverse color and grayscale processing</title>  </head>  <body onload="loadImage()">  <div>  <button id="invertbtn">The color</button>  <button id="grayscalebtn">Gray,</button>  </div>  <canvas id="canvas" width="800" height="600"></canvas>  <script>  function loadImage() {  var img = new Image();  img.crossOrigin = "";  img.onload = function () {  draw(this);  };  // This is a picture of Po Ge  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> Copy the code

Note that you may encounter cross-domain problems when calling the getImageData method to get image pixel data, such as:

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

For this problem, you can read the article “Zhang Xinxu” to solve canvas Picture getImageData,toDataURL cross-domain problem “.

3.6 How to Implement Image Steganography

“Steganography is the art and science of hiding information from anyone other than the intended recipient about the event or content of a message.” Steganography, or Steganography, comes from The Title of Trithmius’ book Steganographia, which tells the story of cryptography and Steganography. The title comes from the Greek word meaning “writing in secret.”

The following figure is the result of using online steganography tool to hide the six words “The road to immortality” in the original picture, and then using the corresponding decryption tool to decrypt the hidden information:


(online image steganalysis experience address: https://c.p2hp.com/yinxietu/)

At present, there are many schemes to implement steganography. The following are some common schemes:

  • Attached steganography of pictures;
  • Steganography based on file structure;
  • Image steganography based on LSB principle;
  • JPG steganography based on DCT domain;
  • Steganography of digital watermarking;
  • Steganography of image tolerance.

We don’t have enough space to go into each of these scenarios. If you are interested in steganography, you can read the article “Steganography: Picture Steganography (PART 1)”.

Iv. Reference resources

  • Baike – Vector diagram
  • Wiki – Scalable vector graphics
  • Steganography pictures steganography (I)
  • Unspeakable secret – Picture steganography that can be played on the front end
  • The evolution of the two generations and the underlying principle of the multi-million level image search system
  • image-manipulation-libraries-for-javascript

This article is formatted using MDNICE