Adresse d'origine : github.com/whinc/blog/…
Récemment, j'ai reçu une demande de publication de commentaires : les utilisateurs saisissent des commentaires et peuvent prendre des photos ou sélectionner des images de l'album à télécharger, ce qui signifie que les commentaires sous forme de texte et d'image sont pris en charge. Il doit être implémenté à la fois sur le H5 et sur les mini-programmes. Cette exigence nécessite de nombreux endroits pour traiter les images. Cet article résume la pratique de traitement d'image du côté du H5. Le code du projet est basé sur le framework Vue. Afin d'éviter d'être affecté par le framework, j'ai modifié tout le code pour l'implémentation de l'API native pour explication. En même temps, il existe de nombreux autres détails et fonctions supplémentaires (aperçu). , recadrage, progression du téléchargement, etc.) dans le code du projet ici. Omettez-le et introduisez uniquement les idées et codes clés liés au traitement de l'image. L'implémentation du mini programme est similaire à H5 et ne sera pas répétée. Le code d'implémentation du mini programme est joint à la fin de l'article.
PhotographierUtilisez la balise <input>, définissez le type sur file pour sélectionner le fichier, définissez accept sur image/* pour sélectionner le type de fichier et la caméra, et définissez multiple pour prendre en charge plusieurs sélections. Écoutez l'événement change pour obtenir la liste des fichiers sélectionnés, chaque fichier est de type Blob.
<input type=file accept=image/* multiple /> <img class=preivew /> <script type=text/javascript> function onFileChange (event) { const files = Array.prototype.slice.call(event.target.files ) files.forEach(file => console.log('file name:', file.name)) } document.querySelector('input').addEventListener('change', onFileChange) </script>Aperçu de l'image
La méthode URL.createObjectURL peut créer un chemin d'URL local pointant vers l'objet ressource locale. Cette interface est utilisée ci-dessous pour créer l'adresse de l'image sélectionnée et l'afficher.
function onFileChange (événement) { const files = Array.prototype.slice.call(event.target.files) const file = files[0] document.querySelector('img').src = window.URL.createObjectURL(file) }Rotation de l'image
Les photos prises avec un appareil photo peuvent pivoter en raison de la direction dans laquelle l'appareil photo est tenu lors de la prise de vue et doivent être corrigées. Corriger la rotation nécessite de connaître les informations de rotation de l'image. Ici, nous utilisons une bibliothèque appelée exif-js, qui peut lire les métadonnées EXIF de l'image, y compris la direction de la caméra lors de la prise de vue. En fonction de cette direction, la rotation. Les informations de l'image peuvent être calculées.
Ce qui suit est le bit du drapeau de rotation EXIF. Il existe 8 types au total, mais lors de la prise de vue via la caméra, seuls 1, 3, 6 et 8 peuvent être générés, qui correspondent respectivement à la rotation normale de la caméra à 180 ° dans le sens des aiguilles d'une montre. , rotation à 90° dans le sens inverse des aiguilles d'une montre et rotation dans le sens des aiguilles d'une montre. Photo prise à 90°.
Par conséquent, pour corriger l'angle de rotation de l'image, il vous suffit de lire le drapeau de rotation EXIF de l'image, de déterminer l'angle de rotation, de faire pivoter l'image sur la toile et de réexporter une nouvelle image. Concernant l'opération de rotation du canevas, vous pouvez vous référer à l'article « Rotation de l'image du canevas et déverrouillage de la posture de retournement ». La fonction suivante implémente la correction de l'angle de rotation du fichier image, reçoit un fichier image et renvoie le nouveau fichier image corrigé.
/** * Correction du problème d'angle de rotation de l'image * @param {file} image originale * @return {Promise} promesse résolue Renvoie la nouvelle image corrigée */function fixImageOrientation (file) { return new Promise((resolve, rejet) => { // Récupère l'image const img = new Image(); img.src = window.URL.createObjectURL(file); img.onload = () => { // Récupère les métadonnées de l'image (les variables EXIF sont des variables globales exposées par la bibliothèque exif-js introduite) EXIF.getData(img, function() { // Récupère l'indicateur de rotation de l'image var orientation = EXIF.getTag(this, Orientation); // Faites pivoter l'image sur le canevas en fonction de l'angle de rotation if (orientation === 3 || orientation === 6 || orientation === 8) { const canvas = document.createElement(canvas); const ctx = canvas.getContext(2d); switch (orientation) { cas 3 : // Rotation de 180° canvas.width = img.width; canvas.height = img.height; (180 * Math.PI) / 180); ctx.drawImage(img, -img.largeur, -img.hauteur, img.width, img.height); break; cas 6 : // Rotation de 90° canvas.width = img.height; canvas.height = img.width; ctx.drawImage(img, 0, -img.height, img.width, img.height) cas 8 : // Rotation de -90° canvas.width = img.height; canvas.height = img.width; ctx.rotate((-90 * Math.PI) / ctx.drawImage(img, -img.width, 0, img); .width, img.height); break; } // Renvoie la nouvelle image canvas.toBlob(file => solve(file), 'image/jpeg', 0.92) } else { return solve(fichier } } });Compression d'images
De nos jours, l'effet appareil photo des téléphones mobiles s'améliore de plus en plus, et avec lui la taille des images a augmenté, qui peut facilement atteindre quelques Mo, voire plus de dix Mo. Le téléchargement direct de l'image originale est lent et facile à télécharger. , et l'arrière-plan a également des restrictions sur la taille du corps de la requête , le chargement ultérieur de l'affichage de l'image sera également plus lent. Ces problèmes peuvent être résolus si le frontal compresse les images puis les télécharge.
La fonction suivante implémente la compression d'image. Le principe est de dessiner l'image mise à l'échelle sur le canevas, et enfin d'exporter l'image compressée depuis le canevas. Il existe deux manières de contrôler la compression de l'image : l'une consiste à contrôler le taux de zoom de l'image ; l'autre consiste à contrôler la qualité de l'image exportée.
/** * Image compressée * @param {file} Image d'entrée * @returns {Promise} promise promise Renvoie la nouvelle image compressée */function compressImage(file) { return new Promise((resolve, rejet) => { // Get l'image (le chargement de l'image consiste à obtenir la largeur et la hauteur de l'image) const img = new Image(); rejeter (erreur); img.onload = () => { // Largeur et hauteur du canevas const canvasWidth = document.documentElement.clientWidth * window.devicePixelRatio; const canvasHeight = document.documentElement.clientHeight * window.devicePixelRatio; factor // Ici, je prends les facteurs d'échelle horizontaux et verticaux plus grands comme facteur d'échelle, afin de garantir que tout le contenu de l'image est visible const scaleX = canvasWidth / img.width; const scaleY = canvasHeight / img.height; const scale = Math.min(scaleX, scaleY); // Redimensionnez l'image originale en fonction du facteur de mise à l'échelle et dessinez-la sur le canevas const canvas = document.createElement ('toile'); const ctx = toile.getContext(2d); toile.largeur = toile.hauteur = toileHauteur = img.width * scale; const imageHeight = img.height * scale; const dx = (canvasWidth - imageWidth) / 2; const dy = (canvasHeight - imageHeight) / 2; ); // Exporter une nouvelle image // Spécifier le type MIME de l'image comme 'image/jpeg', passer la qualité Contrôler la qualité des images exportées et implémenter la compression d'image const quality = 0.92 canvas.toBlob(file => solve(tempFile), image/jpeg, quality } });};Téléchargement d'images
Créez des données de formulaire via FormData et lancez une requête ajax POST. La fonction suivante implémente le téléchargement de fichiers.
Remarque : lors de l'envoi de données FormData, le navigateur définira automatiquement le type de contenu sur une valeur appropriée. Il n'est pas nécessaire de définir le type de contenu, sinon une erreur sera signalée car la limite du délimiteur du corps de la requête HTTP est générée par le navigateur. et ne peut pas être réglé manuellement.
/** * Télécharger le fichier* @param {Fichier} fichier Fichier à télécharger* @returns {Promise} Renvoie la promesse résolue si le téléchargement réussit, sinon renvoie la promesse rejetée */function uploadFile (file) { return new Promise((resolve , rejeter) = > { // Préparer les données du formulaire const formData = new FormData() formData.append('file', file) // Soumettre la demande const xhr = new XMLHttpRequest() xhr.open('POST', uploadUrl) xhr.onreadystatechange = function () { if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { solve(JSON.parse(this.responseText)) } else { rejeter (this.responseText) } } xhr.send (formData) })}résumé
Avec les fonctions auxiliaires ci-dessus, le traitement est beaucoup plus simple. Le code d'appel final est le suivant :
function onFileChange (event) { const files = Array.prototype.slice.call(event.target.files) const file = files[0] // Correction de la rotation de l'image fixImageOrientation(file).then(file2 => { // Créer un aperçu Image document.querySelector('img').src = window.URL.createObjectURL(file2) // Retour de compression compressImage(file2) }).then(file3 => { // Mettre à jour l'image d'aperçu document.querySelector('img').src = window.URL.createObjectURL(file3) // Télécharger le retour uploadFile(file3) }).then(data => { console.log('Téléchargement réussi') }).catch(error => { console.error('Échec du téléchargement') })}
H5 fournit une interface de traitement des fichiers. À l'aide de Canvas, un traitement d'image complexe peut être implémenté dans le navigateur. Cet article résume certaines pratiques de traitement d'image dans le scénario de téléchargement d'images dans H5 sur le terminal mobile. référence partielle lorsqu’on rencontre des besoins similaires à l’avenir.
Vous trouverez ci-joint une petite référence de mise en œuvre du programme
// Prendre des photos wx.chooseImage({ sourceType: [camera], success: ({ tempFiles }) => { const file = tempFiles[0] // Traiter les images }});/** * Compresser les images* @param { Object } params * filePath : String Le chemin de l'image d'entrée * success : Fonction Rappelée lorsque la compression est réussie et renvoie le nouveau chemin de l'image compressée * fail : Fonction Rappel en cas d'échec de la compression */compressImage({ filePath, success, fail }) { // Récupère la largeur et la hauteur de l'image wx.getImageInfo({ src: filePath, success: ({ width, height }) => { const systemInfo = wx .getSystemInfoSync (); const canvasWidth = systemInfo.screenWidth; const canvasHeight = systemInfo.screenHeight; Mettre à jour la taille du canevas this.setData({ canvasWidth, canvasHeight }) // Calculer le rapport de mise à l'échelle const scaleX = canvasWidth / width; const scaleY = canvasHeight / height; const scale = Math.min(scaleX, scaleY); * scale ; const imageHeight = height * scale; // Dessine l'image mise à l'échelle sur le canevas const ctx = wx.createCanvasContext(hidden-canvas let); dx = (canvasWidth - imageWidth) / 2; let dy = (canvasHeight - imageHeight) / 2; ctx.drawImage(filePath, dx, dy, imageWidth, imageHeight); Images compressées dans des fichiers temporaires wx.canvasToTempFilePath({ canvasId : caché-canvas, width : canvasWidth, hauteur : canvasHeight, destWidth : canvasWidth, destHeight : canvasHeight, fileType : jpg, qualité : 0,92, succès : ({ tempFilePath }) => { // Masquer le canevas this.setData({ canvasWidth : 0, canvasHeight : 0 } ) // Compression terminée avec succès ({ tempFilePath } }), échec : erreur => { // Masquer le canevas this.setData({ canvasWidth: 0, canvasHeight: 0 }) fail(error); } } } }; fail: error => { fail(error); Télécharger le fichier*/uploadFile({ uploadUrl, filePath, onData, onError }) { wx.uploadFile({ url : uploadUrl filePath : filePath, nom : fichier, en-tête : { Cookie : cookie }, succès : res => { if (res.statusCode === 200) { onData(res.data) } else { onError(res } }, échec : erreur => { onErreur(erreur); } });}Résumer
Ce qui précède est le petit programme HTML5 introduit par l'éditeur pour réaliser les fonctions de rotation, de compression et de téléchargement d'images. J'espère que cela vous sera utile. Si vous avez des questions, laissez-moi un message et l'éditeur vous répondra. vous à temps. Je tiens également à remercier tout le monde pour votre soutien au site d'arts martiaux VeVb !