Lecaw

Учимся создавать Web-сайты

Загрузчик изображений на HTML5 и Jcrop

October 16, 2012 411hits

В последнее время нам часто стали задавать вопрос – как загрузить фотографии на веб-сайт. Мне кажется, что это интересный вопрос, и я решил поэкспериментировать с этим. Я думаю, что просто загрузка файлов это скучная тема, поэтому я решил добавить интересную опцию – Обрезка. Кроме того мы будем использовать HTML5 FileReader, чтобы выполнить обрезку будем использовать - Jcrop (jquery библиотека) на стороне клиента. В результате – мы должны получить процесс с 3 шагами: выбор файла, обрезка, загрузка. Во время выбора файла мы проверим тип файла и размер (чтобы избежать огромных файлов). Когда все будет готово и мы загрузили обрезанное изображение – мы переходим к этапу загрузки (в определенную папку сайта). Обратите внимание, что библиотека GD обрабатывает изображения.

ДЕМО Исходные файлы

 

 

Шаг 1. HTML

Наш первый шаг - разметка HTML. Для начала поместим стили и сценарии в разделе заголовка:

<!-- добавление стилей -->
<link href="/css/main.css" rel="stylesheet" type="text/css" />
<link href="/css/jquery.Jcrop.min.css" rel="stylesheet" type="text/css" /> <!-- добавление сценариев -->
<script src="/js/jquery.min.js"></script>
<script src="/js/jquery.Jcrop.min.js"></script>
<script src="/js/script.js"></script>

А теперь добавим форму загрузки:

<div class="bbody">
 <!-- форма загрузки -->
<form id="upload_form" enctype="multipart/form-data" method="post" action="upload.php"> <input type="hidden" id="x1" name="x1" />
<input type="hidden" id="y1" name="y1" />
<input type="hidden" id="x2" name="x2" />
<input type="hidden" id="y2" name="y2" /> <h2>Step1: Please select image file</h2>
<div><input type="file" name="image_file" id="image_file" /></div> <div class="error"></div> <div class="step2">
<h2>Step2: Please select a crop region</h2>
<img id="preview" /> <div class="info">
<label>File size</label> <input type="text" id="filesize" name="filesize" />
<label>Type</label> <input type="text" id="filetype" name="filetype" />
<label>Image dimension</label> <input type="text" id="filedim" name="filedim" />
<label>W</label> <input type="text" id="w" name="w" />
<label>H</label> <input type="text" id="h" name="h" />
</div> <input type="submit" value="Upload" />
</div>
</form>
</div>

Я надеюсь у вас не возникли проблемы на этом шаге, это - обычная форма загрузки со скрытыми и видимыми полями, как только мы выбрали изображение, будет показан второй шаг (обрезка). Как только мы обрезали необходимую область, мы можем загрузить результат.

Шаг 2. CSS

Теперь, я хотел бы настроить 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;
}

Шаг 3. JS

Наш следующий шаг –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;
};
// обновление информации обрезки ( обработчик событий onChange и onSelect)
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);
};
// очистка информации обрезки ( обработчик событий onRelease)
function clearInfo() {
    $('.info #w').val('');
    $('.info #h').val('');
};
function fileSelectHandler() {
    // получение выбранного файла
    var oFile = $('#image_file')[0].files[0];
    // скрыть все ошибки
    $('.error').hide();
    // проверка изрбражения ( доступны jpg, и png)
    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 содержит DataURL, который мы можем использовать в качестве источника изображения
        oImage.src = e.target.result;
        oImage.onload = function () { // обработчик событий onload
            // отображение второго шага
            $('.step2').fadeIn(500);
            // вывод на экран информации об изображении
            var sResultFileSize = bytesToSize(oFile.size);
            $('#filesize').val(sResultFileSize);
            $('#filetype').val(oFile.type);
            $('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight);
            // Создание переменных, для использования API Jcrop 
            var jcrop_api, boundx, boundy;
            // удалите Jcrop, если он уже использовался
            if (typeof jcrop_api != 'undefined')
                jcrop_api.destroy();
            // инициализация Jcrop
            $('#preview').Jcrop({
                minSize: [32, 32], // минимальный размер обрезки
                aspectRatio : 1, // сохранение форматного соотношения 1:1
                bgFade: true, // использовать эффект исчезновения
                bgOpacity: .3, // непрозрачность
                onChange: updateInfo,
                onSelect: updateInfo,
                onRelease: clearInfo
            }, function(){
                // используйте API Jcrop, чтобы получить реальный размер изображения
                var bounds = this.getBounds();
                boundx = bounds[0];
                boundy = bounds[1];
                // сохранение переменных API Jcrop в jcrop_api 
                jcrop_api = this;
            });
        };
    };
    oReader.readAsDataURL(oFile);
}

В начале есть несколько общих функций: bytesToSize, checkForm, updateInfo и clearInfo. Они довольно просты. Следующая функция (fileSelectHandler) более сложная. Когда мы выбрали файл (файл изображения), мы проверим тип и размер этого файла. Мы установили фильтр для форматов изображения: png и jpg. К тому же, нам не нужны очень большие изображения, я думаю, что 250 КБ более чем достаточно. Затем если все в порядке, мы можем отредактировать наш выбранный файл FileReader:: readAsDataURL (html5 функция). И как только результат загружен, можно продолжать: мы должны вывести на экран шаг 2 с Предварительным просмотром и разделом информации, а затем – мы должны инициализировать (или – повторно инициализировать) Jcrop для нашего изображения. Как только мы обрезали изображение, мы можем нажать кнопку 'Upload', чтобы отправить результат на сервер.

Шаг 4. PHP

На этом шаге – мы должны сохранить (и загрузить) нашу готовую фотографию.

upload.php

function uploadImageFile() { // Примечание: для этой функции требуется библиотека GD 
    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
        $iWidth = $iHeight = 200; // требуемый размер изображения
        $iJpgQuality = 90;
        if ($_FILES) {
            // если нет ошибок и размер меньше 250kb
            if (! $_FILES['image_file']['error'] && $_FILES['image_file']['size'] < 250 * 1024) {
                if (is_uploaded_file($_FILES['image_file']['tmp_name'])) {
                    // новое уникальное имя файла
                    $sTempFileName = 'cache/' . md5(time().rand());
                    // перемещение загруженного файла в папку кэша
                    move_uploaded_file($_FILES['image_file']['tmp_name'], $sTempFileName);
                    // изменение разрешения файла к 644
                    @chmod($sTempFileName, 0644);
                    if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) {
                        $aSize = getimagesize($sTempFileName); // информация об изрбражении
                        if (!$aSize) {
                            @unlink($sTempFileName);
                            return;
                        }
                        // проверьте тип изображения
                        switch($aSize[2]) {
                            case IMAGETYPE_JPEG:
                                $sExt = '.jpg';
                                // создание нового изображения из файла
                                $vImg = @imagecreatefromjpeg($sTempFileName);
                                break;
                            case IMAGETYPE_PNG:
                                $sExt = '.png';
                                // создание нового изображения из файла
                                $vImg = @imagecreatefrompng($sTempFileName);
                                break;
                            default:
                                @unlink($sTempFileName);
                                return;
                        }
                        
                        $vDstImg = @imagecreatetruecolor( $iWidth, $iHeight );
                        // скопируйте и измените размеры изображения
                        imagecopyresampled($vDstImg, $vImg, 0, 0, (int)$_POST['x1'], (int)$_POST['y1'], $iWidth, $iHeight, (int)$_POST['w'], (int)$_POST['h']);
                        // определите имя файла 
                        $sResultFileName = $sTempFileName . $sExt;
                        // готовое изображение
                        imagejpeg($vDstImg, $sResultFileName, $iJpgQuality);
                        @unlink($sTempFileName);
                        return $sResultFileName;
                    }
                }
            }
        }
    }
}
$sImage = uploadImageFile();
echo '<img src="'.$sImage.'" />';

Как видите – мы должны проверить размер изображения и формат на стороне сервера. В результате – мы получим двойную защиту (на стороне пользователя и сервера) от нежелательных файлов. Как только мы загрузили изображение (используя move_uploaded_file) – мы можем обрезать его (использование функций GD: imagecreatefromjpeg, imagecreatetruecolor и imagecopyresampled), и – сохранить результат в файл изображения, используя функцию 'imagejpeg'. Обратите внимание – что в результате мы получим маленькое изображение (которое имеет размер 200×200), таким образом, во время обрезки мы также изменяем размеры изображения. Я выбрал размер для всех входящих фотографий: 200×200.

ДЕМО Исходные файлы

Дополнительная информация

RATTING:
(1 Голосовать)

Медиа

Комментарии

#1 vladimir 02.11.2012 11:07
А куда добавляется изображение?
Сразу на сервер или в базу??
Цитировать
#2 vladimir 02.11.2012 11:19
не фига не чего не работает
Цитировать
#3 Weezy 02.11.2012 12:58
Файл помещается в папку на сервере. Перед тем как загружать нужно обрезать изображение, размеры обрезки можно изменить в коде
Цитировать