Sigueme en Facebook Sigueme en Twitter Sigueme en Instagram Sigueme en Youtube
JC Mouse Bolivia
Index / Android / Subir imagen a un servidor web con REST/JSON

Subir imagen a un servidor web con REST/JSON

Autor jc mouse viernes, diciembre 5, 2014

En este tutorial crearemos una sencilla aplicación para android que nos permitirá subir una imagen a un servidor web. La imagen que subiremos sera una foto que tomemos con nuestra cámara, pero aquí lo importante no subiremos archivos grandes sino archivos que no excedan los 1MB de peso esto porque para subir archivos pesados se utiliza otra forma que veremos en post futuros.

Necesitamos

  •  IDE Eclipse con SDK Android instalado
  • Conocimientos sobre Java, PHP, JSON
  • Un dispositivo android o el emulador que viene con el SDK :/
  • Un servidor web 🙂 si no tienes uno pago, puedes encontrar hosting gratuitos en toda la red.

Nivel: Intermedio

Tiempo: 15 minutos

Tutorial

El APIREST

Antes de desarrollar la aplicación android, nos detendremos un momento para ver lo que sera nuestro API REST, no construiremos nada complicado sino por el contrario nuestra API consistirá en un solo archivo PHP el cual estará a la espera de un objeto JSON con la siguiente forma:

{
  "encodedImage": "\/9j\/4AAQSkZJRgABAQAAAQABAAD\.."
}

Como vemos nuestro JSON contiene un solo parámetro que es “encodeImage” que contiene en una cadena  la imagen codificada en Base64, mientras mas grande sea la imagen a enviar, más grande sera la cadena que se forme y podremos tener algunos problemas, es por eso que las imagen que usemos no deben exceder los 1000×1000 pixeles a lo mucho.

Nuestro apirest.php tendrá el siguiente codigo

<?php
   $data = file_get_contents("php://input");
   $datares = array( 'Result'=>"200" );
   saveJSON($data);
   print ( json_encode( $datares ) );

   function saveJSON($data)
   { 
      $file = 'photo.txt';
      $success = file_put_contents($file, $data);
   }
?>

Como se ve, nuestra sencilla API, espera un JSON el cual guarda en un archivo de texto “photo.txt“, esto para que veas como es que se envía la imagen codificada.  Nuestra api debe responder cuando le llega la petición POST y responde un JSON con una variable “Result” con valor de 200, esto para informar de que se recibió la imagen correctamente, por la sencillez de nuestra aplicación no nos detendremos en más detalles como control de errores o cosas por el estilo, suponemos que nos llega un JSON con la forma indicada más arriba y listo 🙂

Cuando subamos una imagen, más o menos esto es lo que veras en tu navegador:

imagen codificada

Para terminar el trabajo en el servidor web, creamos un nuevo archivo php con el nombre de “photo.php“, este archivo tiene la tarea de leer el archivo “photo.txt” creado cuando se sube una imagen al servidor, y decodificar su contenido para transformar y mostrar en pantalla la imagen restaurada. El codigo es el siguiente:

<?php
if (file_exists('photo.txt')) 
{
 header("Content-type: image/gif");
 $json = file_get_contents('photo.txt');
 $obj = json_decode($json);
 echo base64_decode( $obj->{'encodedImage'} );
}
else
{
 echo 'No se cargo ninguna fotografia';
}
?>

Una vez creados los archivos y subidos al servidor, podemos comenzar a crear la aplicación android.
1. El proyecto

Crea un nuevo proyecto android en eclipse con el nombre de “UploadImageToServer“, deja el MainActivity que se crea por defecto y añade un par de clases como se ve en la imagen de abajo:

upload file

2. Interfaz

Abre el archivo “Strings.xml” y cambia el contenido por:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Upload Image to Server</string>
    <string name="action_settings">Settings</string>
    <string name="strUpload">Subir al servidor</string>

</resources>

A continuación, abre el archivo “activity_main.xml” que esta en la carpeta Layout y reemplaza el contenido por:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <ImageView
        android:id="@+id/photo"
        android:layout_width="180dp"
        android:layout_height="180dp"    
        android:layout_gravity="center"    
        android:src="@drawable/ic_launcher" />

    <Button
        android:id="@+id/btnUpload"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="26dp"
        android:text="@string/strUpload" />

</LinearLayout>

En la vista diseño podremos ver algo como esto

vista previa app

Abre el archivo AndroidManifest.xml y agrega el permiso para internet

<uses-permission android:name="android.permission.INTERNET" />

3. APIREST

En nuestra clase “ApiRest.java” declaramos el método uploadPhoto(…) para subir la imagen codificada en Base64 al servidor mediante POST y JSON, el código es el siguiente:

package com.bolivia.uploadimage;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import org.json.JSONObject;

public class ApiRest {

 private final String HTTP_EVENT="http://tuweb.net/api/apirest.php";

 /**
 * Envia la imagen codificada al servidor
 * @param String encodedImage Imagen codificada con Base64
 * @throws IOException 
 * @throws ClientProtocolException 
 * @throws JSONException
 * */
 public Boolean uploadPhoto(String encodedImage) throws ClientProtocolException, IOException, JSONException
 {
  HttpClient httpclient = new DefaultHttpClient();
  //url y tipo de contenido
  HttpPost httppost = new HttpPost(HTTP_EVENT);
  httppost.addHeader("Content-Type", "application/json");
  //forma el JSON y tipo de contenido
  JSONObject jsonObject = new JSONObject();
  jsonObject.put("encodedImage", encodedImage );
  //
  StringEntity stringEntity = new StringEntity( jsonObject.toString());  
  stringEntity.setContentType( (Header) new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));  
  httppost.setEntity(stringEntity);  
  //ejecuta
  HttpResponse response = httpclient.execute(httppost);
  //obtiene la respuesta y transorma a objeto JSON 
  String jsonResult = inputStreamToString(response.getEntity().getContent()).toString();
  JSONObject object = new JSONObject(jsonResult);  
  if( object.getString("Result").equals("200"))
  {    
   return true;
  } 
  return false;  
 }

 /**
 * Transforma el InputStream en un String
 * @return StringBuilder
 * */
 private StringBuilder inputStreamToString(InputStream is)
 {  
  String line = "";
  StringBuilder stringBuilder = new StringBuilder();
  BufferedReader rd = new BufferedReader( new InputStreamReader(is) );  
  try
  {
   while( (line = rd.readLine()) != null )
   {
    stringBuilder.append(line);
   }
  }
  catch( IOException e)
  {
   e.printStackTrace(); 
  }

  return stringBuilder;
 }

}//end:ApiRest

4. Tarea en segundo plano

Como ya se vio en post anteriores, android no nos permite ejecutar tareas que puedan colgar la aplicación en el hilo principal por tal motivo debemos hacer uso dela clase  AsyncTask que nos permite ejecutar en un nuevo hilo el método para subir el archivo al servidor.

package com.bolivia.uploadimage;

import java.io.IOException;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;

public class MyAsyncTask extends AsyncTask<String,Void,Boolean>{

 private ProgressDialog progressDialog;
 AlertDialog.Builder builder;
 private Context context;

 /**Constructor de clase */
 public MyAsyncTask(Context context) {
        this.context = context;
        builder = new AlertDialog.Builder(context);        
    }
 /**
 * Antes de comenzar la tarea muestra el progressDialog
 * */
  @Override
  protected void onPreExecute() {
       super.onPreExecute();         
       progressDialog = ProgressDialog.show(context, "Por favor espere", "Subiendo...");        
  }

 /**
 * @param
 * */
 @Override
 protected Boolean doInBackground(String... params) {
  Boolean r = false;
  ApiRest apiRest = new ApiRest();  
  try {
   r = apiRest.uploadPhoto(params[0]);
  } catch (ClientProtocolException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (JSONException e) {
   e.printStackTrace();
  }  
  return r;
 }

  /**
 * Cuando se termina de ejecutar, cierra el progressDialog y avisa
 * **/
   @Override
   protected void onPostExecute(Boolean resul) {
    progressDialog.dismiss();   
    if( resul )
    {
     builder.setMessage("Imagen subida al servidor")
        .setTitle("JC le informa")
        .setNeutralButton("Aceptar", new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog,int which) {
                                       dialog.cancel();                                                    
        }
        }).create().show();  
    } 
    else
    {
     builder.setMessage("No se pudo subir la imagen")
        .setTitle("JC le informa")
        .setNeutralButton("Aceptar", new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog,int which) {
                                       dialog.cancel();                                                    
        }
        }).create().show();
    }
   }
}

5. Unimos todo

Ya para terminar abre el MainActivity y reemplaza el código por:

package com.bolivia.uploadimage;

import java.io.ByteArrayOutputStream;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

 ImageView photo;
 Button button;
 Bitmap photobmp;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  //Controles
  button = (Button)findViewById(R.id.btnUpload);
  photo = (ImageView)findViewById(R.id.photo);

  //evento click para cargar fotografia a la aplicación
  photo.setOnClickListener(
                new View.OnClickListener() {
                    public void onClick(View view) {                     
                     Intent intent = new Intent();
                        intent.setType("image/*");
                        intent.setAction(Intent.ACTION_GET_CONTENT);
                        startActivityForResult(Intent.createChooser(intent, "Complete la acción usando..."), 1);
                    }});
  //evento click para comenzar a subir la imagen al servidor
  button.setOnClickListener(
                new View.OnClickListener() {
                    public void onClick(View view) {   
                     //Codifica la imagen con Base64
                     ByteArrayOutputStream baos = new ByteArrayOutputStream();
                     photobmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);                     
                     byte[] imageBytes = baos.toByteArray();
                     String encodedImage = Base64.encodeToString(imageBytes, Base64.DEFAULT);
                     //Se ejecuta en segundo plano para no colgar la aplicacion
                     new MyAsyncTask(MainActivity.this).execute(encodedImage);                      
                    }});  
 }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {     
     if (requestCode == 1 && resultCode == RESULT_OK) {
            Uri selectedImageUri = data.getData(); 
            String aaa = getRealPathFromURI(selectedImageUri);
            photobmp = BitmapFactory.decodeFile(aaa);
            photo.setImageBitmap(photobmp);                  
     }
    }

    /**
 * Obtiene la ruta del archivo de imagen en el dispositivo
 * @param Uri 
 * @return String
 * */
    public String getRealPathFromURI(Uri contentUri) {
       Cursor cursor = null;
       try { 
         String[] proj = { MediaStore.Images.Media.DATA };
         cursor = getApplicationContext().getContentResolver().query(contentUri,  proj, null, null, null);
         int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
         cursor.moveToFirst();
         return cursor.getString(column_index);
       } finally {
         if (cursor != null) {
           cursor.close();
         }
       }
     }    

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}

Ejecuta la aplicación, carga una imagen presionando en la imagen con el logo de android y luego presiona el boton “Subir”

kawaii

Después de unos segundos si todo salio bien, te aparecerá una ventana de dialogo avisando de que la imagen se subio con exito, en tu navegador ejecuta el photo.php y podrás ver la imagen que subiste, ejecuta también el photo.txt para ver la imagen codificada

lana de ovejaFIN 🙂

Tags

Si te ha gustado podrías compartirlo o dejar un comentario. ¡Muchas gracias!
Autor: JC Mouse

Yo soy yo :) JC Mouse, Soy orgullosamente boliviano soy fundador y CEO de la web jc-Mouse.net uno de las pocas web en emprendimiento y tecnología en Bolivia.

Toda la información que encuentres en este sitio es y sera completamente gratis siempre, puedes copiar, descargar y re-publicar si así lo deseas en otros blogs o sitios web, solo te pido a cambio que dejes una referencia a esta web. Esto nos ayuda a crecer y seguir aportando. Bye

Enjoy! :)

También Te Podría Interesar

Ejercicios con Hashtable y C#

Ejercicios con Hashtable y C#

Ejercicio: Escriba un programa en consola que implemente un Hashtable, cree una clase “Persona“, este será e...

Cargar fuente TTF

Cargar fuente TTF

Cuando realizamos un proyecto java utilizando fuentes de nuestro sistema, al momento de distribuir el programa y ejecuta...

Conexion Access con PHP

Conexion Access con PHP

Para poder conectar PHP con una base de datos de microsoft Access debemos seguir los siguientes pasos: 1. Crea una base...

Construye la interfaz de facebook

Construye la interfaz de facebook

En este tutorial veremos un poco lo que es el diseño de interfaces en android, en lugar de colocar el ejemplo de uso de...

Pruebas Unitarias con PHPUnit

Pruebas Unitarias con PHPUnit

PHPUnit es un framework que se utiliza para escribir tests en PHP, Netbeans nos permite configurarlo y usarlo fácilmente...

Imprimir imagen con Print

Imprimir imagen con Print

La siguiente clase hace uso de PRINT para imprimir una imagen que se encuentra en un variable de tipo FileInputStream, e...

21 comentarios en “Subir imagen a un servidor web con REST/JSON”

  1. Jose dice:

    Hola buen tutorial una pregunta como puedo descargar el codigo?

    1. Mouse dice:

      el proyecto no esta disponible para descarga pero en el tutorial tienes las clases necesarias para implementarlo por ti mismo

  2. Antonio dice:

    Buen tutorial

    jc Mouse un pregunta para capturar una ip webcam o camara ip en android hay alguna documentacion

    Gracias por la atencion

  3. Jesus dice:

    Muchas felicidades por la info y los tutoriales estoy comenzando con Android Studio, una pregunta se puede con este tutorial en vez de subir una imagen subir un archivo mp4, wav o 3gp. Es posible. Gracias por tu ayuda y comentario

    Jesus.

    1. Mouse dice:

      si se puede, pero estos archivos son mucho mas grandes por lo que se debe subir por lotes

      1. Jesus dice:

        La idea es no enviar archivos grandes estoy hablando de 2MB hasta cuanto crees que podria enviar sin tener que enviar por lotes.

        gracias por tu ayuda, saludos

      2. Jesus dice:

        compañero tengo una duda…si al subir la imagen es tomada por la camara del telefono pero muchos de estas camaras cuentan con una resolucion grande, es decir aumentan de tamaño como se puede disminuir el tamaño de una imagen? por decirte que las camaras actuales sacan fotografias de 3Mb a 6 Mb, como volverlo a kb el tamaño,

  4. jose luis dice:

    buen tutorioal solo una pregunta donde indicas la ruta donde se guardara la imagen ?

  5. hannsell dice:

    hola una pregunta como haces para que en vez de guardarse la imagen en un archivo.txt se guarde en uno .jpg me parece poco practico tenerla como un txt lo implemente y funciona pero mi duda es esa la de la extenion del archivo

    1. hannsell dice:

      listo ya esta resuelto este es el codigo en apirest.php
      “200” );
      saveJSON($obj);
      print ( json_encode( $datares ) );
      function saveJSON($data){
      $file = ‘photo.jpg’;
      $success = file_put_contents($file, base64_decode($data->{‘encodedImage’}));
      }
      ?>

      con este codigo no se necesita uploadimage.php para mostrarla con json… y comprendo que el tuto era de json para el tratamiento de las imagenes…

    2. Mouse dice:

      es un ejemplo para que se pueda apreciar como se sube la imagen pero claro lo mejor es guardar en formato imagen

  6. John Honey dice:

    Hola, he sido un seguidor tuyo me encanta tu web y publicaciones, muchas felicitaciones.

    Tengo un problema, pongo la dirección donde esta el php:
    final String HTTP_EVENT=”

    Y siempre me dice que no se pudo subir el archivo, que estoy haciendo mal?, saludos.

  7. sebastian ¿vj dice:

    OLA MUCHAS GRACIAS TUE UN ERROR AL EJECUTAR LA APLICACION, EN LA LINEA 50 DE APIREST ME ARROJA LO SIGUIENTE:

    W/System.err: org.json.JSONException: Value <br of type java.lang.String cannot be converted to JSONObject

    Estas son las lineas donde curre este problema:

    String jsonResult = inputStreamToString(response.getEntity().getContent()).toString();
    JSONObject object = new JSONObject(jsonResult);

    COMO PUEDO REPARARLO??????? AYUDAME PORFAVOR ES URGENTE MUCHAS GRACIAS POR EL TUTORIAL SALUDOS

    1. Mouse dice:

      ese error te dice que lo que le pasas no se puede convertir en formato JSON verifica y valida y JSON

  8. Hola muchas gracias por tu tutoriales agradezco que hallas compartido tu conocimiento, tengo las siguientes dudas:

    1. En el php en donde debo colocar la carpeta y si tengo que darle algún permiso especial???
    2. Me gustaría que a la misma vez se alojará la imagen en una base de datos como debería hacer el proceso???
    3. En el caso de querer obtener una imagen de la galería de fotos cual seria el código correcto.

    Agradezco la colaboración que me brindes es de suma importancia para mi gracias.

    1. Mouse dice:

      1) en donde lo necesites, solo debes especificar la dirección, permisos de escritura
      2) cuando te llega el JSON tu lo procesas desde php, si lo quieres guardar en base de datos implementas las clases necesarias
      3) ¿cual galería de fotos? 🙂

  9. carlos dice:

    Que librerías debo usar para import org.apache.http.Header;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.message.BasicHeader;
    import org.apache.http.protocol.HTTP;

    gracias.

  10. Raymundo Cruz dice:

    Hola que tal! Una duda, al inicio del post mecionas que para subir archivos mayores a 1MB se utiliza otra forma, quisiera me compartieras cuál es esta forma? muchas gracias y gran artículo.

    1. Mouse dice:

      hay que subirlo por partes 🙂 me falta hace el post

  11. nelson dice:

    sabes como puedo hacer el codigo php de lado servidor pero en c# asmx asp

  12. MAURICIO dice:

    me sale error en stringEntity.setContentType( (Header) new BasicHeader(HTTP.CONTENT_TYPE, “application/json”));

    en el CONTENT_TYPE

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*

Comparte lo que sabes

Categorias

Últimas entradas

PHPUnit es un framework que se utiliza para escribir tests en PHP, Netbeans nos permite configurarlo y usarlo fácilmente...

Una Prueba Unitaria, es una forma de comprobar que nuestro código, hace lo que se supone debe hacer; es decir, se asegur...

La prueba del camino básico, es una prueba de “caja blanca” que consiste en verificar el código de nuestros...

Si quieres cambiar el nombre de tus atributos sin tener que reescribir código java por X o Y razón, GSON te permite reno...

Android Bolivia

Bandera en Alto