{"id":2102,"date":"2016-01-08T22:00:21","date_gmt":"2016-01-08T22:00:20","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2102"},"modified":"2023-07-05T12:14:14","modified_gmt":"2023-07-05T19:14:14","slug":"exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/","title":{"rendered":"Explorando Couchbase y N1QL a trav\u00e9s de Touchbase usando Node.js y Angular.js - Parte 4: Carga de im\u00e1genes con Multer y codificaci\u00f3n base64"},"content":{"rendered":"<h2>Parte 4: Carga de im\u00e1genes<\/h2>\n<p>Hasta ahora, la parte 0 y la parte 1 cubren el modelo de datos y el documento de usuario utilizado en la aplicaci\u00f3n, seguido de la parte 2 donde verificamos cuentas a trav\u00e9s de correo electr\u00f3nico utilizando Nodemailer y Sendgrid. Luego tuvimos la parte 3 que cubri\u00f3 la autenticaci\u00f3n de usuario basada en sesi\u00f3n. Ahora que podemos crear un usuario, y permitirle iniciar sesi\u00f3n, ser\u00eda ideal asociar una foto de perfil a este usuario. Para ello, debemos ser capaces de subir im\u00e1genes, y recortarlas para que todas tengan una forma uniforme. Empecemos.<\/p>\n<h4>Materiales necesarios:<\/h4>\n<ul>\n<li>Node.js<\/li>\n<li>Express<\/li>\n<li>Biblioteca 'fs' de Node.js<\/li>\n<li>Binarios GraphicsMagick<\/li>\n<\/ul>\n<h4>M\u00f3dulos de nodo utilizados:<\/h4>\n<ul>\n<li>Couchbase Node.js SDK\/N1QL<\/li>\n<li>body-parser<\/li>\n<li>uuid<\/li>\n<li>Multer<\/li>\n<li>GraphicsMagick<\/li>\n<\/ul>\n<h4>Resumen:<\/h4>\n<p>Una de las partes m\u00e1s dif\u00edciles de construir Touchbase fue crear una forma de almacenar im\u00e1genes. Esto fue una lucha porque hay muchas partes diferentes (front-end y back-end) que deben unirse para este proceso. Era necesario recortar las im\u00e1genes para que los usuarios tuvieran el m\u00e1ximo control sobre ellas. Esto requiri\u00f3 un m\u00f3dulo de recorte para Angular.js, <a href=\"https:\/\/github.com\/koorgoo\/ngCropper\">ng-cropper<\/a>as\u00ed como una forma de cambiar el tama\u00f1o de la imagen a las nuevas dimensiones en el back-end proporcionado por <a href=\"https:\/\/www.graphicsmagick.org\/\">graphicsMagick<\/a>. Tambi\u00e9n era necesario elegir en qu\u00e9 formato almacenar estas im\u00e1genes (base64), entre muchos enfoques diferentes. Esta entrada del blog cubre el proceso de pasar la imagen de front-end a back-end, incluyendo el recorte y el formato.<\/p>\n<h4>Instalaci\u00f3n de Multer y GraphicsMagick<\/h4>\n<p>La configuraci\u00f3n del m\u00f3dulo Multer es una parte importante de este proceso. Multer es un m\u00f3dulo de nodo que utilizamos para almacenar las im\u00e1genes que se publican desde el front-end, en una carpeta de nuestro servidor. Para descargar el m\u00f3dulo, ejecute el siguiente comando.<\/p>\n<pre><code>$ npm install multer --save<\/code><\/pre>\n<p>Otro m\u00f3dulo importante que necesitamos es GraphicsMagick. La descarga de GraphicsMagick debe hacerse en dos partes: instalar los binarios de GraphicsMagick en tu sistema, y descargar el m\u00f3dulo node GraphicsMagick. Esta combinaci\u00f3n nos permite alterar im\u00e1genes en una ruta de archivo especificada dentro de nuestra aplicaci\u00f3n Node.js. Las instrucciones para descargar los binarios GraphicsMagick para los sistemas Linux, OSX y Windows se pueden encontrar en la p\u00e1gina web <a href=\"https:\/\/github.com\/couchbaselabs\/touchbase\/blob\/master\/PREREQUISITES.md\">Repo Github de Touchbase<\/a>. Una vez completado este paso, descargue el m\u00f3dulo node para GraphicsMagick con el siguiente comando.<\/p>\n<pre><code>$ npm install gm --save<\/code><\/pre>\n<h4>Configuraci\u00f3n del multer<\/h4>\n<p>La configuraci\u00f3n del m\u00f3dulo Multer se realiza en el m\u00f3dulo <strong>app.js<\/strong> y ayudar\u00e1 a indicar en qu\u00e9 fase del proceso de carga se encuentra una imagen. La parte que m\u00e1s nos interesa es cu\u00e1ndo se completa la carga de una imagen, lo que se indica mediante una variable llamada <strong>Hecho<\/strong>. Una vez que esto ocurra, podremos acceder con seguridad al archivo y realizar el recorte y la reducci\u00f3n de tama\u00f1o necesarios de la imagen.<\/p>\n<h4>app.js Configuraci\u00f3n de Multer<\/h4>\n<p>Hay un punto final de la API que se encarga de recortar y reducir el tama\u00f1o de la imagen (utilizando la configuraci\u00f3n que hicimos anteriormente), y la mayor parte de su trabajo se produce en el archivo <strong>\"Imagen.intento<\/strong> funci\u00f3n. Esta funci\u00f3n s\u00f3lo se ejecuta una vez finalizada la carga de la imagen (cuando <strong>hecho<\/strong> es verdadero), y Multer lo ha almacenado en el archivo <strong>carga<\/strong> especificada en la carpeta <strong>app.js<\/strong> configuraci\u00f3n. La propia ruta s\u00f3lo puede recuperar unos pocos atributos de la imagen antes de que se complete la carga de la imagen. Estos metadatos que Multer recibe ser\u00e1n cruciales durante el proceso de recorte.<\/p>\n<p>Multer simplemente carga cualquier tipo de formulario que sea del tipo <strong>&lt;enctype=&#8217;multipart\/form-data&#8217;&gt;<\/strong>. La imagen es simplemente un tipo de entrada en este formulario, por lo que tambi\u00e9n podemos a\u00f1adir otros atributos al formulario. Por ejemplo, para obtener los datos de recorte de ng-cropper, creo un atributo oculto del formulario que es un objeto que contiene todos los datos de recorte. De esta forma, la imagen y los metadatos del front-end se env\u00edan juntos en el HTML POST que se ejecuta cuando se env\u00eda el formulario. Durante este proceso, tambi\u00e9n accedo al localStorage del navegador, que contiene el sessionID (discutido en la parte 3) para enviar el ID, de modo que la ruta pueda ser autenticada. El <strong>Sesi\u00f3n.auth<\/strong> se ajusta para manejar esta situaci\u00f3n en la que el identificador de sesi\u00f3n aparece en el campo <strong>req.body<\/strong> (lo que ocurre cuando se env\u00eda el sessionID como metadatos Multer). Para ver c\u00f3mo se hace, a continuaci\u00f3n se muestra la implementaci\u00f3n en Angular.js de ng-cropper, as\u00ed como el formulario HTML que carga la imagen con los datos de recorte.<\/p>\n<h4>Formulario HTML con POST en public\/html\/picture-partial.html<\/h4>\n<h4>Uso de 'ng-cropper' en pictureController dentro de public\/js\/touchbase.js<\/h4>\n<p>Multer divide los datos del formulario en dos partes diferentes cuando se env\u00edan al back-end. Todos los metadatos sobre los archivos cargados se especifican en <strong>req.files<\/strong>. Esto nos dice cosas b\u00e1sicas como la ruta de archivo de la imagen, el tama\u00f1o de la imagen, el formato de la imagen, etc. Diferentes aspectos de esto se utilizan en nuestro <strong>\"Imagen.intento<\/strong> funci\u00f3n. El resto de los datos del front-end, todo lo que no sea un fichero, se encuentra en la funci\u00f3n <strong>req.body<\/strong> atributo. Desde aqu\u00ed, podemos acceder a los datos de recorte que hemos cargado utilizando el atributo HTML del formulario. La forma de acceder a estos diferentes par\u00e1metros es utilizando los atributos de las diferentes partes del formulario. Por ejemplo, al acceder a la subida de la foto, en el formulario front-end ten\u00edamos la entrada de fichero con un nombre de <strong>FotoUsuario<\/strong>. Para acceder a los metadatos correspondientes, buscar\u00edamos en <strong>req.files.userPhoto<\/strong>. Para obtener los datos del cultivo, nos fijaremos en su nombre, <strong>cropDim<\/strong>y acceder a \u00e9l mediante <strong>'req.body.cropDim'<\/strong>. A estos datos se accede en el <strong>\/api\/uploadAttempt<\/strong> ruta, que puede verse a continuaci\u00f3n.<\/p>\n<h4>API '\/api\/uploadAttempt<\/h4>\n<p>Ahora que podemos acceder a todos estos datos, tenemos que utilizarlos. Se utilizan en el <strong>\"Imagen.intento<\/strong> funci\u00f3n en <strong>models\/picturemodel.js<\/strong> donde podemos usar esto para alterar realmente la imagen. En primer lugar, debemos comprobar que esta imagen es algo que podemos almacenar correctamente. En nuestra configuraci\u00f3n de Multer en <strong>app.js<\/strong> permitimos subir im\u00e1genes de hasta 20mb. Hacemos esto por prop\u00f3sitos de manejo de errores, permitiendo mucho m\u00e1s de lo que la mayor\u00eda necesitar\u00eda. Si se sube un archivo con un tama\u00f1o superior a nuestro l\u00edmite, Multer falla silenciosamente, por lo que simplemente establecemos un l\u00edmite aribitariamente alto. En <strong>\"Imagen.intento<\/strong>Comprobamos si la imagen pesa m\u00e1s de 7,5 MB y, en caso afirmativo, la eliminamos. En este segundo nivel de validaci\u00f3n, informar\u00edamos al usuario de que el tama\u00f1o m\u00e1ximo del archivo es de 7,5 mb y que su imagen no ha podido cargarse, indic\u00e1ndole c\u00f3mo puede solucionar el problema. El sitio <strong>'fs.unlink'<\/strong> borra el archivo usando la ruta que Multer nos dio en el comando <strong>req.files<\/strong> atributo. A continuaci\u00f3n, la funci\u00f3n llama a <strong>\"Imagen.intento<\/strong>con la ruta de archivo mencionada y manipula la imagen con la funci\u00f3n <strong>fs<\/strong> y GraphicsMagick.<\/p>\n<h4>Funci\u00f3n \"Picture.attempt<\/h4>\n<p>Los pasos finales de validaci\u00f3n de la imagen provienen de GraphicsMagick. La raz\u00f3n por la que usamos GraphicsMagick para comprobar el tipo de archivo en lugar de Multer es porque Multer s\u00f3lo comprueba la extensi\u00f3n del archivo, que no representa necesariamente el contenido. GraphicsMagick hace su propio an\u00e1lisis del archivo. Si el tipo de archivo no es uno de los formatos aceptables, la carga falla y el usuario es notificado del error. Pasando esta validaci\u00f3n, s\u00f3lo necesitamos alterar el archivo para recortarlo y reducir su tama\u00f1o.<\/p>\n<p>Utilizando GraphicsMagick, el primer paso es <strong>'autoOrient()'<\/strong> que utilizar\u00e1 los datos EXIF (un est\u00e1ndar de formato de archivos de imagen) para orientar correctamente la imagen a la orientaci\u00f3n en la que fue tomada. Esto es importante para las subidas desde m\u00f3viles, ya que muchas de ellas pueden girar 90 grados, dando lugar a una imagen extra\u00f1a.<\/p>\n<p>A continuaci\u00f3n, la imagen se recorta utilizando los datos de recorte que obtuvimos del front-end a trav\u00e9s de <strong>'req.body.cropDim'<\/strong>. Esto se pasa entonces a la funci\u00f3n de recorte de GraphicsMagick, que requiere un desplazamiento X e Y, as\u00ed como la altura y anchura de la imagen. ng-cropper espera este m\u00e9todo de recorte y nos da estos atributos cuando la imagen es recortada haciendo que sea sencillo para nosotros simplemente pasar estos atributos directamente a GraphicsMagick.<\/p>\n<p>Por \u00faltimo, reducimos el tama\u00f1o de la imagen para que el archivo sea m\u00e1s peque\u00f1o. En mi opini\u00f3n, 7,5mb, o incluso 2mb es un poco grande para estar almacenando y recuperando cada vez que se utiliza el sitio web, y se ve un perfil de usuario. Aunque esto puede no ser necesariamente una gran carga para la aplicaci\u00f3n, podr\u00eda causar una mala experiencia para los usuarios, especialmente los usuarios m\u00f3viles. Despu\u00e9s de algunas pruebas, descubr\u00ed que reducir la escala a 200px y ajustar la calidad de la imagen a 50% ten\u00eda el m\u00e1ximo beneficio en t\u00e9rminos de calidad de la imagen y tama\u00f1o del archivo. En mi implementaci\u00f3n actual, las im\u00e1genes son cuadrados de 150px. Tenga esto en cuenta, ya que es posible que desee hacer la reducci\u00f3n de tama\u00f1o de manera diferente para su aplicaci\u00f3n si decide mostrar las im\u00e1genes m\u00e1s grandes o m\u00e1s peque\u00f1as. Despu\u00e9s de todos estos cambios, esta imagen alterada se escribe sobre su ubicaci\u00f3n anterior.<\/p>\n<p>Despu\u00e9s de que la imagen est\u00e9 correctamente alterada, queremos leerla de nuevo para transformar el binario de la imagen en una cadena base64 usando un Javascript <strong>Buffer<\/strong> . La raz\u00f3n por la que hacemos esto es porque HTML puede leer base64 en sus etiquetas de imagen, por lo que esto simplificar\u00e1 la representaci\u00f3n de las im\u00e1genes en el front-end cuando queramos mostrarlas.<\/p>\n<p>Por \u00faltimo, cargamos esta cadena base64 utilizando una operaci\u00f3n de inserci\u00f3n Clave-Valor. Utilizando la <strong>Sesi\u00f3n.auth<\/strong> y el identificador de sesi\u00f3n enviado en los datos del formulario de Multer, conocemos el identificador del usuario que subi\u00f3 la imagen. Entonces en <strong>req.userID<\/strong> como podemos ver el <strong>\/api\/uploadAttempt<\/strong> API. Este ID de usuario, al que se a\u00f1ade \"_picMulterNode\", se utiliza como ID del documento para la imagen, de modo que podamos vincular f\u00e1cilmente al usuario con esta imagen en el futuro cuando necesitemos encontrar el perfil completo de un usuario.<\/p>\n<p>Couchbase es inteligente, y reconoce que esta cadena base64 que se ha subido no es JSON, y la almacena como tipo binario. Despu\u00e9s de este punto, usamos el <strong>'fs.unlink'<\/strong> para eliminar la imagen del <strong>carga<\/strong> carpeta. Esto hace que la carpeta <strong>carga<\/strong> como un b\u00fafer y, a continuaci\u00f3n, inserta el contenido base64 de la imagen en la base de datos, antes de eliminarlo de la carpeta <strong>carga<\/strong> carpeta. Finalmente, se ejecuta una consulta N1QL para cambiar el atributo booleano 'login.hasPicture' para el usuario en cuesti\u00f3n a true, desde su valor por defecto false. Esto asegurar\u00e1 que al perfil del usuario no se le aplique la foto de stock, y en su lugar se ejecute una b\u00fasqueda de la foto de perfil subida por el usuario.<\/p>\n<h4>Funci\u00f3n \"Picture.receive<\/h4>\n<p>Al final de toda esta carga de im\u00e1genes, tambi\u00e9n tiene que haber una forma de recibir la foto de perfil de cada usuario. Para ello, utilizamos la funci\u00f3n <strong>Picture.receive<\/strong> funci\u00f3n. \u00c9sta se llama en el <strong>\/api\/advancedSearch<\/strong> API en <strong>rutas\/routes.js<\/strong> porque este endpoint tiene que encontrar a cada usuario y su foto de perfil para mostrarla en el front-end. El sitio <strong>Picture.receive<\/strong> toma el documentID de un usuario como entrada y devuelve la cadena base64 de su imagen. Primero comprueba que el booleano 'login.hasPicture' es verdadero. Si no lo es, simplemente aplica la imagen por defecto al usuario. Si el atributo es verdadero, entonces toma el atributo 'uuid' del usuario y le a\u00f1ade '_picMulterNode' y luego hace un get KEY\/VALUE est\u00e1ndar para recuperar la imagen del usuario, que almacenamos como una cadena base64. El c\u00f3digo para esta funci\u00f3n se puede ver arriba.<\/p>\n<p>En resumen, utilizamos Multer para gestionar las cargas de archivos desde <strong>&lt;enctype=&#8217;multipart\/form-data&#8217;&gt;<\/strong> formularios, y los almacen\u00f3 en un <strong>carga<\/strong> en nuestro servidor. Tambi\u00e9n utilizamos atributos ocultos dentro de este formulario para almacenar los datos de recorte de ng-cropper, y los a\u00f1adimos al cuerpo de los datos enviados en Multer. En el back-end, usamos GraphicsMagick para recortar primero la imagen con los datos de recorte de ng-cropper, y redujimos el tama\u00f1o de la imagen para una mejor UX. Convertimos la imagen a base64, la almacenamos en Couchbase, y la guardamos con un documentID que est\u00e1 relacionado con el documentID del usuario. Por \u00faltimo, escribimos una funci\u00f3n para recuperar la cadena de imagen base64 de un individuo, de modo que se pueda utilizar con facilidad dentro de un atributo de imagen HTML en el front-end.<\/p>\n<p>Con esto concluye la parte de carga de im\u00e1genes de la serie de tutoriales de Touchbase. \u00a1Por favor, deje un comentario a continuaci\u00f3n con cualquier comentario, y gracias por leer!<\/p>","protected":false},"excerpt":{"rendered":"<p>Parte 4: Carga de im\u00e1genes Hasta ahora, la Parte 0 y la Parte 1 cubren el modelo de datos y el documento de usuario utilizado en la aplicaci\u00f3n, seguido por la Parte 2 donde verificamos cuentas a trav\u00e9s de correo electr\u00f3nico utilizando Nodemailer y Sendgrid. Luego tuvimos la parte [...]<\/p>","protected":false},"author":60,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1816,1822,1812],"tags":[],"ppma_author":[9034],"class_list":["post-2102","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-server","category-node-js","category-n1ql-query"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.0 (Yoast SEO v26.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Multer and base64 Encoding: How to Upload Image in Node.js<\/title>\n<meta name=\"description\" content=\"This blog post covers the process of image uploads with Multer and base64 encoding from front-end to back-end, including cropping and formatting.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Exploring Couchbase and N1QL through Touchbase using Node.js and Angular.js \u2013 Part 4: Image Uploads with Multer and base64 encoding\" \/>\n<meta property=\"og:description\" content=\"This blog post covers the process of image uploads with Multer and base64 encoding from front-end to back-end, including cropping and formatting.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2016-01-08T22:00:20+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-07-05T19:14:14+00:00\" \/>\n<meta name=\"author\" content=\"Pranav Mayuram\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Pranav Mayuram\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/\"},\"author\":{\"name\":\"Pranav Mayuram\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/454261061bad5159ad2696e0bf162eaa\"},\"headline\":\"Exploring Couchbase and N1QL through Touchbase using Node.js and Angular.js \u2013 Part 4: Image Uploads with Multer and base64 encoding\",\"datePublished\":\"2016-01-08T22:00:20+00:00\",\"dateModified\":\"2023-07-05T19:14:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/\"},\"wordCount\":2040,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Couchbase Server\",\"Node.js\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/\",\"name\":\"Multer and base64 Encoding: How to Upload Image in Node.js\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2016-01-08T22:00:20+00:00\",\"dateModified\":\"2023-07-05T19:14:14+00:00\",\"description\":\"This blog post covers the process of image uploads with Multer and base64 encoding from front-end to back-end, including cropping and formatting.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Exploring Couchbase and N1QL through Touchbase using Node.js and Angular.js \u2013 Part 4: Image Uploads with Multer and base64 encoding\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/454261061bad5159ad2696e0bf162eaa\",\"name\":\"Pranav Mayuram\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/61baa4ff0f18aa9a8ce672f0f97f1ac0\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/de8b1b457fdc2f5f8b407ef8bf0bfcacb1e2be0ab9de2cee8e8aa4ee7f985709?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/de8b1b457fdc2f5f8b407ef8bf0bfcacb1e2be0ab9de2cee8e8aa4ee7f985709?s=96&d=mm&r=g\",\"caption\":\"Pranav Mayuram\"},\"description\":\"Pranav Mayuram is a N1QL Query language intern, Couchbase. Built a social network platform, Touchbase, using Couchbase Server, Node.js, Express &amp; Angular.js.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/pranav-mayuram\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Multer y codificaci\u00f3n base64: C\u00f3mo subir una imagen en Node.js","description":"Esta entrada de blog cubre el proceso de carga de im\u00e1genes con Multer y codificaci\u00f3n base64 desde el front-end al back-end, incluyendo recorte y formateo.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/","og_locale":"es_MX","og_type":"article","og_title":"Exploring Couchbase and N1QL through Touchbase using Node.js and Angular.js \u2013 Part 4: Image Uploads with Multer and base64 encoding","og_description":"This blog post covers the process of image uploads with Multer and base64 encoding from front-end to back-end, including cropping and formatting.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/","og_site_name":"The Couchbase Blog","article_published_time":"2016-01-08T22:00:20+00:00","article_modified_time":"2023-07-05T19:14:14+00:00","author":"Pranav Mayuram","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Pranav Mayuram","Est. reading time":"9 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/"},"author":{"name":"Pranav Mayuram","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/454261061bad5159ad2696e0bf162eaa"},"headline":"Exploring Couchbase and N1QL through Touchbase using Node.js and Angular.js \u2013 Part 4: Image Uploads with Multer and base64 encoding","datePublished":"2016-01-08T22:00:20+00:00","dateModified":"2023-07-05T19:14:14+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/"},"wordCount":2040,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Couchbase Server","Node.js","SQL++ \/ N1QL Query"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/","url":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/","name":"Multer y codificaci\u00f3n base64: C\u00f3mo subir una imagen en Node.js","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2016-01-08T22:00:20+00:00","dateModified":"2023-07-05T19:14:14+00:00","description":"Esta entrada de blog cubre el proceso de carga de im\u00e1genes con Multer y codificaci\u00f3n base64 desde el front-end al back-end, incluyendo recorte y formateo.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/exploring-couchbase-and-n1ql-through-touchbase-using-node-js-and-angular-js-part-4-image-uploads-with-multer-and-base64-encoding\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Exploring Couchbase and N1QL through Touchbase using Node.js and Angular.js \u2013 Part 4: Image Uploads with Multer and base64 encoding"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/454261061bad5159ad2696e0bf162eaa","name":"Pranav Mayuram","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/61baa4ff0f18aa9a8ce672f0f97f1ac0","url":"https:\/\/secure.gravatar.com\/avatar\/de8b1b457fdc2f5f8b407ef8bf0bfcacb1e2be0ab9de2cee8e8aa4ee7f985709?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/de8b1b457fdc2f5f8b407ef8bf0bfcacb1e2be0ab9de2cee8e8aa4ee7f985709?s=96&d=mm&r=g","caption":"Pranav Mayuram"},"description":"Pranav Mayuram es pasante de lenguaje de consulta N1QL, Couchbase. Construy\u00f3 una plataforma de red social, Touchbase, usando Couchbase Server, Node.js, Express &amp; Angular.js.","url":"https:\/\/www.couchbase.com\/blog\/es\/author\/pranav-mayuram\/"}]}},"authors":[{"term_id":9034,"user_id":60,"is_guest":0,"slug":"pranav-mayuram","display_name":"Pranav Mayuram","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/de8b1b457fdc2f5f8b407ef8bf0bfcacb1e2be0ab9de2cee8e8aa4ee7f985709?s=96&d=mm&r=g","author_category":"","last_name":"Mayuram","first_name":"Pranav","job_title":"","user_url":"","description":"Pranav Mayuram es pasante de lenguaje de consulta N1QL, Couchbase. Construy\u00f3 una plataforma de red social, Touchbase, usando Couchbase Server, Node.js, Express &amp; Angular.js."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2102","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/60"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=2102"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2102\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=2102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=2102"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=2102"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=2102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}