Я пытаюсь создать миниатюру для большего изображения. Я использую Jcrop, чтобы получить координаты обрезки, но не могу включить это в правильно обрезанное миниатюрное изображение. Я правильно настроил Jcrop, и он отправляет координаты xy вместе с размером поля, но я не могу понять, как это обрезать.
У меня есть путь к изображению на моем сервере, а также 4 координаты, а также ширина и высота квадратного поля, которое они создают (я заблокировал соотношение сторон 1: 1, так как мне нужны квадратные миниатюры). Затем я отправляю это через Ajax в свой сценарий обрезки PHP, но я не могу заставить его обрезать на основе того, что установлено.
Это то, что у меня есть до сих пор:
public function Crop($file, $crop) {
$height = $width = 180;
$ratio = $width / $height;
$pos = strrpos($file, '.');
$name = substr($file, 0, $pos);
$ext = strtolower(substr($file, $pos));
if( ! in_array($ext, array('.gif', '.jpg', '.jpeg', '.png'))) {
return 'INVALID_EXT';
}
// When loading the image we check to see if the first character in file is a slash, and if so remove it as the last character of root is a slash.
$src = ROOT . (in_array(substr($file, 0, 1), array('/', '\\')) ? substr($file, 1) : $file);
$srcRes = imagecreatefromstring(file_get_contents($src));
if( ! $srcRes) {
return 'INVALID_FILE';
}
$srcWidth = imagesx($srcRes);
$srcHeight = imagesy($srcRes);
$srcRatio = $srcWidth / $srcHeight;
$dstRes = imagecreatetruecolor($crop['w'], $crop['h']);
if($ext == '.gif') {
$dstBg = imagecolorallocate($dstRes, 0, 0, 0);
imagecolortransparent($dstRes, $dstBg);
} elseif($ext == '.png') {
$dstBg = imagecolorallocate($dstRes, 0, 0, 0);
imagecolortransparent($dstRes, $dstBg);
imagealphablending($dstRes, FALSE);
imagesavealpha($dstRes, TRUE);
}
$srcX = 0;
$srcY = 0;
if($srcRatio > $ratio) {
$tmpWidth = $srcHeight * $ratio;
$tmpHeight = $srcHeight;
$srcX = ($srcWidth - $tmpWidth) / 2;
$srcY = 0;
} else {
$tmpWidth = $srcWidth;
$tmpHeight = $srcWidth / $ratio;
$srcX = 0;
$srcY = ($srcHeight - $tmpHeight) / 2;
}
imagecopyresampled($dstRes, $srcRes, 0, 0, $crop['x'], $crop['y'], $crop['w'], $crop['h'], $tmpWidth, $tmpHeight);
$dst = ROOT . (in_array(substr($name, 0, 1), array('/', '\\')) ? substr($name, 1) : $name) . '-thumb' . $ext;
if($ext == '.gif') {
$try = imagegif($dstRes, $dst);
} elseif($ext == '.jpg' || $ext == '.jpeg') {
$try = imagejpeg($dstRes, $dst, 80);
} elseif($ext == '.png') {
$try = imagepng($newThumbImageResource, $dst);
}
if( ! $try) {
return 'CREATE_ERR';
}
return 'SUCCESS';
}
Я пытался изменить все что угодно в imagecopyresampled
, но не могу заставить его обрезаться в соответствии с тем, что отправляет Jcrop. Если я использую $srcWidth
и $srcHeight
, он сохраняет соотношение сторон исходного изображения и сжимает его в квадрат 180 пикселей. Но, похоже, он не изменяет его размер или не обрезает его в нужном месте.
Может кто-нибудь, пожалуйста, помогите мне решить, какие цифры я должен использовать где? Я бьюсь об это головой весь день.
ИЗМЕНИТЬ
Вот остальная часть кода. Сначала JavaScript, который запускает JCrop. Он запускается после загрузки файла Ajax для создания миниатюры этого изображения:
Это загрузка функции Ajax, которая в конце вызывает обрезку.
$(function () {
'use strict';
// Change this to the location of your server-side upload handler:
var url = '/eshop/library/ajax/ajax.file-upload.php';
var uploadDir = 'prodimages/';
$('.listing-image').fileupload({
url: url,
dataType: 'json',
autoUpload: true,
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
maxFileSize: 1000000, // 1 MB
// Enable image resizing, except for Android and Opera,
// which actually support image resizing, but fail to
// send Blob objects via XHR requests:
disableImageResize: /Android(?!.*Chrome)|Opera/
.test(window.navigator.userAgent),
previewMaxWidth: 120,
previewMaxHeight: 120,
previewCrop: true,
paramName: 'files[]',
formData: {uploadDir: uploadDir}
})/*.on('fileuploadprocessalways', function (e, data) {
var index = data.index;
var file = data.files[index];
$(this).html(file.preview);
})*/.on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('.listing-progress', this).css(
'width',
progress + '%'
);
}).on('fileuploaddone', function (e, data) {
var file = data.result.files[0];
var html = '<div class="listing-preview">\
<img src="' + file.thumbnailUrl + '" data-name="' + file.name + '">\
<div class="listing-preview-delete">Delete</div>\
</div>';
$(this).html(html).data('delete-url', file.deleteUrl).css('padding', 0);
Crop('/' + uploadDir + file.name, $(this).prop('id'));
});
});
Это отправляет сведения об урожае в PHP-скрипт выше через Ajax.
$(document).on('click', '.crop-btn', function() {
var data = {
file: $(this).data('src'),
crop: jcrop.tellSelect()
}
ShowLoadingById('crop-loading');
AjaxHandler('/eshop/library/ajax/ajax.product-crop-thumb.php', data, 'POST', true);
});
Окно кадрирования представляет собой лайтбокс, эта функция центрирует его по вертикали и изменяет размер изображения, если оно по вертикали больше доступного пространства.
function CentreCrop() {
var m = ($(window).height() - ($('.crop > div').height() + 60)) / 2;
$('.crop > div').css('margin-top', m);
if($('#crop-img').height() > $('.crop > div').height() - 30) {
$('#crop-img-container').height($('.crop > div').height() - 30);
}
}
Это начальная функция, которая сохраняет файл для обрезки и вызывает рабочий процесс, если он не запущен.
var toBeCropped = [];
var working = false;
function Crop(file, id) {
toBeCropped.push({path: file, id: id});
if( ! working) {
working = true;
CropWorker();
}
}
Это функция, которую я запускаю, когда обрезка завершена, чтобы уничтожить jcrop и очистить лайтбокс обрезки, готовый к обрезке следующего изображения.
function CropSuccess() {
$('.crop').fadeOut(250, function() {
jcrop.destroy();
$(this).html('');
CropWorker();
});
}
Это рабочий процесс, который фактически создает содержимое в лайтбоксе и инициирует jcrop.
function CropWorker() {
if(toBeCropped.length > 0) {
file = toBeCropped.shift();
html = '<div>\
<div id="crop-img-container" class="row-fluid">\
<img id="crop-img" src="' + file.path + '">\
</div>\
<div class="row-fluid">\
<div class="span3 offset9">\
<button class="span12 btn crop-btn" data-id="' + file.id + '" data-src="' + file.path + '">Create Thumb</button>\
</div>\
</div>\
<div class="row-fluid loading-screen" id="crop-loading">\
<div>\
<h4>Cropping...</h4>\
<img src="/img/loading.gif">\
</div>\
</div>\
</div>';
$('.crop').html(html);
$('.crop').fadeIn(250);
$('#crop-img').load(function() {
CentreCrop();
$('#crop-img').Jcrop({
aspectRatio: 1/1,
bgColor: 'black',
bgOpacity: 0.4,
boxWidth: $('#crop-img').width(), // Only just recently added boxWidth and height to see if that would fix it, no difference with or without.
boxHeight: $('#crop-img').height(),
//maxSize: [300,300],
minSize: [180,180]
}, function() {
jcrop = this;
jcrop.setSelect([0,0,180,180]);
});
});
} else {
working = false;
}
}
ОБНОВЛЕНИЕ
Часть проблемы, похоже, заключалась в изменении размера изображения. Я менял размер изображения, чтобы он соответствовал размеру экрана, хотя JCrop позаботится об этом за меня, но, похоже, вы должны сообщить JCrop исходные размеры изображения. Я добавил параметр истинного размера при инициализации JCrop, и, кажется, мы почти у цели.
Для небольших изображений, размером менее 1000 пикселей, обрезка работает отлично. Но для больших (1000 пикселей +) он создает черные изображения. Он не делает этого, когда я использую его с демо-скриптом JCrop, но единственная разница между ними заключается в том, что один выводит файл на экран, а другой сохраняет его. Я не вижу никакой другой разницы или не могу понять, почему это произошло.
ОБНОВЛЕНИЕ 2 Похоже, это влияет только на запуск кода через Ajax. Если я запускаю ту же самую функцию, просто публикуя на странице и запуская ее вверху, миниатюра каждый раз создается идеально, независимо от размера исходного изображения или размера поля, которое я рисую.