This article was originally published at: github.com/bigo-fronte… Welcome to follow and reprint.
preface
Recently, I often received the demand of customized pictures for users on the activity page, so I made a summary of the business functions of picture cutting and some pits stepped on before, hoping to be of reference value to everyone.
Requirements describe
Let’s take a look at the overall requirements functionality:
- Clicking on a fixed area allows the user to select the photo in the photo/gallery
- The user can then zoom and drag the selected photo to adjust the photo display area
- After completing the picture, users to be adjusted can also choose different activity theme covers to synthesize and generate live cover related to the event
Function implementation
- The first step from the photo, album function, this step can be directly used
input
The tag invokes native photo and album functions.
<input type="file" accept="image/jpeg, image/png" @change="selectPhoto" />
Copy the code
- The second step involves image cropping, zooming, dragging and other functions, which we introduced hereAlloyCrop Image clipping libraryIn the
body
The bottom can be introduced afterVue
Call directly from:
<script src="<%= BASE_URL %>alloy-crop.js"></script>
Copy the code
new AlloyCrop({
image_src: file,
width: clientWidth,
height: clientWidth,
output: 1.className: "m-clip-box".ok(base64) {
that.picUrl = base64;
that.prewObj.destroy();
},
ok_text: "Ok".cancel_text: "Cancel".cancel(){ that.prewObj.destroy(); }});Copy the code
- Directly introducing
AlloyCrop
Later, I found that the UI style displayed was inconsistent with that in our design drawing. After checking the document, I found no configuration to customize the style, so I directly used itchrome
的dom
Check the tool, find the corresponding node to obtain the class name and then style overwrite. - The next step is to choose different covers for composition, which can be used here
canvas
Draw it, and pass itcanvas.toDataURL
Export the image we need:
drawCanvas() {
const canvas = document.getElementById('a3');
const context = canvas.getContext('2d');
context.clearRect(0.0.480.480);
const imageBg = new Image();
const imageHeadBg = new Image();
imageBg.setAttribute('crossOrigin'.'anonymous');
imageHeadBg.setAttribute('crossOrigin'.'anonymous');
const imgList = [];
function allImgLoad(resolve) {
if (imgList.length === 2) {
// Draw the background
context.drawImage(imageBg, 0.0.480.480);
context.drawImage(imageHeadBg, 0.0.480.480);
resolve(canvas.toDataURL('image/jpeg'));
}
}
imageBg.src = this.picUrl;
imageHeadBg.src = this.selectCover;
return new Promise((resolve) = > {
imageBg.onload = () = > {
console.log('image1 has loaded');
imgList.push(1);
allImgLoad(resolve);
};
imageHeadBg.onload = () = > {
console.log('image2 has loaded');
imgList.push(1);
allImgLoad(resolve);
};
});
},
Copy the code
Problems encountered
IOS photo rotation 90 degree problem
- In the process of self-testing, it was found that the picture would rotate 90 degrees on IOS devices after taking photos. After investigation, the reason is that IOS devices have different ways of judging the picture landscape/portrait in the process of taking photos, so we need to pass the picture according to the picture parameters
canvas
Rotate it in the direction we expect. - Exif. js library is a relatively mature library in the field of image attribute acquisition. Its principle is to obtain the parameters of the image when taking photos, including Orientation label, according to the binary data of the image. After importing the library, call as follows:
// Get the direction of the image
function getPhotoOrientation(img) {
var orient;
EXIF.getData(img, function () {
orient = EXIF.getTag(this."Orientation");
console.log("orient2", orient);
});
return orient;
}
Copy the code
- Given that we’re trying to get the picture
Orientation
Property, introduced a 40K library, after viewing the source code found that it also contains a lot of image processing methods we do not need, so finally found a simplified version of the function, useDataView
andreadAsArrayBuffer
Is enough to meet our needs:
function getOrientation(file, callback) {
const reader = new FileReader();
// eslint-disable-next-line func-names
reader.onload = function (e) {
const view = new DataView(e.target.result);
if (view.getUint16(0.false)! = =0xffd8) {
return callback(-2);
}
const length = view.byteLength;
let offset = 2;
while (offset < length) {
if (view.getUint16(offset + 2.false) < =8) return callback(-1);
const marker = view.getUint16(offset, false);
offset += 2;
if (marker === 0xffe1) {
// eslint-disable-next-line no-cond-assign
if (view.getUint32((offset += 2), false)! = =0x45786966) {
return callback(-1);
}
const little = view.getUint16((offset += 6), false) = = =0x4949;
offset += view.getUint32(offset + 4, little);
const tags = view.getUint16(offset, little);
offset += 2;
for (let i = 0; i < tags; i += 1) {
if (view.getUint16(offset + i * 12, little) === 0x0112) {
return callback(view.getUint16(offset + i * 12 + 8, little)); }}// eslint-disable-next-line no-bitwise
} else if ((marker & 0xff00)! = =0xff00) {
break;
} else {
offset += view.getUint16(offset, false); }}return callback(-1);
};
reader.readAsArrayBuffer(file);
}
Copy the code
- To get to
Orientation
Attribute meanings are as follows: - Use after obtaining the direction
canvas
Rotate image processing:
resetOrientation(srcBase64, cb) {
const img = new Image();
const { Orientation } = this;
img.onload = () = > {
const { width, height } = img;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (Orientation > 4 && Orientation < 9) {
canvas.width = height;
canvas.height = width;
} else {
canvas.width = width;
canvas.height = height;
}
// transform context before drawing image
switch (Orientation) {
case 2:
ctx.transform(-1.0.0.1, width, 0);
break;
case 3:
ctx.transform(-1.0.0, -1, width, height);
break;
case 4:
ctx.transform(1.0.0, -1.0, height);
break;
case 5:
ctx.transform(0.1.1.0.0.0);
break;
case 6:
ctx.transform(0.1, -1.0, height, 0);
break;
case 7:
ctx.transform(0, -1, -1.0, height, width);
break;
case 8:
ctx.transform(0, -1.1.0.0, width);
break;
default:
break;
}
ctx.drawImage(img, 0.0);
const rs = canvas.toDataURL('image/jpeg');
cb(rs);
};
img.src = srcBase64;
},
Copy the code
Canvas export result is empty problem
- Snapshots are found in ios12
canvas.toDataURL
It keeps coming back"data:,"
Causes the image to be empty. - Description in MDN is as follows:
- It turned out to be a full-screen screenshot
canvas
The size exceeds the viewable area of the WebView. Whereas different WebViewsmaximum canvas size
The problem was solved by making the screenshot area always smaller than the viewable area width.
conclusion
BigoLive revenue As a global live streaming platform, has a large user base. Different from the booming Internet environment in China, many overseas users’ operating systems and network environments are still at the middle and low-end level. All kinds of terminal models, complex code running environment and network environment pose greater challenges to front-end development. We need to continue to accommodate more and more user groups to fulfill the basic business functions.
Welcome everyone to leave a message to discuss, wish smooth work, happy life!
I’m bigO front. See you next time.