通过动态创建 html 文件元素来上传克隆的画布照片,默认值为画布图像

Posted

技术标签:

【中文标题】通过动态创建 html 文件元素来上传克隆的画布照片,默认值为画布图像【英文标题】:Uploading a cloned canvas photo by dynamically creating a html file element with the default value being the canvas image 【发布时间】:2015-07-15 15:15:45 【问题描述】:

我正在尝试将图像过滤器应用于图像,并在每次单击过滤器时重新创建文件元素。因此,这将是伪代码。它仍然说文件字段为空,我不知道为什么。

我正在尝试将文件传递给处理上传的 php 脚本,但我不确定如何在脚本中执行此操作,因为我的 javascript 技能不够好..

HTML

<div id="uploadPic" class="modal fade" >
  <form method="post" id="fileinfo" name="fileinfo" onsubmit="return submitForm();">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header" style="background:#f3f3f3;">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title" style="color:black;">Choose picture to upload as profile pic.</h4>          
            </div>
            <div class="modal-body">
              <div id="filterContainer" style='width:400px;'>
                <ul id="filters" style='width:400px;'>
                  <li> <a href="#" id="normal">Normal</a> </li>
                  <li> <a href="#" id="vintage">Vintage</a> </li>
                  <li> <a href="#" id="lomo">Lomo</a> </li>
                  <li> <a href="#" id="clarity">Clarity</a> </li>
                  <li> <a href="#" id="sinCity">Sin City</a> </li>
                  <li> <a href="#" id="sunrise">Sunrise</a> </li> 
                  <li> <a href="#" id="crossProcess">Cross Process</a> </li>
                  <li> <a href="#" id="orangePeel">Orange Peel</a> </li>
                  <li> <a href="#" id="love">Love</a> </li>
                  <li> <a href="#" id="grungy">Grungy</a> </li>
                  <li> <a href="#" id="jarques">Jarques</a> </li>
                  <li> <a href="#" id="pinhole">Pinhole</a> </li>
                  <li> <a href="#" id="oldBoot">Old Boot</a> </li>
                  <li> <a href="#" id="glowingSun">Glowing Sun</a> </li>
                  <li> <a href="#" id="hazyDays">Hazy Days</a> </li>
                  <li> <a href="#" id="herMajesty">Her Majesty</a> </li>
                  <li> <a href="#" id="nostalgia">Nostalgia</a> </li>
                  <li> <a href="#" id="hemingway">Hemingway</a> </li>
                  <li> <a href="#" id="concentrate">Concentrate</a> </li>
                </ul>
              </div>
              <div id='output_file'></div>
              <div id="output"></div>
              <div id="photo">
                <a href="#" class="downloadImage" target="_blank" download="photo.png">Download Image</a>-
              </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <input type="submit" value="Upload" class="btn btn-info" data-dismiss="modal" onClick="return submitForm();"/> 
            </div>
        </div>
    </div>
  </form>
</div> 

JavaScript:

$(function() 
    /*
        In this code, we are going to do the following:
        1. Accept an image on drag and drop
        2. Create a new canvas element (original), with a max size
           of 500x500px (customizable) and keep it in memory
        3. Listen for clicks on the filters. When one is selected:
                3.1 Create a clone of the original canvas
                3.2 Remove any canvas elements currently on the page
                3.3 Append the clone to the #photo div
                3.4 If the selected filter is different from the "Normal"
                    one, call the Caman library. Otherwise do nothing.
                3.5 Mark the selected filter with the "active" class
        4. Trigger the "Normal" filter
    */
    var maxWidth = 500,
        maxHeight = 500,
        photo = $('#photo'),
        originalCanvas = null,
        filters = $('#filters li a'),
        filterContainer = $('#filterContainer');
    // Use the fileReader plugin to listen for
    // file drag and drop on the photo div:
    photo.fileReaderJS(
        on:
            load: function(e, file)
                // An image has been dropped.
                var img = $('<img>').appendTo(photo),
                    imgWidth, newWidth,
                    imgHeight, newHeight,
                    ratio;
                // Remove canvas elements left on the page
                // from previous image drag/drops.
                photo.find('canvas').remove();
                filters.removeClass('active');

                // When the image is loaded successfully,
                // we can find out its width/height:
                img.load(function() 
                    imgWidth  = this.width;
                    imgHeight = this.height;
                    // Calculate the new image dimensions, so they fit
                    // inside the maxWidth x maxHeight bounding box
                    if (imgWidth >= maxWidth || imgHeight >= maxHeight) 
                        // The image is too large,
                        // resize it to fit a 500x500 square!
                        if (imgWidth > imgHeight) 
                            // Wide
                            ratio = imgWidth / maxWidth;
                            newWidth = maxWidth;
                            newHeight = imgHeight / ratio;
                         else 
                            // Tall or square
                            ratio = imgHeight / maxHeight;
                            newHeight = maxHeight;
                            newWidth = imgWidth / ratio;
                        
                     else 
                        newHeight = imgHeight;
                        newWidth = imgWidth;
                    
                    // Create the original canvas.
                    originalCanvas = $('<canvas>');
                    var originalContext = originalCanvas[0].getContext('2d');
                    // Set the attributes for centering the canvas
                    originalCanvas.attr(
                        width: newWidth,
                        height: newHeight
                    ).css(
                        marginTop: -newHeight/2,
                        marginLeft: -newWidth/2
                    );
                    // Draw the dropped image to the canvas
                    // with the new dimensions
                    originalContext.drawImage(this, 0, 0, newWidth, newHeight);
                    // We don't need this any more
                    img.remove();
                    filterContainer.fadeIn();
                    // Trigger the default "normal" filter
                    filters.first().click();
                );
                // Set the src of the img, which will
                // trigger the load event when done:
                img.attr('src', e.target.result);
            ,
            beforestart: function(file)
                // Accept only images.
                // Returning false will reject the file.
                return /^image/.test(file.type);
            
        
    );
    // Listen for clicks on the filters
    filters.click(function(e)
        e.preventDefault();
        var f = $(this);
        if(f.is('.active'))

            // Apply filters only once
            return false;
        
        filters.removeClass('active');
        f.addClass('active');
        // Clone the canvas
        var clone = originalCanvas.clone();
        // Clone the image stored in the canvas as well
        clone[0].getContext('2d').drawImage(originalCanvas[0],0,0);
        // Add the clone to the page and trigger
        // the Caman library on it
        photo.find('canvas').remove().end().append(clone);
        var effect = $.trim(f[0].id);
        Caman(clone[0], function () 
            // If such an effect exists, use it:
            if( effect in this)
                this[effect]();
                this.render();
        var url = clone[0].toDataURL("image/png;base64;");
        $("#output_file").html('<input type="file" name="file" value="'+url+'" required / >');
                // Show the download button
                showDownload(clone[0]);
            
            else
                hideDownload();
            
        );
    );
    // Use the mousewheel plugin to scroll
    // scroll the div more intuitively
    filterContainer.find('ul').on('mousewheel',function(e, delta)
        this.scrollLeft -= (delta * 50);
        e.preventDefault();
    );
    var downloadImage = $('a.downloadImage');
    function showDownload(canvas)
        downloadImage.off('click').click(function()
            // When the download link is clicked, get the
            // DataURL of the image and set it as href:
            var url = canvas.toDataURL("image/png;base64;");
            downloadImage.attr('href', url);
        ).fadeIn();
    
    function hideDownload()
        downloadImage.fadeOut();
    
);

PHP:

<?php
$username = $_POST["username"];
$timestamp = $_POST["timestamp"];
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp);
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 200000)
&& in_array($extension, $allowedExts)) 
    if ($_FILES["file"]["error"] > 0) 
        #echo "Return Code: " . $_FILES["file"]["error"] . "<br>";
     else 
        $filename = $username.$timestamp.$_FILES["file"]["name"];
        #echo "Upload: " . $_FILES["file"]["name"] . "<br>";
        #echo "Type: " . $_FILES["file"]["type"] . "<br>";
        #echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
        #echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br>";
        if (file_exists("images/profile_images/" . $filename)) 
            echo $filename . " already exists. ";
         else 
            move_uploaded_file($_FILES["file"]["tmp_name"],
            "images/profile_images/" . $filename);
            echo "images/profile_images/" . $filename;
        
    
 else 
    echo "Invalid file";

?>

根据 Rayon 的评论,我正在执行以下操作:

每次单击过滤器时,都会将 base64 附加到我的主页上的表单数据中。因此,当有人点击上传时,它会将该数据发送到 pho 脚本。

var fd = new FormData(document.getElementById("fileinfo"));
fd.append("file_upload", clone[0].toDataURL("image/png;base64;"));

这是我当前用于处理 AJAX 请求的 JavaScript:

function submitForm() 
  if (get_user != logged_username)  else 
    var d = new Date();
    var time = d.getTime();
    //console.log(document.getElementById("file"));
    var fd = new FormData(document.getElementById("fileinfo"));
    //console.log(fd);
    fd.append("username", logged_username);
    fd.append("timestamp", time);
    $.ajax(
      url: "upload_photo.php",
      type: "POST",
      data: fd,
      enctype: 'multipart/form-data',
      processData: false, // tell jQuery not to process the data
      contentType: false // tell jQuery not to set contentType
    ).done(function(data) 
      if (data.indexOf("Invalid") >= 0) 
        alert('invalid file type, must be jpeg, jpg, or png.');
       else 
        var post = 
          "pic_location": data,
          "time": time,
          "username": logged_username
        ;
        console.log(data);
        var json_data = post;
        Cynergi.insert('http://thhd.com:3000/profile_pictures', json_data);
        //this is where we save the photos location to the db for retrieveal.
      
    );
    return false;
  

然后是php:

<?php

    // requires php5
    define('UPLOAD_DIR', 'images/profile_images/');
    $img = $_POST['file_info'];
    $img = str_replace('data:image/png;base64,', '', $img);
    $img = str_replace(' ', '+', $img);
    $data = base64_decode($img);
    $file = UPLOAD_DIR . uniqid() . '.png';
    $success = file_put_contents($file, $data);
    echo $file;
    print $success ? $file : 'Unable to save the file.';

?>

日志输出显示:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfQAAAH0CAYAAADL1t+KAAAgAElEQ…P3PeerM0GN4J7vE4xyTdlT34hvfOMbuiYnL6xlqkUu4v8BZ033tp7lXCwAAAAASUVORK5CYII=

php返回无法保存文件,它保存了一个0字节的文件。

这可行,但它放置了一个 0 字节的文件,我不知道为什么。

【问题讨论】:

【参考方案1】:

不需要文件输入。您可以在画布上绘制图像并在用户的每次操作后重新绘制它,如果您愿意存储该图像,那么您需要使用 php 脚本将图像的 Base64 数据操作到图像中..

【讨论】:

不知道该怎么做 :) 但我至少有方向 你是否实现了根据用户操作操作画布数据?如果是,那么剩下的任务非常小.. thewaywardjourney.com 注册用户点击相机图标 上传部分是我不懂的部分 参考此链接:j-query.blogspot.in/2011/02/…

以上是关于通过动态创建 html 文件元素来上传克隆的画布照片,默认值为画布图像的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jquery 将动态创建的 img 元素加载到 HTML5 画布中

如何上传/发布多个画布元素

画布中的 HTML5 图像适合问题

动态 HTML 元素创建

github项目上传与克隆

有没有一种不用图像就可以用 HTML5 画布和 javascript 动态绘制云的好方法?