繁体   English   中英

Base64上传图片问题

[英]Base64 Upload Image Issue

抱歉问了这么长的问题,但我想尽可能地表达它,并以易于理解的方式提问。 我有一个程序,允许用户在 JavaScript 中使用croppie.js 裁剪图像,并将图像发送到后端运行 Lisp 程序的 Hunchentoot 服务器。 用户上传后,将 Base64 图像保存到 .png 文件时出现问题。 将发布请求发送到服务器后,我将 Base64 图像作为字符串获取,通过创建字符串的子序列来从 Base64 请求中删除无效字符,而没有发布请求发送的标题,并替换为“%”字符使 Base64 有效的“+”字符。 接下来,我删除字符串末尾的子字符串 +3D+3D,因为我在 Common Lisp 中使用的 s-base64 库抱怨 +3D​​+3D 是无效的填充,我将其替换为“==”,这被认为是有效的填充。 接下来我通过使用 s-base64 库将 Base64 字符串转换为字节数组来创建一个字节数组,并将其存储在一个变量中。 然后我遍历字节数组并将每个字节写入输出文件。 完成后,我决定将字节数组的结尾打印到控制台,以便我可以查看输出和结尾填充是否有效,这似乎是有效的。 这是代码的那部分,并带有注释以使其更清晰:

(define-easy-handler (handle-image :uri "/handle-image.html") ()
    (let ((data-source (hunchentoot:raw-post-data :force-text t))) ;get Base64 string
      (let ((new-string (subseq data-source 36))) ;create a subsequence of Base64 string
         (let ((final-string (substitute #\+ #\% new-string))) ;substitute % for +
            (let ((end (search "+3D+3D" final-string))) ;find the invalid padding
                (setf final-string (concatenate 'string (subseq final-string 0 end) "==")) ;add valid padding
                (let ((byte-array (with-input-from-string (in final-string) ;create byte array (or simple-vector) out of Base64 string
                                     (decode-base64-bytes in))))
                   (with-open-file (out "path/path/path/path/profile-image.png" ;create output stream to store file
                                         :direction :output
                                         :if-exists :supersede
                                         :element-type 'unsigned-byte)
                      (dotimes (i (length byte-array)) ;write each byte from the byte array to output stream
                        (write-byte (aref byte-array i) out)))) ;close stream
                (format t "!!!!!!!!: ~a" (subseq final-string (- (length final-string) 30))))))) ;print ending to console to ensure proper padding
       "Upload Successful") ;send response to client

这是我的一些 JavaScript 代码:

$(document).ready(function(){

     $image_crop = $('#image_demo').croppie({
        enableExif: true,
        viewport: {
          width:200,
          height:200,
          type:'square' //circle
        },
        boundary:{
          width:300,
          height:300
        }
   });

如您所见,我首先创建了裁剪器。 我允许用户有一个 200 x 200 的正方形来裁剪,裁剪空间的总大小是 300 x 300。那部分代码没有问题:

$('#upload_image').on('change', function(){
var reader = new FileReader();
reader.onload = function (event) {
  $image_crop.croppie('bind', {
    url: event.target.result
  }).then(function(){
    console.log('jQuery bind complete');
  });
}

在上面,当他们选择一个文件时,我将他们上传的图像绑定到裁剪器(就像您上传 Facebook 图像一样)。 再次,没有问题:

 reader.readAsDataURL(this.files[0]);
$('#uploadImageModal').modal('show');

上面我阅读了他们选择的文件,然后模态“弹出”,就像你在裁剪 Facebook 或 Instagram 照片一样:

$('.crop_image').click(function(event){
       $image_crop.croppie('result', {
             type: 'canvas',
             size: 'viewport'
        }).then(function(response){
               $.ajax({
                    url:"handle-image.html",
                    type: "POST",
                    data:{"image": response},
                    success:function(data){
                            $('#uploadImageModal').modal('hide');
                            $('#uploaded_image').html(data);
                     }
              });
          })
       });

上面我上传了ajax请求,如果上传成功,他们会从服务器收到一条消息,它是成功的,我也隐藏了图像裁剪的模式。

现在的问题是图像只是空白。 我知道 Base64 是有效的,因为我使用了 Base64 转换工具来查看字符串是否有效。 我还回去研究了图像的位、字节、像素和尺寸,以了解计算机如何与它们交互,所以我不确定为什么我的图像只是显示为空白。 这是裁剪器在我的网站上的样子:

在此处输入图片说明

绑定正在运行,然后我收到上传成功的消息。 但是在写入图像并在文件系统中查看后,它要么是空白图像,要么有时会说不支持该图像类型。

我在这篇文章中标记 PHP 的原因是因为我确信有些人在通过 ajax 上传裁剪图像时在 PHP 中遇到了类似的问题,其中一些解决方案可能适用于这种情况,但显然需要我翻译lisp 语法的解决方案。 我的假设是,当我将字符串转换为字节数组并将其写入文件时,我的代码有问题,但我认为如果我忽略了某些内容,最好发布代码的其他部分。

正如 Brad 评论的那样,您应该首先尝试直接使用二进制上传。

除此之外:如果您在 base64 编码的字符串中遇到% ,则很可能意味着整个内容是另外的 URL 编码的。 快速的适当搜索将do-urlencode作为一个库来解码。 +替换%使 base64 有效,但结果不一定代表有效的 jpg。

另外:使用let*而不是嵌套的let表单。 也许使用write-sequence而不是按字节输出。

感谢@Brad 和@Svante 的回答,我能够解决这个问题。 我决定将要上传的图像放在表单元素中,将画布中的 blob 图像添加为表单的 FormData,然后通过 ajax post 请求发送 FormData:

 $('.crop_image').on('click mousedown touchstart', function(event){ //When the crop image button is pressed event.
    $image_crop.croppie('result', { //Get the result of the cropper

        size: 'viewport', //Set the size to the viewport size (180 x 120)
        format: 'png', //.png format
        type: 'blob'
    }).then(function (blob){
        $form = $('#uploadForm');
        var fd = new FormData($form);
        fd.append('upload_image', blob);
        $.ajax({
        url: "handle-image.html",
        type: "POST",
        data: fd,
        processData: false,
        contentType: false,
        success: function (data){
            $('#uploadImageModal').modal('hide');
            $('#uploaded_image').html(data);
        }
        });
    })
 });

在这里,我决定将croppie 结果从“canvas”类型更改为“form”类型,并指定它将是一个.png 文件。 从那里我将新创建的表单中的表单数据添加到 .ajax 请求并从那里开始。 感谢@Brad 和@Svante 在此提供帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM