preface

Writing background

Recently, I have done a lot of business involving the content related to pictures, so the leader suggested me to sort out the content related to pictures commonly used in the business, so as to facilitate the students in the group to have corresponding solutions to the same problem. Therefore, THIS article is drawn from this, and I hope it can also be helpful to students who meet relevant problems.

Read the instructions

This paper classifies the picture scheme from the user’s operation habits, from upload, download to display and others, divided into four categories. Although it’s a collection, there are bound to be some scenes that are missing, so look at the following figure before you read to see if there are any themes you need:

Key points:

  1. This article is just to integrate solutions and provide technical ideas, because some of them have not been carried out in the business, so these contents cannot be guaranteed to be feasible. (Generally, it works, but there may be some problems.)
  2. This article is not for front end beginners, it is not a step by step solution from 0 to 1, but beginners can search the relevant information for more details.

Upload the related

Pictures to choose

Image Type selection

The accepte attribute for input can be set as follows

Upload a file Set the Accepte property to
png image/png
gif image/gif
Jpeg or JPG image/jpeg
Any pictures image/*
. .

1.1 Various types of use, segmentation, such as accept = “image/ PNG,image/ JPEG”

1.2 This only limits the browser’s file selection properties. Users can still select all files and upload files that do not meet the expected file types

Picture a multiple-choice

Multiple selection can be controlled by the multiple attribute of the input element

Note:

The number of pictures can not be selected by native control (if there is a message to inform, thank you ~). If you need to control the number of pictures, you need to select pictures and listen to the number of files in the input onchange to judge.

Advice:

  1. Add an obvious prompt near the button that selects upload to inform the user of the maximum number of images to upload. As for the logic of uploading more than the number, you can decide according to the business scenario: uploading the first few pictures within the upper limit, or not uploading all of them;
  2. When the H5 page is embedded in the APP end and the native upload scheme input is used, the APP selects images, that is, the upper limit of images may be limited by the APP end.

Paste selection image

This requirement is not applied in the author’s business for the time being, because the author’s common upload scenario is that there are multiple single upload buttons on a page, and paste and select pictures to upload, which is suitable for the scenario with only a single selector in a single page (personal opinion).

The core logic is to listen for paste events, as shown below. Note that the browser is calculating here, so the printed value may be incorrect, as shown in Figure 2. The value cannot be seen after the object is expanded.

For a more detailed introduction, you can see Zhang Xinxu’s blog: front-end JS implementation of directly cutting and pasting pictures.

Note:

1. Many sources say that this API cannot monitor the content of pictures in local files, but it is found that some websites can. I don’t know how to implement it.

2 you need to pay attention to the presentation of the API in different browsers, namely compatibility.

Verify files before uploading

Whether using A UI library such as ANTD, or using a native INPUT, the core point is basically written logically based on the onchange event of input, in which you can get some relevant information about the file, its structure is roughly as follows:

Get the above file information and compare it accordingly

1 File size, the size shown in the figure above, in bytes. If it is converted to Base64, the length of the file can also be obtained through certain calculation. According to the base64 conversion rules, three 8-bit bytes (3*8=24) are converted into four 6-bit bytes (4*6=24), which are then preceded by two zeros. , the sample code is as follows:

computeFileSize: (base64) = > {
// base64 header such as data:image/ JPG; base64
let str = base64.split(', ') [1]; 
const equalIndex = str.indexOf('='); 
if (str.indexOf('=') > 0) {
    // Find the equal sign and remove the equal sign
    str = str.substring(0, equalIndex);
}
const length = str.length;
// The computed file stream size, in bytes
const fileSize = ~~(length - (length / 8) * 2); 

return fileSize / 1024; // Convert in KB
Copy the code

2 File name extension, the type in the image above, where type is the file name extension when you upload the file, not the actual file name extension. For example, if you change an Excel file to.jpeg, where type is image/ JPEG, not Excel, if you want to verify the actual file type, Refer to my previous article: the core logic is to read the beginning of the binary stream of a file

Preprocess files before uploading them

The core logic is to use Canvas to redraw the picture once. It should be noted that Canvas should operate after image onload when drawing. Because the canvas. drawImage method takes the first argument to canvasImageSource. Maybe the createImageBitmap API doesn’t need to be executed in image.onload because its documentation says it can be loaded using Blob and rendered using fileReader after reading the binary stream of the file. But this method has not been tried before, so you can try it if you are interested.

Image cropping

This block has not been used in the actual project by the author. Here is someone else’s plan: Canvas clipping picture

The idea is as follows: Get the fixed point coordinates of the relative position between the clipping frame and the picture to be clipped, namely the red point in the figure, and use API offsetTop and offsetLeft

W1 is the width of the picture to be clipped, and W2 is the width of the clipping box. To get the width, height and coordinates, you can use the drawImage of canvas for clipping drawing. API extracted from W3School, as follows:

DrawImage parameter (in order) meaning
img Specify the image, canvas, or video to use.
sx Optional. The x position at which the shear began.
sy Optional. The y position where the shear started.
swidth Optional. The width of the clipped image.
sheight Optional. The height of the clipped image.
x Place the x position of the image on the canvas.
y Place the y coordinate position of the image on the canvas.
width Optional. The width of the image to use. (Stretch or zoom out image)
height Optional. The height of the image to use. (Stretch or zoom out image)

For example, the width and height of the original picture are 534 * 345, the width and height of the cropped box are 434 * 145, and the red dot coordinate position is (50,100). DrawImage (img,50, 100,434, 145,0, 0,534, 345), the resulting image is cropped and enlarged to the same size as the original image.

Note: all 7 parameters must be passed because the interface definition for this must have 3 or 5 or 8 parameters, as shown below:

Automatically straighten

Use exif.js library to complete, this kind of related articles also have a lot of, you can search, you can also see my previous article, here is no longer described, the article address upload rotation

Note: today’s browsers may automatically correct this: browser rotation compatibility, with the following solution: javasjavascript load-image

const testAutoOrientationImageURL =
    'data:image/jpeg; base64,/9j/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAYAAAA' +
    'AAAD/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA' +
    'QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE' +
    'BAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAf/AABEIAAEAAgMBEQACEQEDEQH/x' +
    'ABKAAEAAAAAAAAAAAAAAAAAAAALEAEAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAAAAAAA' +
    'AAAAAEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwA/8H//2Q==';

let isImageAutomaticRotation; // Check whether the browser supports rotation by default

detectImageAutomaticRotation: (a)= > (
    // Use a special image to check whether the current browser corrects images with EXIF information
    // method source: https://github.com/blueimp/JavaScript-Load-Image/blob/6dc04e85d62d395d93c4bfdd35644772027671d1/js/load-image-orientation .js
    new Promise((resolve) = > {
        if (isImageAutomaticRotation === undefined) {
            const img = new Image();
            img.src = testAutoOrientationImageURL;
            img.onload = (a)= > {
                        // If the image becomes 1x2, the browser has corrected the image
                isImageAutomaticRotation = img.width === 1 && img.height === 2;
                resolve(isImageAutomaticRotation);
            };
        } else{ resolve(isImageAutomaticRotation); }}))const checkIsAutoRotate = await detectImageAutomaticRotation();
if (true === checkIsAutoRotate) {
    ctx.drawImage(this.0.0, imgWidth, imgHeight);
} else {
    // Use EXIF to determine the rotation Angle before the image
}
Copy the code

Add a watermark

Because the watermark is determined by business needs, the specific logic will not be released, you can search the relevant point according to the actual drawing effect of the business good, this kind of article has been a lot.

const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
// image Instance object
const imageUpload = new Image();
imageUpload.src = originImgUrl;
imageUpload.setAttribute('crossOrigin'.'anonymous');
imageUpload.onload = (a)= > {
    canvas.width = imageUpload.width;
    canvas.height = imageUpload.height;
    // Canvas draws the image
    context.drawImage(imageUpload, 0.0);
    // Draw watermark logic, such as add a name in the lower right corner, etc.// Export the image URL in base64 format after drawing
    canvas.toDataURL('image/jpeg')}Copy the code

Note: please investigate whether the file storage service of the company platform will automatically add watermarks, otherwise you will fold two layers of watermarks, just like folding murder books.

Image compression

At present, the commonly used scheme of picture compression is to compress the length and width of the picture proportionally, and the general business has been enough to meet expectations. This kind of article is also a lot of, can own search engine, or I also mentioned before the article: upload compression.

If you don’t want to adjust the size of the picture, you can try to modify the bit depth and other attributes of the picture. This block has not been investigated, so it may not be feasible.

Formal upload

Single upload

Author Department Service transmission is classified into base64 and file stream. If the file stream type is transmitted, the request header is multipart/form-data, and file stream is transmitted as the main parameter.

If you are transmitting Base64, you need to pay attention to it, because in form-data, there is a + sign in Base64, and when transmitting, the + sign will be treated as a space. Front-end base64 encodeURIComponent, back-end corresponding decoding can be.

Note: this conclusion may not be accurate, as it is based only on the JSON transfer and file stream. It is not clear whether there are other headers or other reasons.

More than one

In multiple cases, Base64 is currently used for delivery

Put base64 of multiple images into an array, and then transfer JSON. (Base64 problem same as above)

Breakpoint continuingly

Has not been actually applied in the business, the real use of business students pay attention to pit.

  1. The file flows through a slice slice and is converted into an object-like format and submitted to the back end
{file: the file to slice, index: the subscript of the slice, size: the size of the slice, totalSize: the total file size, totolCount: the number of slices,}Copy the code
  1. When the front end listens that the transferred slice subscript is the last file fragment, it tells the back end that the file has been successfully transferred. (Can be through another interface)
  2. Or, if the original file length or total slice is known, the back end can know whether the current file fragment is the last file (index === totolCount) when it gets the file fragment. Or the size of all previous files plus the size of this file is equal to totolSize to let the back end know that the file has been transferred. The back end performs the merge file operation.

The actual code can try this article: Resumable from breakpoint

Because the author generally large file image needs less; The second is the large file image rendering, there is a certain cost of optimization. So there are very few business scenarios where you really need to do a breakpoint continuation operation on an image. Except for cloud services

download

Download the program, can be front-end implementation, can also be made back-end implementation, can be assessed according to the technical cost of both sides to make a decision. In fact, this can be used not only for images, but also for other files.

Single image download

  1. Right-click directly save as a picture (PC), long press the picture to pop up the operation options similar to the right-click menu, save the picture (mobile)
  2. Download using native A tags
  3. JS control download, first through AJAX and other requests, from the server to the file source (binary stream object) or image address, after its own business logic (such as verification, etc.), and then passed into a label, the same as the principle of the second step

Multiple images to download (packaged download)

  1. You need to inform the back end of the selected image identification information (such as the address of the image, file flow, etc., depending on the services of each party). The back end returns the compressed file flow packed with multiple images, and you can go to the third step of downloading a single image. The advantage of this scheme is that the experience is acceptable, the front-end cost is low, but the disadvantage is that the back-end needs to cooperate;
  2. Take the array of selected files, call library: JSZip, and merge the image into the Zip file to download. The advantage of this scheme is that the experience is acceptable without back-end configuration, but the disadvantage is that the third-party library needs to be introduced, and the volume and front-end cost are slightly larger.
  3. Take the array of selected files, iterate through the array, and keep building the A tag element to trigger a single image download. The advantage of this scheme is that the front-end cost is acceptable without the back-end configuration, while the disadvantage is that the experience is slightly insufficient. This scheme should be called batch download: click the button and the browser can download 10 pictures.

Display at the

The watermark

The watermark logic has been mentioned above and will not be repeated

rotating

The Rotate of CSS3 can be used for everyday services.

Note: Rotate is an attribute value under transform. If other apis are used, check whether other attributes are affected.

For example: Transform :rotate(7deg) translate(40%,20%);

Rotate (97deg) rotate(97deg) rotate(97deg) rotate(97deg) rotate(97deg) rotate(97deg) translate(40%,20%)

The zoom

Transorm’s attribute scale and Zoom can also be used to complete the scaling function, but zoom is not a specification defined attribute.

  1. Zoom is scaled relative to the top left corner, while scale defaults to center scale;
  2. Zoom changes the amount of space that an element takes up, while scale’s original size remains the same and the layout of the page does not change. (Zoom triggers rearrangement, scale doesn’t)
  3. Inconsistent scaling rules for text. Zoom is still limited to a minimum Chinese size of 12px; Scale is purely proportional to graphics, so text support is less than 12px.

Scale is recommended, but note that it is also a property problem in transform (i.e., rotation).

Rotation/full screen

Picture rotation can be understood as horizontal scrolling and full-screen scrolling as vertical scrolling.

The principle of picture rotation is divided into two kinds :(take ABCD 4 pictures as an example)

The first option:

Is the rotation in the vertical direction, which can be understood as the analogy of PS layer overlap, as follows:

A. show B. hide C. hide D. hideCopy the code

JS is used to control the hidden image, while CSS3 controls the “illusion”, mainly translate + animation.

This can be applied to interactive design where only one image at a time is shown in rotation.

The second option:

As A visual rotation, arrange the images horizontally such as [A B] C D (in the box, for what is being shown)

  1. Assign a width to the entire broadcast outer Div, beyond hiding
  2. Each time the image is toggled, the left-most image is left offset (or the right-most image is right offset) and CSS3 animation is added.
  3. When it comes to the last image (D), there is actually A backup image of A behind D, which is used as A smoke screen.
  4. Normal animation continues from D to A, and when it reaches A (backup), all the left offset values of the picture are set to 0, that is to say, it is back to the real first picture at this time, and the user is not aware of it (no animation effects need to be added to the switch at this time).
  5. The code then continues to cut from the first sheet to the second sheet and so on, seamlessly switching.
  6. Same thing from the first A to the last D
  7. To sum up, the actual picture list using this rotation is D, A, B, C, D, A

Compared with the previous method, this method is a little more difficult to implement, but it can support the interaction design of multiple images appearing in the view area at the same time.

The interaction of full-screen scrolling is mainly as follows: each screen displays only one highly matched content, and then the navigation bar is generally left on the right or left side. For each screen scrolling, the item corresponding to the navigation bar is highlighted, as shown in the figure:

Mainly use the native OnScroll event and Element. ScrollIntoView API processing.

Since it is full screen listening, the height is known, that is, the screen height.

Monitor onScroll height/screen height to find the current screen number. Then highlight the corresponding directory in the navigation bar. The scrollIntoView logic is similar and will not be repeated.

ScrollIntoView is recommended because it is better for performance.

It is not recommended to write for full-screen and round-robin requirements, but to use third-party libraries:

Swiper (highest star)

The react, Vue, and Angular versions are available in full screen

Lazy loading

Loading lazy is the simplest method, but only Chrome supports: loading lazy on the IMG tag. For details, see: learn more about lazy loading in images and frames

Common implementation principles:

The img SRC attribute is assigned to a placeholder image by default. This image should be as small as possible, and the size should be consistent with the actual image displayed, as well as maintaining the layout of the page.

Attach the actual image address to each image via the data-* custom attribute of the HTML element, with the following pseudocode:

<img SRC = "default image" data-src= "real image" />Copy the code

When the IMG element is almost in the browser’s viewport, it is assigned to the image’s SRC with the real link address in data-*. So the main core logic is to listen for the scrollTop and element position calculations, namely scrollTop and offsetTop. The core judgment logic is as follows:

clientHeight = document.documentElement.clientHeight; // View height

clientHeight + scrollTop > img.offsetTop // If true, the element is already visible
Copy the code

Depending on the situation, you can add part of the buffer height, request images in advance, load them in advance, and make them more interactive.

Based on the above scheme, the following optimization measures can be adopted:

1 plus throttle

2 IntersectionObserver personally thinks a more elegant monitoring scheme (but does not support IE)

3 virtual long list, that is, only a small number of DOM nodes in the viewport are used to simulate a long list node. (www.npmjs.com/package/rea)…

Lazy loading is not recommended to write their own, commonly used libraries are:

lazyload

react-lazyload

preload

In addition to making the interactive experience more user-friendly, preloading is also used to deal with image flickering: loading background image will flash for the first time, you can use the preloading method to solve the problem.

The main principle is to use the browser cache mechanism (like links, browsers will call the cache), there are two common schemes:

  1. The simplest way to load an image is to use backage-image in your CSS, but not to show it (hide it, put it out of view, etc.)

Note: Opera and Firefox on display: None elements of the background, do not immediately request, only when its display! = None. Other browsers initiate image requests immediately.

  1. Load directly with new Image. As for the timing, it depends on the business:
const images = []
function preload(list) { 
	for (i = 0; i < list.length; i++) { 
		images [i] = new Image() 
		images [i].src = list [i] 
	} 
} 
preload( 
	["Picture 1"."Photo 2"."Three graphics"Picture,"4"]);// Call the preload image function, call the timing of business decision.
Copy the code

Adaptive picture display

There are a lot of adaptive solutions out there (you could even write a column about it), and these generic solutions can also be used for image elements. Therefore, only those unique to the image element are mentioned here.

1 Srcset property (IE incompatible). Srcset property is used to set the image to automatically load different images under different screen densities, as shown in the figure below:

You can design images that fit well on different screens, and with a little bit of style control, you can achieve more general image adaptation. Source package

2 Object -fit & object-position

An original:

value meaning The sample
fill The image stretches to fill the entire container without ensuring the original proportions.
contain Make sure the image will fit in the container while keeping it in proportion. This parameter may leave blank space in the image container.
cover Ensure that the size of the picture is larger than the size of the container, and that at least one of the width and height is the same as the container, while maintaining the image proportion. This parameter may make parts of the image invisible.
none Keep the original size of the image while maintaining the original size ratio.
scale-down None + contain, and the last one is the smaller one. Contain: if the container is larger than the image, the effect of the image is none. If the container is smaller than the image, the effect of the image is like contain.

Object-position Controls the display position of the image. The default value is 50%, 50%, that is, the center effect. For example, in the image of Object-Fit, the image is centered horizontally and vertically.

Object -fit + Object -position can solve a lot of picture adaptability problems.

To view a larger version

The general scenario is as follows: Thumbnail images are displayed by default. You can click the thumbnail and view the enlarged version of the image in a pop-up window. You can rotate and zoom the image.

The principle can be combined with CSS3 rotate, Scale and other properties mentioned above, plus the modal box popup processing. In general, it is not recommended to recreate this wheel. There are already a number of UI libraries available in the community, such as:

Viewer.js Zooming

other

Preventing hotlinking

In fact, the server verifies the parameters on the request head to decide whether to allow the image resource to be returned. On pictures, the most common is the referer header. Common ideas are:

  1. When the referer is null, the correct graph is returned
  2. When the referer is not empty and the host matches a whitelist site, the correct graph is returned
  3. When the referer is not empty, but the host fails to hit the whitelist site, the wrong graph is returned

Another option is to add a time limit to the resource, usually with a unique identifier for the IMAGE URI, such as:

https://images.cdn.com/image/608782/201503/291535318955336.jpg (behind the Numbers is a set of unique identifier)

The logic of a solution is roughly as follows. Note: THE CDN in the figure refers to a server with certain logical processing, rather than a static storage.

Webpack image to Base64 embedded file

Webpack can use the URL-loader to convert images to Base64, but it is not recommended to convert all images to Base64, although it can reduce a request, but it will increase the size of CSS, bringing CSP problems, you can refer to this article: [front end overview] : Play image Base64 encoding

module.exports = {
    module: {
        rules: [{test: /\.(gif|png|jpg|woff|svg|ttf|eot)$/ ,
                use: [{loader:'url-loader'.options: {
                        limit:500.outputPath: 'images/'.name:'[name].[ext]'}}]}};Copy the code

Through the limit configuration item of URL-loader, the unit of byte, the image resources smaller than the limit will be base64 encoding conversion, currently the scaffolding used by the author’s business is set to 204800, that is, 200KB.

Sprite figure

At present, it is basically not recommended to use it on the Web side (but not completely eliminated, graphics and games are still used), for the following reasons:

  1. At present, there are few small images in web pages. The emergence of Iconfont has greatly reduced the use of Sprite images.
  2. Sprite figure is in order to solve a lot of small pictures of a lot of extra requests, forced to, because its itself brings to the design and development are the additional costs, the small icon position determines the later can’t literally change, the size also can’t literally change, can’t move to other icon position, there are more limited.
  3. HTTP2’s multiplex concurrency largely eliminates the overhead of creating additional requests and communicating requests

Image base64 to file stream

Such schemes have a lot of online, here on Twitter: www.zhihu.com/question/30…

function convertCanvasToBlob(canvas) {
    var format = "image/jpeg";
    var base64 = canvas.toDataURL(format);
    var code = window.atob(base64.split(",") [1]);
    var aBuffer = new window.ArrayBuffer(code.length);
    var uBuffer = new window.Uint8Array(aBuffer);
    for(var i = 0; i < code.length; i++){
        uBuffer[i] = code.charCodeAt(i);
    }
    var Builder = window.WebKitBlobBuilder || window.MozBlobBuilder;
    if(Builder){
        var builder = new Builder;
        builder.append(buffer);
        return builder.getBlob(format);
    } else {
        return new window.Blob([ buffer ], {type: format}); }}Copy the code

Img buried point

At present, the use of blank GIF or 1×1 PX GIF is a common means of Internet advertising or website monitoring, simple and safe, for the following reasons:

  1. Avoid cross-domain (img elements support cross-domain natively);
  2. Image requests do not occupy the Ajax request quota;
  3. GIF has the smallest legal size (74 bytes for the smallest BMP file, 67 bytes for PNG, and 43 bytes for a legal GIF)
  4. Compared with PNG/JPG, 1px transparent image has little impact on web content.
  5. Does not block page loading and affect the user’s experience, as long as the new Image object (asynchronous) does not generally need to append into the DOM (in memory), through its onError and onLoad events to detect the sending status.

Note: in no picture mode, images will not be requested, that is, onload and onError events will not be triggered, so it is not recommended to send page request logic in this way.

Canvas drawing

There are three possibilities for a black or white Canvas drawing problem

  1. Pictures of cross-domain
  2. No drawing function is called in the image.onload function
  3. No API calls like darwImage to actually draw

Cross-domain problems:

Canvas cross-domain problem actually has two different situations:

The first kind: can get the picture

Canvas can be rendered normally, but operations on it, such as toDataURL and getImageData, will prompt cross-domain. In this case, the solution is as follows:

You can use Ajax request to get the image, and then transfer the file stream to Canvas for operation.

Second: the image is not accessible

Neither new Image nor AJax can be accessed. At this time, the Image has not been downloaded before it is prompted to cross domain, that is, it has not entered any operation on Canvas. For this situation, there is no solution on pure front-end technology for the time being.

There are currently three options:

  1. Is the user to actively close the browser cross-domain interception;
  2. The server needs to convert the image into non-cross-domain resources, such as Base64, file stream, and upload to CDN.
  3. The user is prompted interactively to download the image first, then upload the file, and the Canvas processes the local file stream to solve the problem.

At the end

~ Thanks (· ω ·) Blue 😊

Finally, I hope this article can help students who have difficulties in front pictures ~