Dirección original: github.com/whinc/blog/…
Recientemente, recibimos una solicitud para publicar comentarios: los usuarios ingresan comentarios y pueden tomar fotografías o seleccionar fotografías del álbum para cargarlas, lo que significa que se admiten comentarios de texto e imágenes. Debe implementarse en programas H5 y mini al mismo tiempo. Este requisito requiere muchos lugares para procesar imágenes. Este artículo hace un resumen de la práctica de procesamiento de imágenes en el extremo H5. El código del proyecto se basa en el marco Vue. Para evitar que el marco me afecte, cambié todo el código a la implementación API nativa para explicarlo. Al mismo tiempo, hay muchos otros detalles y funciones adicionales (vista previa, recorte). , cargar progreso, etc.) en el código del proyecto aquí omítalo y solo introduzca las ideas clave y los códigos relacionados con el procesamiento de imágenes. La implementación del miniprograma es similar a H5 y no se repetirá. El código de implementación del miniprograma se adjunta al final del artículo.
FotografíaUtilice la etiqueta <input>, establezca tipo en archivo para seleccionar el archivo, establezca aceptar en imagen/* para seleccionar el tipo de archivo y la cámara, y configure múltiples para admitir múltiples selecciones. Escuche el evento de cambio para obtener la lista de archivos seleccionados, cada archivo es de tipo Blob.
<tipo de entrada=archivo aceptar=imagen/* múltiple /> <img clase=preivew /> <tipo de script=texto/javascript> función onFileChange (evento) { archivos const = Array.prototype.slice.call(event.target.files ) files.forEach(file => console.log('nombre de archivo:', file.name)) } document.querySelector('entrada').addEventListener('cambio', onFileChange) </script>Vista previa de la imagen
El método URL.createObjectURL puede crear una ruta URL local que apunte al objeto de recurso local. Esta interfaz se utiliza a continuación para crear la dirección de la imagen seleccionada y mostrarla.
función onFileChange (evento) { archivos constantes = Array.prototype.slice.call(event.target.files) archivo constante = archivos[0] document.querySelector('img').src = window.URL.createObjectURL(archivo) }Rotación de imagen
Las fotografías tomadas con una cámara pueden girarse debido a la dirección en la que se sostiene la cámara al disparar y es necesario corregirlas. Corregir la rotación requiere conocer la información de rotación de la imagen. Aquí usamos una biblioteca llamada exif-js, que puede leer los metadatos EXIF de la imagen, incluida la dirección de la cámara al disparar, en función de esta dirección. Se puede calcular la información de la imagen.
El siguiente es el bit de bandera de rotación EXIF. Hay 8 tipos en total. Sin embargo, al disparar a través de la cámara, solo se pueden generar 1, 3, 6 y 8, que corresponden respectivamente a la cámara normal, 180 ° en el sentido de las agujas del reloj. rotación, rotación de 90° en sentido contrario a las agujas del reloj y rotación en el sentido de las agujas del reloj. Foto tomada a 90°.
Por lo tanto, para corregir el ángulo de rotación de la imagen, solo necesita leer el indicador de rotación EXIF de la imagen, determinar el ángulo de rotación, rotar la imagen en el lienzo y volver a exportar una nueva imagen. Con respecto a la operación de rotación del lienzo, puede consultar el artículo "Rotación de imágenes del lienzo y desbloqueo de postura de giro". La siguiente función implementa la corrección del ángulo de rotación del archivo de imagen, recibe un archivo de imagen y devuelve el nuevo archivo de imagen corregido.
/** * Solucionar el problema del ángulo de rotación de la imagen * @param {archivo} imagen original * @return {Promise} promesa resuelta Devolver la nueva imagen corregida */function fixImageOrientation (archivo) { return new Promise((resolver, rechazar) => { // Obtener la imagen const img = new Image(); img.src = window.URL.createObjectURL(file); img.onerror = () => resolve(file); img.onload = () => { // Obtener los metadatos de la imagen (las variables EXIF son variables globales expuestas por la biblioteca exif-js introducida) EXIF.getData(img, function() { // Obtener el indicador de rotación de la imagen var orientación = EXIF.getTag(this, Orientación); // Gira la imagen en el lienzo según el ángulo de rotación if (orientación === 3 || orientación === 6 || orientación === 8) { const canvas = document.createElement(canvas); const ctx = canvas.getContext(2d); switch (orientación) { caso 3: // Girar 180° canvas.width = img.width; canvas.height = img.height( (180 * Math.PI) / 180); ctx.drawImage(img, -img.width, -img.height, img.width, img.height); caso 6: // Girar 90° canvas.width = img.height; canvas.height = img.width((90 * Math.PI) / 180); ctx.drawImage(img, 0, -img.height, img.width, img.height caso 8: // Girar -90° lienzo.width = img.height; canvas.height = img.width; ctx.rotate((-90 * Math.PI) / ctx.drawImage(img, -img.width, 0, img); .width, img.height); break; } // Devuelve la nueva imagen canvas.toBlob(file => resolve(file), 'imagen/jpeg', 0.92) } else { return resolver(archivo); } });Compresión de imágenes
Hoy en día, el efecto de cámara de los teléfonos móviles es cada vez mejor y, con él, el tamaño de las imágenes ha aumentado, que puede alcanzar fácilmente unos pocos MB o incluso más de diez MB. La carga directa de la imagen original es lenta y fácil de cargar. falla, y el fondo también tiene restricciones en el tamaño del cuerpo de la solicitud, la carga posterior de la visualización de la imagen también será más lenta. Si el front-end comprime la imagen y luego la carga, estos problemas se pueden resolver.
La siguiente función implementa la compresión de imágenes. El principio es dibujar la imagen escalada en el lienzo y finalmente exportar la imagen comprimida desde el lienzo. Hay dos formas de controlar la compresión de la imagen: una es controlar la relación de zoom de la imagen; la otra es controlar la calidad de la imagen exportada.
/** * Imagen comprimida * @param {archivo} Imagen de entrada * @returns {Promise} promesa resuelta Devuelve la nueva imagen comprimida */function compressImage(file) { return new Promise((resolver, rechazar) => { // Obtener la imagen (cargar la imagen es para obtener el ancho y el alto de la imagen) const img = new Image(); img.src = window.URL.createObjectURL(file); rechazar(error); img.onload = () => { // Ancho y alto del lienzo const canvasWidth = document.documentElement.clientWidth * window.devicePixelRatio; const canvasHeight = document.documentElement.clientHeight * window.devicePixelRatio; factor // Aquí tomo los factores de escala horizontal y vertical más grandes como factor de escala, para garantizar que todo el contenido de la imagen sea visible const scaleX = canvasWidth / img.width; const scaleY = canvasHeight / img.height; const scale = Math.min(scaleX, scaleY); escala la imagen original según el factor de escala y dibújala en el lienzo const canvas = document.createElement; ('lienzo'); const ctx = lienzo.getContext(2d); lienzo.ancho = lienzo.alto = lienzoHeight; img.width * escala; const imageHeight = img.height * escala; const dx = (canvasWidth - imageWidth) / 2; const dy = (canvasHeight - imageHeight) / 2; ); // Exportar nueva imagen // Especificar el tipo MIME de la imagen como 'imagen/jpeg', pasar calidad Controlar la calidad de las imágenes exportadas e implementar la compresión de imágenes calidad constante = 0,92 canvas.toBlob(file => resolve(tempFile), image/jpeg, calidad } });};Subir imagen
Cree datos de formulario a través de FormData e inicie una solicitud POST ajax. La siguiente función implementa la carga de archivos.
Nota: Al enviar datos de FormData, el navegador establecerá automáticamente el tipo de contenido en un valor apropiado. No es necesario configurar el tipo de contenido; de lo contrario, se informará un error porque el navegador genera el límite delimitador del cuerpo de la solicitud HTTP. y no se puede configurar manualmente.
/** * Cargar archivo* @param {Archivo} archivo Archivo a cargar* @returns {Promise} Devuelve la promesa resuelta si la carga se realiza correctamente; de lo contrario, devuelve la promesa rechazada */function uploadFile (archivo) { return new Promise((resolve , rechazar) = > { // Preparar datos del formulario const formData = new FormData() formData.append('file', file) // Enviar solicitud const xhr = new XMLHttpRequest() xhr.open('POST', uploadUrl) xhr.onreadystatechange = function () { if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { resolve(JSON.parse(this.responseText)) } else { rechazar(this.responseText) } } xhr.send(formData) })}resumen
Con las funciones auxiliares anteriores, el procesamiento es mucho más sencillo. El código de llamada final es el siguiente:
function onFileChange (evento) { const files = Array.prototype.slice.call(event.target.files) const file = files[0] // Corregir la rotación de la imagen fixImageOrientation(file).then(file2 => { // Crear vista previa Imagen document.querySelector('img').src = window.URL.createObjectURL(file2) // retorno de compresión compressImage(file2) }).then(file3 => { // Actualizar imagen de vista previa document.querySelector('img').src = window.URL.createObjectURL(file3) // Cargar return uploadFile(file3) }).then(data => { console.log('Carga exitosa') }).catch(error => { console.error('Carga fallida') })}
H5 proporciona una interfaz para procesar archivos. Con la ayuda de Canvas, se puede implementar un procesamiento de imágenes complejo en el navegador. Este artículo resume algunas prácticas de procesamiento de imágenes en el escenario de cargar imágenes en H5 en el terminal móvil. referencia parcial cuando se encuentren necesidades similares en el futuro.
Adjunto una pequeña referencia de implementación del programa.
// Tomar fotos wx.chooseImage({ sourceType: [camera], Success: ({ tempFiles }) => { const file = tempFiles[0] // Procesar imágenes }});/** * Comprimir imágenes* @param { Object } params * filePath: Cadena La ruta de la imagen de entrada * Success: Función Se vuelve a llamar cuando la compresión es exitosa y devuelve la nueva ruta de la imagen comprimida * Fail: Función Devolución de llamada cuando falla la compresión */compressImage({ filePath, Success, Fail }) { // Obtener el ancho y alto de la imagen wx.getImageInfo({ src: filePath, Success: ({ width, height }) => { const systemInfo = wx .getSystemInfoSync (); const canvasWidth = systemInfo.screenWidth; const canvasHeight = systemInfo.screenHeight; Actualiza el tamaño del lienzo this.setData({ canvasWidth, canvasHeight }) // Calcula la relación de escala const scaleX = canvasWidth / width; const scaleY = canvasHeight / height const scale = Math.min(scaleX, const imageWidth = width); * escala; const imageHeight = altura * escala; // Dibuja la imagen escalada en el lienzo const ctx = wx.createCanvasContext(hidden-canvas); dx = (canvasWidth - imageWidth) / 2; let dy = (canvasHeight - imageHeight) / 2; ctx.drawImage(filePath, dx, dy, imageWidth, imageHeight(false, () => { // Exportar); Imágenes comprimidas en archivos temporales wx.canvasToTempFilePath({ canvasId: oculto-canvas, ancho: canvasWidth, altura: canvasHeight, destWidth: canvasWidth, destHeight: canvasHeight, fileType: jpg, calidad: 0.92, éxito: ({ tempFilePath }) => { // Ocultar el lienzo this.setData({ canvasWidth: 0, canvasHeight: 0 } ) // Compresión completada con éxito ({ tempFilePath } }, error: error => { //); Ocultar lienzo this.setData({ canvasWidth: 0, canvasHeight: 0 }) fail(error } } } }, error => { fail(error);}/** *); Cargar archivo*/uploadFile({ uploadUrl, filePath, onData, onError }) { wx.uploadFile({ url: uploadUrl filePath: filePath, nombre: archivo, encabezado: { Cookie: cookie }, éxito: res => { if (res.statusCode === 200) { onData(res.data) } else { onError(res } }, falla: error => { enError(error); } });}Resumir
Lo anterior es el HTML5 y un pequeño programa introducido por el editor para realizar las funciones de rotar, comprimir y cargar imágenes. Espero que le resulte útil. Si tiene alguna pregunta, déjeme un mensaje y el editor le responderá. usted a tiempo. ¡También me gustaría agradecer a todos por su apoyo al sitio web de artes marciales VeVb!