Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save a <canvas> as a file in a form

Using Canvas method toDataURL, I would like to be able to save the image on the server side (using Rails).

With toDataURL string, how to use it in a form that can be seen as a file attachment in a HTML form ?

like image 576
Pierre Valade Avatar asked May 11 '10 04:05

Pierre Valade


People also ask

How do you save a canvas file?

To save a new Canvas document:Choose File | Save As. In the Save As dialog box, select a location to store the document and type a file name. Click Save to store the document on disk.

How do I save a canvas file as a JPEG?

You can save a canvas to an image file by using the method canvas. toDataURL() , that returns the data URI for the canvas' image data.


2 Answers

Solution using jQuery, Paperclip, datafy.rb http://gist.github.com/397615

like image 105
Pierre Valade Avatar answered Oct 18 '22 15:10

Pierre Valade


Here is my solution:

  • The problem: Compact uploaded images of any size before sending it to the server, which will save the image.
  • Files involved: 2 ASP pages: one that will act client-side and another server-side.

The Presentation page:

<html>
<!-- by [email protected] - on december/2012 -->
<script language='javaScript'>
// Check for the various File API support.
    if (window.File && window.FileReader && window.FileList && window.Blob) {
      // Great success! All the File APIs are supported.
    } else {
        alert('Este Browser não suporte a API Files');
    }


    function Compactar(Elemento) {
        var file = document.getElementById(Elemento), 
            reader = new FileReader(),      // métodos assíncronos, por isso os eventos!
            form = document.getElementById('frmFotos');

        //alert(file.id);

        reader.readAsDataURL(file.files[0]);            // aqui a abertura do arquivo, que irá disparar a função acima

        reader.onloadend = function() {     // aqui um evento, que será disparado na primeira linha abaixo da função chamada 
            var image = new Image();
            image.src = reader.result;      // vai disparar o tratamento do evento abaixo

            image.onload = function() {
                var maxWidth = 800,
                    maxHeight = 600,
                    width = image.width,
                    height = image.height;


                // calculate the width and height, constraining the proportions
                if (width > height) {
                    if (width > maxWidth) {
                      //height *= max_width / width;
                      height = Math.round(height *= maxWidth / width);
                      width = maxWidth;
                    }
                } else {
                    if (height > maxHeight) {
                      //width *= max_height / height;
                      width = Math.round(width *= maxHeight / height);
                      height = maxHeight;
                    }
                }

                var canvas = document.createElement('canvas');
                canvas.width = width;
                canvas.height = height;

                var ctx = canvas.getContext("2d");
                ctx.drawImage(image, 0, 0, maxWidth, maxHeight);

                // The resized file ready for upload
                var finalFile = canvas.toDataURL("image/jpeg",0.8);     //a 80% de qualidade

                // aqui cria-se novo input comun!
                /*var newinput = document.createElement("input");
                newinput.type = 'text';
                newinput.name = "edt" & Elemento;
                newinput.value = finalFile; // put result from canvas into new hidden input
                form.appendChild(newinput);*/
                document.getElementById("edtArq_1").value = finalFile;

                var preview = document.getElementById('preview');
                //alert(preview.id);
                preview.appendChild(canvas); // do the actual resized preview

            }

        }       
    }
</script>

<html>


<form id="form" action="submit" method="post" accept-charset="utf-8" enctype="multipart/form-data">


<!-- this will be left behind - we don't want to upload Mbytes of information -->

<input type='file' name='Arq_1' id='Arq_1' size='50' onchange='Compactar("Arq_1");'>


<form method="POST" id='frmFotos' action='SalvaArquivo.asp'>

<!-- this could be a hidden element -->
<input name='edtArq_1' id='edtArq_1'><br>

<input type='submit' name ='cmdEnviar' id='cmdEnviar' value='Enviar' >
</form>

<!-- just for you see the new resized image - no upload too -->
<div id="preview"></div>

</html>

The page that will reveive the request from the first page and save the image:

<html>
<!-- by [email protected] - on december/2012 -->
<!-- this script could be avoided if I had put the img element in the page directly 
. By the way, actualyy there's no necessity of showing nothing to user 
 -->
<script language='JavaScript'>
    var newImg = document.createElement("img");
    newImg.src = '<%=request.form("edtArq_1")%>';
    document.body.appendChild(newImg);
</script>

<body>

<input name='edtOriginal' value='<%=request.form("edtArq_1")%>'>

<%
' the data is encoded, so, we will need to deencode it ...

Function Base64Decode(ByVal base64String)
  'rfc1521
  '1999 Antonin Foller, Motobit Software, http://Motobit.cz
  Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  Dim dataLength, sOut, groupBegin

  'remove white spaces, If any
  base64String = Replace(base64String, vbCrLf, "")
  base64String = Replace(base64String, vbTab, "")
  base64String = Replace(base64String, " ", "")

  'The source must consists from groups with Len of 4 chars
  dataLength = Len(base64String)
  If dataLength Mod 4 <> 0 Then
    Err.Raise 1, "Base64Decode", "Bad Base64 string."
    Exit Function
  End If

  ' Now decode each group:
  For groupBegin = 1 To dataLength Step 4
    Dim numDataBytes, CharCounter, thisChar, thisData, nGroup, pOut
    ' Each data group encodes up To 3 actual bytes.
    numDataBytes = 3
    nGroup = 0

    For CharCounter = 0 To 3
      ' Convert each character into 6 bits of data, And add it To
      ' an integer For temporary storage.  If a character is a '=', there
      ' is one fewer data byte.  (There can only be a maximum of 2 '=' In
      ' the whole string.)

      thisChar = Mid(base64String, groupBegin + CharCounter, 1)

      If thisChar = "=" Then
        numDataBytes = numDataBytes - 1
        thisData = 0
      Else
        thisData = InStr(1, Base64, thisChar, vbBinaryCompare) - 1
      End If
      If thisData = -1 Then
        Err.Raise 2, "Base64Decode", "Bad character In Base64 string."
        Exit Function
      End If

      nGroup = 64 * nGroup + thisData
    Next

    'Hex splits the long To 6 groups with 4 bits
    nGroup = Hex(nGroup)

    'Add leading zeros
    nGroup = String(6 - Len(nGroup), "0") & nGroup

    'Convert the 3 byte hex integer (6 chars) To 3 characters
    pOut = Chr(CByte("&H" & Mid(nGroup, 1, 2))) + _
      Chr(CByte("&H" & Mid(nGroup, 3, 2))) + _
      Chr(CByte("&H" & Mid(nGroup, 5, 2)))

    'add numDataBytes characters To out string
    sOut = sOut & Left(pOut, numDataBytes)
  Next

  Base64Decode = sOut
End Function


' now, we will save the data (new image) using the old FileSystemObject !!!

Set fso = Server.CreateObject ("Scripting.FileSystemObject")

If Err.Number <> 0 Then
    Response.write "Não foi possível instanciar objeto fso!<br>" & Err.description
    response.end
End if

dim Caminho, objArq

Caminho = Server.MapPath("./images")   'where I saved the new image
response.write Caminho

If Err.Number <> 0 Then
    Response.write "Não foi possível localizar caminho! " & Caminho & "<br>" & Err.description & "<br>"
else
    Set oFile = fso.CreateTextFile(Caminho & "\Teste.jpg", true)
    oFile.Write Base64Decode(replace(request.form("edtArq_1"), "data:image/jpeg;base64,", "")) 'BinaryToString(request.from("edtArq_1"))

    If Err.Number <> 0 Then
        Response.write "Não foi possível localizar thum(s)!" & Caminho & "<br>" & Err.description & "<br>"
    end if

    oFile.close
end if

%>

</body>
</html>
like image 33
Artur Avatar answered Oct 18 '22 13:10

Artur