2012-04-25 24 views
6

Así que tengo un formulario, y de esta forma un usuario puede cargar una imagen. Como alternativa, quiero que puedan tomar una foto y cargarla en su lugar. Imagen de cámara web directamente al archivo adjunto


Ahora supongo que cuando un usuario toma una imagen con algún tipo de interfaz de cámara flash, esa imagen debe almacenarse en algún tipo de memoria intermedia mientras el usuario completa su forma.

¿Hay alguna forma de evitar esto? ¿Cuál es la mejor solución?

Creo que solo hay dos opciones.

O bien (a) Guardo la foto temporal y luego la vuelvo a aceptar una vez que se envía el formulario o (b) el usuario toma una foto, la descarga en su máquina local y la debe elegir como una archivo para ser enviado de nuevo.

Ninguna de estas soluciones es realmente satisfactoria para mí, así que quería saber si hay alguna forma mejor de hacerlo.

Editar: Como una ventaja adicional, aunque no es realmente relevante, estoy haciendo una aplicación de Rails con Paperclip para archivos adjuntos. Además, yo prefiero trabajar con jQuery ...

también acaba opiniones generales de los desarrolladores web con experiencia de interfaz de usuario estaría bien ..

+0

Puede utilizar el 'canvas' de HTML para contener datos de imágenes tomado de la cámara web a un 'div' y luego guárdelo cuando el usuario envíe el formulario. Hice esto hace casi 8 a 9 meses. ¿Quieres la implementación del código? o buscando un tipo de respuesta de mejores prácticas? – Surya

+0

Facebook/Google lo ha implementado bien. Probablemente, échales un vistazo. – Surya

+0

@Surya Sí, una implementación de código sería MUY útil. – varatis

Respuesta

5

que había usado esto: http://www.xarg.org/project/jquery-webcam-plugin/ en mi solicitud rieles para capturar una imagen de una webcam. Puede descargar este jQuery-cámara web aquí: https://github.com/infusion/jQuery-webcam

Aquí es una aplicación más o menos hecho, lo siento por el código desordenado:

class PicturesController < ApplicationController 
    require 'base64' 
    def capture 
     # do something 
     render :layout => "webcam" 
    end 

    def save_image 
     image = params[:capture][:image] 
     File.open("#{Rails.root}/public/path_you_want_to_image/image_name.png", 'wb') do |f| 
     f.write(Base64.decode64(image)) 
     end 
     # Or use paperclip to save image for a model instead!! 
    end 
end 

views/layouts/webcam.html.erb:

<!DOCTYPE html> 
<html> 
<head> 
    <title>Application Name</title> 
    <%= stylesheet_link_tag :all %> 
    <%= javascript_include_tag :defaults %> 
    <%= javascript_include_tag "http://www.google-analytics.com/ga.js"%> 
    <%= javascript_include_tag "http://code.jquery.com/jquery-1.4.2.min.js"%> 
    <%= javascript_include_tag "jquery.webcam"%> 
    <script> 
     !window.jQuery && document.write('<script src="jquery-1.4.3.min.js"><\/script>'); 
    </script> 
    <%= csrf_meta_tag %> 
</head> 
<body> 
    <%= yield %> 
</body> 
</html> 

vistas/imágenes/capture.html.erb:

<div id="webcam"> 
    <p>Capture image here!</p> 
    </div> 

    <%= form_for(save_image_pictures_path, :method => "post", :remote => true) do |f|%> 
    <%= hidden_field(:item, :sku)%> 
    <div id="capture_images"><input id="capture_image" type="hidden" value="" name="capture[image]"></div> 
    <%= submit_tag "Capture Image", :onClick=>"javascript:capture_image();"%> 
    <% end %>  
    <%= link_to "Back", root_path %> 
    <p> 
    <canvas id="canvas" width="320" height="240"></canvas> 
    </p> 

<script type="text/javascript"> 

var pos = 0; 
var ctx = null; 
var cam = null; 
var image = null; 

var filter_on = false; 
var filter_id = 0; 

function changeFilter() { 
    if (filter_on) { 
     filter_id = (filter_id + 1) & 7; 
    } 
} 

function capture_image(){ 
    webcam.capture(); 
    changeFilter(); 
    void(0); 
    var canvas = document.getElementById('canvas') 
    var context = canvas.getContext("2d"); 
    var img  = canvas.toDataURL("image/png"); 
    var item_image = img.replace(/^data:image\/(png|jpg);base64,/, "") ; 
    document.getElementById('capture_images').innerHTML="<input id=\"capture_image\" type=\"hidden\" value=\""+item_image+"\" name=\"capture[image]\">"; 
} 

function toggleFilter(obj) { 
    if (filter_on =!filter_on) { 
     obj.parentNode.style.borderColor = "#c00"; 
    } else { 
     obj.parentNode.style.borderColor = "#333"; 
    } 
} 

    jQuery("#webcam").webcam({ 

    width: 320, 
    height: 240, 
    mode: "callback", 
    swffile: "/javascripts/jscam_canvas_only.swf", 

    onTick: function(remain) { 

     if (0 == remain) { 
      jQuery("#status").text("Cheese!"); 
     } else { 
      jQuery("#status").text(remain + " seconds remaining..."); 
     } 
    }, 

    onSave: function(data) { 

     var col = data.split(";"); 
     var img = image; 

     if (false == filter_on) { 

      for(var i = 0; i < 320; i++) { 
       var tmp = parseInt(col[i]); 
       img.data[pos + 0] = (tmp >> 16) & 0xff; 
       img.data[pos + 1] = (tmp >> 8) & 0xff; 
       img.data[pos + 2] = tmp & 0xff; 
       img.data[pos + 3] = 0xff; 
       pos+= 4; 
      } 

     } else { 

      var id = filter_id; 
      var r,g,b; 
      var r1 = Math.floor(Math.random() * 255); 
      var r2 = Math.floor(Math.random() * 255); 
      var r3 = Math.floor(Math.random() * 255); 

      for(var i = 0; i < 320; i++) { 
       var tmp = parseInt(col[i]); 

       /* Copied some xcolor methods here to be faster than calling all methods inside of xcolor and to not serve complete library with every req */ 

       if (id == 0) { 
        r = (tmp >> 16) & 0xff; 
        g = 0xff; 
        b = 0xff; 
       } else if (id == 1) { 
        r = 0xff; 
        g = (tmp >> 8) & 0xff; 
        b = 0xff; 
       } else if (id == 2) { 
        r = 0xff; 
        g = 0xff; 
        b = tmp & 0xff; 
       } else if (id == 3) { 
        r = 0xff^((tmp >> 16) & 0xff); 
        g = 0xff^((tmp >> 8) & 0xff); 
        b = 0xff^(tmp & 0xff); 
       } else if (id == 4) { 

        r = (tmp >> 16) & 0xff; 
        g = (tmp >> 8) & 0xff; 
        b = tmp & 0xff; 
        var v = Math.min(Math.floor(.35 + 13 * (r + g + b)/60), 255); 
        r = v; 
        g = v; 
        b = v; 
       } else if (id == 5) { 
        r = (tmp >> 16) & 0xff; 
        g = (tmp >> 8) & 0xff; 
        b = tmp & 0xff; 
        if ((r+= 32) < 0) r = 0; 
        if ((g+= 32) < 0) g = 0; 
        if ((b+= 32) < 0) b = 0; 
       } else if (id == 6) { 
        r = (tmp >> 16) & 0xff; 
        g = (tmp >> 8) & 0xff; 
        b = tmp & 0xff; 
        if ((r-= 32) < 0) r = 0; 
        if ((g-= 32) < 0) g = 0; 
        if ((b-= 32) < 0) b = 0; 
       } else if (id == 7) { 
        r = (tmp >> 16) & 0xff; 
        g = (tmp >> 8) & 0xff; 
        b = tmp & 0xff; 
        r = Math.floor(r/255 * r1); 
        g = Math.floor(g/255 * r2); 
        b = Math.floor(b/255 * r3); 
       } 

       img.data[pos + 0] = r; 
       img.data[pos + 1] = g; 
       img.data[pos + 2] = b; 
       img.data[pos + 3] = 0xff; 
       pos+= 4; 
      } 
     } 

     if (pos >= 0x4B000) { 
      ctx.putImageData(img, 0, 0); 
      pos = 0; 
     } 

    }, 

    onCapture: function() { 
     webcam.save('/product_capture'); 

     jQuery("#flash").css("display", "block"); 
     jQuery("#flash").fadeOut(100, function() { 
      jQuery("#flash").css("opacity", 1); 
     }); 

    }, 

    debug: function (type, string) { 
     jQuery("#status").html(type + ": " + string); 
    }, 

    onLoad: function() { 

     var cams = webcam.getCameraList(); 
     for(var i in cams) { 
      jQuery("#cams").append("<li>" + cams[i] + "</li>"); 
     } 
    } 
}); 

function getPageSize() { 

    var xScroll, yScroll; 

    if (window.innerHeight && window.scrollMaxY) { 
     xScroll = window.innerWidth + window.scrollMaxX; 
     yScroll = window.innerHeight + window.scrollMaxY; 
    } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac 
     xScroll = document.body.scrollWidth; 
     yScroll = document.body.scrollHeight; 
    } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari 
     xScroll = document.body.offsetWidth; 
     yScroll = document.body.offsetHeight; 
    } 

    var windowWidth, windowHeight; 

    if (self.innerHeight) { // all except Explorer 
     if(document.documentElement.clientWidth){ 
      windowWidth = document.documentElement.clientWidth; 
     } else { 
      windowWidth = self.innerWidth; 
     } 
     windowHeight = self.innerHeight; 
    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode 
     windowWidth = document.documentElement.clientWidth; 
     windowHeight = document.documentElement.clientHeight; 
    } else if (document.body) { // other Explorers 
     windowWidth = document.body.clientWidth; 
     windowHeight = document.body.clientHeight; 
    } 

    // for small pages with total height less then height of the viewport 
    if(yScroll < windowHeight){ 
     pageHeight = windowHeight; 
    } else { 
     pageHeight = yScroll; 
    } 

    // for small pages with total width less then width of the viewport 
    if(xScroll < windowWidth){ 
     pageWidth = xScroll; 
    } else { 
     pageWidth = windowWidth; 
    } 

    return [pageWidth, pageHeight]; 
} 

window.addEventListener("load", function() { 

    jQuery("body").append("<div id=\"flash\"></div>"); 

    var canvas = document.getElementById("canvas"); 

    if (canvas.getContext) { 
     ctx = document.getElementById("canvas").getContext("2d"); 
     ctx.clearRect(0, 0, 320, 240); 

     var img = new Image(); 
     img.src = "/images/rails.png"; 
     img.onload = function() { 
      ctx.drawImage(img, 129, 89); 
     } 
     image = ctx.getImageData(0, 0, 320, 240); 
    } 

    var pageSize = getPageSize(); 
    jQuery("#flash").css({ height: pageSize[1] + "px" }); 

}, false); 

window.addEventListener("resize", function() { 

    var pageSize = getPageSize(); 
    jQuery("#flash").css({ height: pageSize[1] + "px" }); 

}, false); 
</script> 

Solo asegúrese de que el archivo "jscam.swf" al que se hace referencia en jquery.webcam.js esté cargado correctamente en la página.

rutas que se pueden definir en su routes.rb son:

resources :pictures do 
    collection do 
    get 'capture' 
    post 'save_image' 
    end 
end 

A partir de aquí, a continuación, puede utilizar este: https://github.com/blueimp/jQuery-File-Upload para subirlo utilizando un formulario de envío Ajax !!

Háganme saber si tiene alguna pregunta.

+0

¡Guau! Gracias por la respuesta muy completa. Lo investigaré en las próximas semanas para asegurarme de que sepa, pero esto es exactamente lo que estaba buscando. – varatis

+0

Un par de preguntas: ¿qué hacen los oyentes de eventos de la ventana al final de capture.html.erb? También onCapture llama a webcam.save ('/ product_capture'); .... Pero no veo eso en sus rutas. – varatis

+0

@varatis He pegado solamente el código requerido para que esta cámara web jQuery funcione con su aplicación. 'webcam.save ('/ product_capture')' en el evento onCapture fue solo una prueba para publicar los datos de la imagen en la ruta 'product_capture' desde su método de devolución de llamada. Pero, ese tipo de trabajo no funcionó para mí. Simplemente verifique si ese método de devolución de llamada funciona para usted creando una ** ruta ** de publicación para 'product_capture'. No se preocupe, la solución que he publicado aquí está funcionando, si no funciona, hágamelo saber, puedo proporcionar mi código real. Que es algo grande y desordenado, hice todo esto cuando era un novato en los rieles ..: P – Surya

0

Errores.

Reemplazar

def save_image 
    image = params[:canvas][:image] 
    File.open("#{Rails.root}/public/path_you_want_to_image/image_name.png", 'wb') do |f| 
    f.write(Base64.decode64(image)) 
    end 
    # Or use paperclip to save image for a model instead!! 
end 

por el

def save_image 
    image = params[:capture][:image] 
    File.open("#{Rails.root}/public/path_you_want_to_image/image_name.png", 'wb') do |f| 
    f.write(Base64.decode64(image)) 
    end 
    # Or use paperclip to save image for a model instead!! 
end 

y

function capture_image(){ 
webcam.capture(); 
changeFilter(); 
void(0); 
var canvas = document.getElementById('canvas') 
var context = canvas.getContext("2d"); 
var img  = canvas.toDataURL("image/png"); 
var item_image = img.replace(/^data:image\/(png|jpg);base64,/, "") ; 
document.getElementById('capture_images').innerHTML="<input id=\"capture_image\" type=\"hidden\" value=\""+capture_image+"\" name=\"capture[image]\">";} 

a

function capture_image(){ 
webcam.capture(); 
changeFilter(); 
void(0); 
var canvas = document.getElementById('canvas') 
var context = canvas.getContext("2d"); 
var img  = canvas.toDataURL("image/png"); 
var item_image = img.replace(/^data:image\/(png|jpg);base64,/, "") ; 
document.getElementById('capture_images').innerHTML="<input id='capture_image' type='hidden' value=\'"+item_image+"\' name='capture[image]'>";} 

Después de esto, todo funciona bien.

PS. Si obtuvo: "capture_image() no es un fn", cambie el nombre fn a: "capture_images()" no olvide cambiar el nombre en el evento onClick

+0

corrigió el código, gracias por estar atento y llegar. Lo aprecio. – Surya

Cuestiones relacionadas