Jcrop & Canvas: странный размер обрезанной области и 500 Internal Server Error

Введение

Технологический поток

Итак, я делаю веб-приложение, в котором пользователи должны иметь возможность загружать изображение и обрезать его:

  1. Пользователь выбирает локальное изображение
  2. URL-адрес объекта создается из изображения
  3. URL-адрес объекта является источником <img>
  4. Jcrop применяется к этому <img>
  5. Выбранная область кадрирования рисуется на холсте
  6. URL-адрес данных создается из этого холста
  7. Этот URL-адрес данных записывается в файл, который хранится на сервере.

Проблемы

  1. Размер области обрезки, хранящейся на холсте, в несколько раз больше размера исходного изображения.
  2. Когда я в конце концов пытаюсь записать URL-адрес декодированных данных в файл, я получаю 500 Internal Server Error.

Код

Примечание. Код упрощен

event_handlers.js

jQuery('#my_upload_input').change(function(my_event)
{
    my_load_image(my_event.currentTarget.files);
});

jQuery(document).keyup(function(my_event)
{
    if (my_event.which == 13)
    {
        my_crop_image();
    }
});

image_handling.js

var my_file_glob;
var my_image_glob;
var my_jcrop_api_glob;

function my_load_image(my_files)
{
    var my_file_glob = my_files[0];
    var my_image_glob = new Image();

    my_image_glob.onload = function()
    {
        my_show_image();
    };
    my_image_glob.src = URL.createObjectURL(my_file_glob);
}

function my_show_image()
{
    jQuery('#my_container').html('<img id="my_img" src="' + my_image_glob.src + '" />');

    jQuery('#my_img').Jcrop(
    {
        boxWidth: 1280,
        boxHeight: 720,
        trueSize: [my_image_glob.width, my_image_glob.height],
        setSelect: [0, 0, 1920, 1080],
        aspectRatio: 1920 / 1080,
        minSize: [1920, 1080],
        bgColor: '',
        allowSelect: false
    }, function()
    {
        my_jcrop_api_glob = this;
    });
}

function my_crop_image()
{
    if (typeof my_jcrop_api_glob !== 'undefined')
    {
        var my_selection = my_jcrop_api_glob.tellSelect();
        var my_canvas = document.createElement('canvas');
        var my_canvas_context = my_canvas.getContext('2d');

        my_canvas.width = my_selection.w;
        my_canvas.height = my_selection.h;

        my_canvas_context.drawImage(my_image_glob, my_selection.x, my_selection.y, my_selection.w, my_selection.h, 0, 0, my_selection.w, my_selection.h);

        my_upload_canvas(my_canvas);
    }
}

function my_upload_canvas(my_canvas)
{
    var my_canvas_url = my_canvas.toDataURL('image/png');

    jQuery.ajax(
    {
        type: 'POST',
        url: 'ajax_calls.php',
        data:
        {
            my_canvas_url: my_canvas_url
        },
        success: function(my_response)
        {
            alert(my_response);
            window.location.reload(true);
        }
    });
}

ajax_calls.js

if(isset($_POST['my_canvas_url']))
{
    $my_canvas_url = $_POST['my_canvas_url'];
    my_upload_canvas($my_canvas_url);
}

function my_upload_canvas($my_canvas_url)
{
    $my_canvas_data_enc = explode(',', $my_canvas_url)[1];
    $my_canvas_data_enc = str_replace(' ', '+', $my_canvas_data_enc);

    $my_canvas_data_dec = base64_decode($my_canvas_data_enc);

    file_put_contents(dirname(__FILE__) . '/menu.png', $my_canvas_data_dec);

    if($my_png_created !== false)
    {
        echo 'success';
    }
    else
    {
        echo 'failure';
    }
}

Дополнительный

В функции my_upload_canvas(my_canvas) я написал эти несколько строк, чтобы сравнить размер исходного изображения и обрезанной области:

var head = 'data:image/png;base64,';
var imgfilesize = Math.round((my_canvas_url.length - head.length) * 3 / 4);
console.log('size orig: ' + Math.round(my_file_glob.size));
console.log('size crop: ' + Math.round(imgfilesize));
console.log('cropped area is ' + Math.round(imgfilesize / my_file_glob.size) + ' times bigger than the original image');

Выходные данные для трех разных изображений следующие:

JPEG (807 КБ)

size orig: 826730
size crop: 2445081
cropped area is 3 times bigger than the original image

JPG (141 КБ)

size orig: 144837
size crop: 1201146
cropped area is 8 times bigger than the original image

PNG (334 КБ)

size orig: 342617
size crop: 53799
cropped area is 0 times bigger than the original image

Обратите внимание, что размеры обрезанных областей изображений № 1 и № 2 больше, чем размеры самих исходных изображений, но не изображения № 3.


Обновление №1

Внутренняя ошибка сервера 500 была вызвана $ перед функцией plugins_url()... глупый я. Но, к сожалению, сохранить .png все равно не получится (даже не могу создать файл). Введение и код обновлены.

Обновление №2

Загрузка изображения теперь работает! Я заменил
file_put_contents(plugins_url('/menu.png', __FILE__), $my_canvas_data_dec)
на
file_put_contents(dirname(__FILE__) . '/menu.png', $my_canvas_data_dec)
, так как очевидно, что URL-адрес не будет работать, но полный путь будет работать. Введение и код обновлены.

Обновление №3

Тайна раскрыта! Как вы можете прочитать здесь, холст содержит не больше информации, чем пикселей изображения. Поэтому размер URL-адреса данных зависит от того, как браузер кодирует эти пиксели, и может привести к тому, что он будет больше размера изображения. Кроме того, PNG в большинстве случаев будет намного больше, чем JPEG того же холста.


person Flo1231    schedule 18.03.2015    source источник


Ответы (1)


Я понял это сам. Пожалуйста, посмотрите обновления моего поста, если вам интересны ответы.

person Flo1231    schedule 19.03.2015