Загрузка изображения

Как загрузить фотографии на сайт — это интересный вопрос. Просто загрузка файлов немного скучная вещь, поэтому добавим важную особенность — обрезка. Для этого мы применим HTML5 FileReader и плагин Jcrop для библиотеки jQuery. Процесс обрезки изображения в пользовательский размер состоит из трёх действий: выбрать файл -> обрезать -> готово (результат будет в новом окне).

Загрузить и обрезать изображение

При выборе изображения для загрузки будет проверяться тип и размер изображения (что бы избежать больших файлов) по умолчанию разрешены файлы с расширением jpg, png. Размеры изображения указаны в пикселях. После обрезки изображения — кликнем (готово) этот файл загрузится на нашем сайте (в определенной папке). Пожалуйста, обратите внимание, что GD библиотеки, необходимые для обработки изображений. Если вы готовы — давайте начнем.

Демо

к меню ↑

HTML

<!-- стили -->
<link href="css/main.css" rel="stylesheet" type="text/css" />
<link href="css/jquery.Jcrop.min.css" rel="stylesheet" type="text/css" />

<!-- скрипты -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.Jcrop.min.js"></script>
<script type="text/javascript" src="js/script.js"></script>

Форма загрузки изображения HTML5 и выбор размера:

<div class="bbody">

    <!-- форма загрузки -->
 <form id="upload_form" action="upload.php" enctype="multipart/form-data" method="post" onsubmit="return checkForm()">

    <!-- скрытые параметры -->
 <input id="x1" type="hidden" name="x1" />
 <input id="y1" type="hidden" name="y1" />
 <input id="x2" type="hidden" name="x2" />
 <input id="y2" type="hidden" name="y2" />

    <!-- Выбрать файл изображения -->

    <div><input id="image_file" type="file" name="image_file" onchange="fileSelectHandler()" /></div>
    <div class="error"></div>
    <div class="step2">

    <!-- Указать новый размер -->

    <img id="preview" alt="" />
       <div class="info">
         <label>Размер файла</label> <input id="filesize" type="text" name="filesize" />
         <label>Тип</label> <input id="filetype" type="text" name="filetype" />
         <label>Размер изображения</label> <input id="filedim" type="text" name="filedim" />
         <label>Ширина</label> <input id="w" type="text" name="w" />
         <label>Высота</label> <input id="h" type="text" name="h" /></div>
         <input type="submit" value="Готово" />
      </div>
   </form>
</div>

Эта форма загрузки с нужными полями, как только изображение выбрано приступаем ко второму действию обрезка изображения. После обрезки изображения до не обходимого размера, после нажатия кнопки готово увидим что получилось.

к меню ↑

CSS

Файл css/main.css

.bheader {
    background-color: #DDDDDD;
    border-radius: 10px 10px 0 0;
    padding: 10px 0;
    text-align: center;
}
.bbody {
    color: #000;
    overflow: hidden;
    padding-bottom: 20px;
    text-align: center;

    background: -moz-linear-gradient(#ffffff, #f2f2f2);
    background: -ms-linear-gradient(#ffffff, #f2f2f2);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2));
    background: -webkit-linear-gradient(#ffffff, #f2f2f2);
    background: -o-linear-gradient(#ffffff, #f2f2f2);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2');
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')";
    background: linear-gradient(#ffffff, #f2f2f2);
}
.bbody h2, .info, .error {
    margin: 10px 0;
}
.step2, .error {
    display: none;
}
.error {
    font-size: 18px;
    font-weight: bold;
    color: red;
}
.info {
    font-size: 14px;
}
label {
    margin: 0 5px;
}
input {
    border: 1px solid #CCCCCC;
    border-radius: 10px;
    padding: 4px 8px;
    text-align: center;
    width: 70px;
}
.jcrop-holder {
    display: inline-block;
}
input[type=submit] {
    background: #e3e3e3;
    border: 1px solid #bbb;
    border-radius: 3px;
    -webkit-box-shadow: inset 0 0 1px 1px #f6f6f6;
    box-shadow: inset 0 0 1px 1px #f6f6f6;
    color: #333;
    font: bold 12px/1 "helvetica neue", helvetica, arial, sans-serif;
    padding: 8px 0 9px;
    text-align: center;
    text-shadow: 0 1px 0 #fff;
    width: 150px;
}
input[type=submit]:hover {
    background: #d9d9d9;
    -webkit-box-shadow: inset 0 0 1px 1px #eaeaea;
    box-shadow: inset 0 0 1px 1px #eaeaea;
    color: #222;
    cursor: pointer;
}
input[type=submit]:active {
    background: #d0d0d0;
    -webkit-box-shadow: inset 0 0 1px 1px #e3e3e3;
    box-shadow: inset 0 0 1px 1px #e3e3e3;
    color: #000;
}
к меню ↑

JavaScript

Файл js/script.js

function bytesToSize(bytes) {
    var sizes = ['Bytes', 'KB', 'MB'];
    if (bytes == 0) return 'n/a';
    var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
    return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
};

// выбрать полигон обрезки
function checkForm() {
    if (parseInt($('#w').val())) return true;
    $('.error').html('Please select a crop region and then press Upload').show();
    return false;
};

// обновление
function updateInfo(e) {
    $('#x1').val(e.x);
    $('#y1').val(e.y);
    $('#x2').val(e.x2);
    $('#y2').val(e.y2);
    $('#w').val(e.w);
    $('#h').val(e.h);
};

// очистка инфы об обрезке
function clearInfo() {
    $('.info #w').val('');
    $('.info #h').val('');
};

function fileSelectHandler() {

    // добавить выбранный файл
    var oFile = $('#image_file')[0].files[0];

    // ошибочка
    $('.error').hide();

    // проверка расширения файла
    var rFilter = /^(image\/jpeg|image\/png)$/i;
    if (! rFilter.test(oFile.type)) {
        $('.error').html('Please select a valid image file (jpg and png are allowed)').show();
        return;
    }

    // проверка веса файла
    if (oFile.size > 250 * 1024) {
        $('.error').html('You have selected too big file, please select a one smaller image file').show();
        return;
    }

    // просмотр
    var oImage = document.getElementById('preview');

    // HTML5 FileReader
    var oReader = new FileReader();
        oReader.onload = function(e) {

        // e.target.result contains the DataURL
        oImage.src = e.target.result;
        oImage.onload = function () { // onload event handler

            // показать
            $('.step2').fadeIn(500);

            // показать инфу
            var sResultFileSize = bytesToSize(oFile.size);
            $('#filesize').val(sResultFileSize);
            $('#filetype').val(oFile.type);
            $('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight);

            // переменные для размера изображения
            var jcrop_api, boundx, boundy;

            // давай до свидания Jcrop
            if (typeof jcrop_api != 'undefined')
                jcrop_api.destroy();

            // инициировать Jcrop
            $('#preview').Jcrop({
                minSize: [32, 32], // min crop size
                aspectRatio : 1, // keep aspect ratio 1:1
                bgFade: true, // use fade effect
                bgOpacity: .3, // fade opacity
                onChange: updateInfo,
                onSelect: updateInfo,
                onRelease: clearInfo
            }, function(){

                // спросить у API реальный размер изображения
                var bounds = this.getBounds();
                boundx = bounds[0];
                boundy = bounds[1];

                // подружить Jcrop API с переменными jcrop_api
                jcrop_api = this;
            });
        };
    };

    // чтение выбранного файла как DataURL
    oReader.readAsDataURL(oFile);
}

Есть несколько общих функций в начале: bytesToSize, checkForm, UpdateInfo и clearInfo — они лёгкие. Следующая функция fileSelectHandler является более сложной, в основной — это главная функция. Когда мы выбрали изображение будет проверка файла на тип и размер. Здесь можно увидеть фильтр для формата изображений PNG и JPG.

Кроме этого, нам не нужны очень большие изображения, я думаю, что 250кб более чем достаточно. Затем, мы можем увидеть наш выбранный файл, используя функции HTML5 FileReader :: readAsDataURL. Как только изображение загружено на сервер, поля внизу покажут информацию о загруженном изображении а потом. Как только указали новый размер изображения, нажимаем кнопку Готово, чтобы отправить результаты на сервер в папку cache.

к меню ↑

PHP

Файл upload.php
Функция PHP покажет результат на сервере:

function uploadImageFile() { // Note: GD library is required for this function

    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
        $iWidth = $iHeight = 200; // desired image result dimensions
        $iJpgQuality = 90;

        if ($_FILES) {

            // if no errors and size less than 250kb
            if (! $_FILES['image_file']['error'] && $_FILES['image_file']['size'] < 250 * 1024) {
                if (is_uploaded_file($_FILES['image_file']['tmp_name'])) {

                    // new unique filename
                    $sTempFileName = 'cache/' . md5(time().rand());

                    // move uploaded file into cache folder
                    move_uploaded_file($_FILES['image_file']['tmp_name'], $sTempFileName);

                    // change file permission to 644
                    @chmod($sTempFileName, 0644);

                    if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) {
                        $aSize = getimagesize($sTempFileName); // try to obtain image info
                        if (!$aSize) {
                            @unlink($sTempFileName);
                            return;
                        }

                        // check for image type
                        switch($aSize[2]) {
                            case IMAGETYPE_JPEG:
                                $sExt = '.jpg';

                                // create a new image from file
                                $vImg = @imagecreatefromjpeg($sTempFileName);
                                break;
                            /*case IMAGETYPE_GIF:
                                $sExt = '.gif';

                                // create a new image from file
                                $vImg = @imagecreatefromgif($sTempFileName);
                                break;*/
                            case IMAGETYPE_PNG:
                                $sExt = '.png';

                                // create a new image from file
                                $vImg = @imagecreatefrompng($sTempFileName);
                                break;
                            default:
                                @unlink($sTempFileName);
                                return;
                        }

                        // create a new true color image
                        $vDstImg = @imagecreatetruecolor( $iWidth, $iHeight );

                        // copy and resize part of an image with resampling
                        imagecopyresampled($vDstImg, $vImg, 0, 0, (int)$_POST['x1'], (int)$_POST['y1'], $iWidth, $iHeight, (int)$_POST['w'], (int)$_POST['h']);

                        // define a result image filename
                        $sResultFileName = $sTempFileName . $sExt;

                        // output image to file
                        imagejpeg($vDstImg, $sResultFileName, $iJpgQuality);
                        @unlink($sTempFileName);

                        return $sResultFileName;
                    }
                }
            }
        }
    }
}

$sImage = uploadImageFile();
echo '<img src="'.$sImage.'" />';

Проверка размера и тип файла выполняется на стороне сервера тоже. В результате — мы получаем двойную защиту на стороне пользователя frontend и на стороне сервера backend от ненужных файлов.

  • Функция загрузки изображения move_uploaded_file
  • Функции обрезки изображения: imagecreatefromjpeg, imagecreatetruecolor и imagecopyresampled,
  • Функция показа результата imagejpeg.

Обратите внимание, кроме обрезки мы также изменим размер изображение 200 × 200px. Я выбрал этот размер по умолчанию для всех входящих фотографий: 200 × 200 это чаще всего нужный размер для аватарки. Наконец — мы можем увидеть это изображение на экране. Поле внизу покажет путь к изображению, имя изображения в виде ключа.

Статья подготовлена для вас коллективом сайта htmlhook.ru
Оригинал статьи: script-tutorials.com/html5-image-uploader-with-jcrop
Перевел: Виктор Клим
Правила использования материалов сайта!