|
|
|
| Здравствуйте! Не хватает мозгов, или опыта. Думал.
Мне нужно загружать в папку фотографии (по одной), все только горизонтальной ориентации (проверку сделал).
Вопрос вот в чем! Фото должны быть 900 х 600 в результате. Если Источник например 1500 х 1200, тогда чтобы лишнее обрезалось и сжималось до 900 х 600, чтобы результат был без искажений.
Написал такой код, но он пропорционально сжимает фотографии, помогите доработать.
<?php
if (empty($_FILES['userfile']['name']))
{
die ("<h2>Не выбрано изображение</h2>");
}
else
{
$directory ='../../s/';//папка, куда будет загружаться начальная картинка и ее сжатая копия
$max_filesize = 8388607; //присваиваем переменной максимальное значение
if (filesize($_FILES['userfile']['tmp_name']) > $max_filesize)
exit ("<h2>Исходный файл превышает 8 Мб</h2>
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
if(preg_match('/[.](JPG)|(jpg)|(jpeg)|(JPEG)$/',$_FILES['userfile']['name']))
{
$original = $_FILES['userfile']['name'];
$istochnik = $_FILES['userfile']['tmp_name'];
$target = $directory . $original;
move_uploaded_file($istochnik, $target);
$rezultat_ne_obrezanniy = imagecreatefromjpeg($directory.$original);
//если оригинал был в формате jpg, то создаем изображение в этом же формате (необходимо для последующего сжатия)
//ОБРЕЗАНИЕ И СЖАТИЕ фото
$w = 900; $h = 600; //присваиваем макс значения ширины и высоты
// создаём исходное изображение на основе исходного файла и определяем его размеры
$w_src = imagesx($rezultat_ne_obrezanniy); //вычисляем ширину
$h_src = imagesy($rezultat_ne_obrezanniy); //вычисляем высоту изображения
if(($w_src<$w)&&($h_src<$h) || ($w_src<$h_src) )
{
$delfile = $directory.$original; //присваиваем переменной путь до оригинала
unlink ($delfile); //удаляем оригинал загруженного изображения
exit ("<h2 align=center>Исходное изображение слишком маленькое, загрузите фотографию чуть лучшего качества
<br>и(или)<br>фотография должна быть горизонтальной (альбомной) ориентации.</h2>
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
}
$koaf=$w/$h;//коэфициент сжатия уменьшенной копии
$src_koaf=$w_src/$h_src;//коэфициент сжатия оригинала
if($koaf<$src_koaf) $h=$w/$src_koaf;
else $w=$h*$src_koaf;
$rezultat = imagecreatetruecolor($w,$h); // создаём пустую пропорциональную картинку
imagecopyresampled($rezultat, $rezultat_ne_obrezanniy,0, 0, 0, 0, $w, $h, $w_src,$h_src);
$date=date('Y-m-d_H-i-s'); //вычисляем дату и время вплоть до секунд для названия
imagejpeg($rezultat, $directory.$date.".jpg"); //сохраняем изображение
$slide = $directory.$date.".jpg";
$delfile = $directory.$original; //присваиваем переменной путь до оригинала
unlink ($delfile); //удаляем оригинал загруженного изображения
}
else
{
//в случае несоответствия формата, выдаем соответствующее сообщение
exit ("<h2>Загружаемый файл должен иметь JPG формат.</h2>
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
}
}
?>
|
| |
|
|
|
|
|
|
|
для: Sarat
(18.09.2014 в 11:26)
| | Здесь вам уже говорилось, что делать так:
if(preg_match('/[.](JPG)|(jpg)|(jpeg)|(JPEG)$/',$_FILES['userfile']['name']))
это вредно для здоровья. Нельзя по такому условию загружать файлы, тем более те, которые можно достоверно проверить. Вы это либо мимо ушей, либо вам нужны баги на сервере и мусор. | |
|
|
|
|
|
|
|
для: Sarat
(18.09.2014 в 11:26)
| |
<?php
//процесс загрузки нужно начинать с проверки ошибки - $_FILES['userfile']['error'], если она равна 0, начинаем работать с файлом
if(!$_FILES['userfile']['error']) {
//empty($_FILES['userfile']['name']) - это бессмыслица, ибо файл уже загружен,
//и проверять выбран файл или нет нужно до загрузки, то есть не пуст ли массив $_FILES
//а вот отсекать лишнее в имени файла стоит
//отсекаем, если нужно оригинальное имя файла, вот так
$origin_name = basename($_FILES['userfile']['name']);
//если вы сохраняете только в JPEG формате, то почему запрещаете загрузку PNG?
//запретить нужно только GIF в вашем случае, но ни в коем случае не с помощью preg_match()
//подсунуть под валидным расширением можно что угодно
//поэтому, чтобы не писать много, можно проверять через массив к примеру
//затем, размер файла еще ничего не значит, гораздо важнее его разрешение,
//которое будет влиять на объем памяти предназначенный для его обработки
//а сохранив в JPEG размер уж никак не будет 8МБ
//узнаем параметры изображения
$size = getimagesize($_FILES['userfile']['tmp_name']);
if($size[2]==1) exit('Загружен GIF формат');
//размер доступной памяти (с округлением)
$mem = intval(ini_get('memory_limit')/100)*100; //в МБ, при доступных 128, выдаст 100, и т.д..
//размер памяти, который потребуется для создания ресурса из загруженного файла
$img_mem = $size[0] * $size[1] * 4;
//плюс требуется память под эскиз $w = 900; $h = 600;
$draft = $w * $h * 4;
//если памяти не хватит значит сообщаем что слишком большое прислали
if($draft + $img_mem > $mem) exit('Большое изображение');
//если хватает, вот тут загружаем сразу в ресурс загруженный временный файл
//без всякого предварительного его перемещения move_uploaded_file() в каталог, а потом еще и удаления
//а открывая ресурс сразу и проверяем - изображение ли это
//или же под расширением изображения подсунули мусор
else if($im = imagecreatefromstring(file_get_contents($_FILES['userfile']['tmp_name']))) {
//переменная $im - это открытый ресурс загруженного изображения
//вот с ним теперь можно делать все что требуется
} else exit('Это не изображение, это туфта');
} else echo $_FILES['userfile']['error']; //это номер ошибки
|
| |
|
|
|
|
|
|
|
для: confirm
(18.09.2014 в 13:39)
| | Спасибо! Наконец то понял и передал весь скрипт под проверку через массив с данными о графическом файле (это действительно правильнее).
Но основной вопрос этой темы остался открытым. Т.е.как дальше с $im ?
Ниже мой фрагмент, где я пропорционально сжимаю фотографию
...
else if($im = imagecreatefromstring(file_get_contents($_FILES['userfile']['tmp_name'])))
{
$koaf=$w/$h;//коэфициент сжатия уменьшенной копии
$src_koaf=$size[0]/$size[1];//коэфициент сжатия оригинала
if($koaf<$src_koaf) $h=$w/$src_koaf;
else $w=$h*$src_koaf;
$rezultat = imagecreatetruecolor($w,$h); // создаём пустую пропорциональную картинку
imagecopyresampled($rezultat, $im, 0, 0, 0, 0, $w, $h, $size[0] ,$size[1] );
$date=date('Y-m-d_H-i-s'); //вычисляем дату и время вплоть до секунд для названия
imagejpeg($rezultat, $directory.$date.".jpg"); //сохраняем изображение
}
else
exit ("<h2>Это НЕ изображение!</h2>
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
|
Как подрезать до 900 х 600 ? | |
|
|
|
|
|
|
|
для: Sarat
(18.09.2014 в 18:56)
| | Подрезать то не проблема, это собственно со школьной скамьи известно. Но давайте сперва так - Наконец то понял и передал весь скрипт под проверку... Возможно и так, но это не все. В вашем первоисточнике, а затем и я выполняю exit() в случае ошибки. А разве это правильно?
Когда нужен exit() - а) если предыдущая операция завершенная неудачей может привести к фатальным ошибкам при дальнейшей работе скрипта; б) когда явно вам напакостить хотят. Все, в первом приближении это так. А что у вас получается, и что получится, если вы скопируете логику работы кода мной представленным? А получится весьма плохо, ибо загрузка файла, это диалог с пользователем, и в этом диалоге не обязательно всегда виноват пользователь, и не обязательно он плохой мальчик.
Вот как можно представить код, что я написал, по ошибкам (с учетом добавления проверки есть ли передача файла):
<?
//проверяем, есть ли загрузка файла
if($_FILES) {
//загрузка была, проверяем
if(!$_FILES['userfile']['error']) {
//файл в закромах, начинается работа
//.......
if($size[2]==1) //загрузка не допустимого формата, возвращаем форму, но не exit()
//если формат в норме, продолжаем и проверяем по объему памяти на операцию
if($draft + $img_mem > $mem) //слишком большое разрешение у изображения, возвращаем форму, но не exit()
//а вот тут, о чем я не говорил, но ведь это же явно необходимо сделать,
//иначе какой смысл грузить попусту память,
//а именно - а что будет если загружено квадратное изображение 600х600?
//ведь вам нужна только альбомная ориентация, а значит здесь нужна проверка на это условие,
//и только, если это удовлетворяется, тогда можно нагружать память
//все инстанции прошли, осталась последняя проверка
else if($im = imagecreatefromstring(file_get_contents($_FILES['userfile']['tmp_name']))) {
//все ОК, работаем
} else exit('Вот тут да, выход, ибо это уже явная подстава на все 100%');
} else //здесь не обязательно виновен пользователь, надо пояснить причину, не exit(), продолжение диалога с формой
} else //здесь о чем-то мечтает пользователь и забыл загрузить, возвращаем форму с сообщением, не exit(), продолжение диалога с формой
|
И еще замечание - $date=date('Y-m-d_H-i-s'); //вычисляем дату и время вплоть до секунд для названия, можно, но все таки это не 100% гарантия того, что в это время будет работать процесс только одного клиента.
Сделайте нормальный диалог, а уж потом можно и подрезать. То есть должно быть так - зачем долго править бабочку перед зеркалом, торопясь на прием в высший свет, если задница голая? ) | |
|
|
|
|
|
|
|
для: Sarat
(18.09.2014 в 18:56)
| | а как определить, что у фотографии лишнее, и можно пустить в обрез? | |
|
|
|
|
|
|
|
для: Trianon
(19.09.2014 в 01:08)
| | Ну, если уши торчат, значит можно обрезать. :) | |
|
|
|
|
|
|
|
для: confirm
(19.09.2014 в 04:04)
| | Ну квадратная картинка пусть будет, а горизонтальную проверюял (если ширина меньше высоты, возвращай форму) . Общем пока буду подгонять код. | |
|
|
|
|
|
|
|
для: confirm
(19.09.2014 в 04:04)
| | Я понимаю что логически не правильно по поводу и без делать выход, но зачем же продолжать код, продолжать работу с картинкой. Может делать выход и возвращать форму? | |
|
|
|
|
|
|
|
для: Sarat
(19.09.2014 в 04:55)
| | Код не подгоняют, над ним думают. Проверили, если ширина меньше высоты, хорошо, но может же быть ситуация когда и альбомная ориентация, и квадрат, который стал допустим, но высота будет меньше 600. Это учтено?
Куда вы торопитесь? Быстрее обрезать?
Может делать выход и возвращать форму?
Это как? exit() - это и есть выход, то есть скрипт прекращает работу, и кто будет возвращать форму? Чтобы ее вернуть при выходе, значит аргументом этой функции и должна быть форма. Удобно это будет?
Мы в жизни делаем ошибки гораздо серьезнее, чем невнимательность и ошибочная загрузка не той картинки. Человек может ошибиться, значит нужен не выход в чистом виде - все бросили и гори оно огнем, а логическое продолжение диалога в случае ошибок. Как это нужно вам сделать вам виднее, ибо только вы видите структур своего кода - где и как формируется форма, где и при каких условиях отдается клиенту. От этого и зависит как поступать.
Если явно подсовывают туфту, то конечно exit(), но могут раз ошибиться, ну два раза, три это уже перебор, а значит тоже потенциальный кандидат на "пошел ...". В общем решайте это по своим условиям.
Но это не все, а имя под которым будет сохранен файл? Даже если микросекунды учитывать, это не будет полной гарантией. Но если каждый пользователь загружает только в свой каталог, то и минут хватит, но сколько же тогда каталогов надо...
А если у всех в кучу, вот тогда и микросекунды могут не помочь. Велика не велика вероятность одновременной записи двух или даже более клиентов, но она существует и пренебрегать ею нельзя. Вряд ли вы разрешаете загружать картинки всем кому непопадя, видимо только регистрированным клиентам. А если так, значит у них у каждого есть свой уникальный идентификатор. Вот к нему и надо привязывать имя сохраняемого файла, можно ID + time() в этом случае гарантировано не будет overwrite.
Но это еще не все. Из вашего условия, что если файл не загружался, то возврат, следует, что загрузка файла, это обязательное условие. Но загружается ли при этом формой и другие данные или нет? Если нет, тогда и вопросов нет, а если да, то тут опять таки могут возникать ситуации:
1) изображение загрузилось нормально и обработано, а POST данные содержат ошибку, форму надо возвращать, но как быть с изображением, опять заставлять его загружать вновь? Неуважуха к клиенту. Сохранять его, можно, но только, если этот файл не привязан к чему либо, кроме как к пользователю, ID которого уже известно.
2) также с загрузкой изображения все ОК, но изображение принадлежит новой теме/сообщению, которое отправляется формой вместе с изображением, и которое еще не добавлено в базу, а значит его ID мы не знаем, пока не запишем его, после чего можем привязать его к имени загруженного файла. Опять возникает вопрос, где держать в это время файл? Ситуация усугубляется опять таки, если есть ошибки в POST данных. Если сохранить файл в каталог временный, а потом "психануть и exit()"..., а что делать с "мертвым" файлом? То есть нужно самому собирать мусор. Такая ситуация может произойти и, если пользователь передумал, не стал править ошибки, ушел со страницы, а файл то на сервере...
То есть вот это все надо обдумать, все если и ситуации обсосать... Вот так в комплексе решать, а обрезать, так это математическая мелочь, всего лишь.
А ведь еще вопросы безопасности. Во-первых каталог в который грузятся изображения должен быть закрыт для запуска любых активных скриптов из него. Записывая в него файл, устанавливайте права - chmod(PATH, 0777), а после записи ограничивайте их - chmod(PATH, 0755). | |
|
|
|
|
|
|
|
для: confirm
(19.09.2014 в 07:56)
| | Парадокс, но тут работают сразу две пословицы "Зачем править долго бабочку, коли задница голая!" и "Чем дальше в лес, тем больше дров!"
На счет названия файла можно не заморачиваться, будет алминка, там (с вероятностью пол процента) максимум два человека одновременно будут добавлять (хотя можно к названию добавить случайное число).
Скажите, а возвращать форму то как? Если функцией header(), то сообщение об ошибки писать придется в файле формы, а это выходит за рамки Компонентного подхода. Дело в том что я самоучка, хочу разобраться как работают в веб-студиях, прочитал что шаблон будет редактировать дизайнер, который не разбираясь особо в пхп может случайно испортить код. Но я зделаю как вы советуете, потому что Компонент (файл, который мы здесь обсуждаем) не должен выводить ничего напрямую в браузер.
И кстати через header() не получается, выдает ошибку что в браузер уже пришла информация, хотя это не так, даже пробовал в первую строчку ставить header(), сразу после <?php и та же ошибка | |
|
|
|
|
|
|
|
для: Sarat
(21.09.2014 в 13:55)
| | "Чем дальше в лес, тем больше дров!"
Все как раз наоборот - если не продумать все, что касается загрузки, именования файлов закрепляемых за объектами (записями в базе), то в последствии такой загрузкой можно наломать столько дров, что придется плакать. А невыгодное, для задачи, построение диалога загрузки может породить лишние и никчемные операции.
На счет названия файла можно не заморачиваться, будет алминка, там (с вероятностью пол процента) максимум два человека одновременно будут добавлять (хотя можно к названию добавить случайное число).
Да-да, не заморачивайтесь, действительно пустяк, пол процента. Интересно как вы его вычислили только. А если эти пол процента и случаться, тогда что?
Я ведь вам ни в одной строке не написал - "Делайте так". Я пишу и показываю примеры как можно, но эти "можно" привязаны к условиям, которых я не знаю. Но, если ваши "пол процента" загружают файлы для записей уникальных, так на кой леший именовать файлы по текущему времени, а тем более "добавить случайное число"?
Вашим "пол процентам" по некоторым причинам потребуется удалить эти записи. Чтобы удалить и файлы им принадлежащие, их имена сформирование по времени, и бог весь какому случайному числу, обязательно придется хранить в базе у каждой записи владельца файла. Прежде чем удалить записи, сперва нужно сделать запрос и получить эти имена файлов, и лишь только затем можно будет удалять записи, а затем файлы.
Если добавляются файлы к записям и файлы именуются по id этих записей, то хранить их имена в базе не обязательно, а удалая к примеру записи с id 12, 232, 156, можно сразу удалять их, а функция glob() по маске найдет файлы необходимые для удаления. Вот и весь процесс.
Вы над этим думали? Мне собственно все равно, я вас же не заставляю делать так, как я пишу, что хотите, то и делайте. Ведь открытие ресурса вот так:
<?
$im = imagecreatefromstring(file_get_contents($_FILES['userfile']['tmp_name']))
|
без всякого шаманства с расширением и предварительного перемещения загруженного файла в каталог, я написал не потому, что так всегда надо поступать, а потому, что в вашем случае это гораздо выгоднее того, что вы писали. Более того, это позволяет убить сразу двух зайцев. Нужно лишь понимать, что сие действие означает.
Скажите, а возвращать форму то как? Если функцией header(), то сообщение об ошибки писать придется в файле формы
Функция header() никак не может возвратить форму, она вообще ничего не возвращает, эта функция передает только HTTP заголовки, поэтому у вас и возникает ошибка И кстати через header() не получается, выдает ошибку - заголовки должны передаваться до любого вывода в браузер, любой информации, вплоть до символа пробела, перевода строки, которые у вас могут оказаться случайно перед открывающим тегом <?php.
Форму возвращать должен php-сценарий, а не header(). А для этого структура кода как раз и должна быть написана с учетом диалога клиент<->сервер, и в простейшем виде быть такой:
Блок получения формы и проверки ее данных:
Если есть ошибки, то они присваиваются переменной $error.
Если нет ошибок, то данные сохраняются,
и можно делать переход на другую страницу, например финальную после приема формы.
Переход производится функцией header(),
а так как блок проверки расположен в самом начале файла,
когда еще не было никакого вывода в браузер,
то и переход чрез header() не будет вызывать ошибки.
Блок вывода формы пользователю:
Форма выводится по условиям -
а) если не было передачи POST-данных (массивы $_POST и $_FILES пусты), то есть первый запрос страницы
б) если есть ошибки в принятых данных - $error не пуста.
HTML-код формы может кроме нее содержать и блок вывода ошибок при их наличии.
А где же еще как кроме рядом с формой или же можно непосредственно у полей формы
показывать ошибки, которые допущены в форме? Отсылать их электронной почтой клиенту?
|
это выходит за рамки Компонентного подхода
Это понятие настолько резиновое, что можно очень долго об этом говорить. Но логика действий, структура кода написанная под эту логику никак не влияет на подход к организации компонентов сайта - пусть это будет и "плоская" структура, или компоненты, или модульность, или что-то иное. Уж поверьте этому, просто подумайте хорошенько.
А шаблон, и если есть дизайнер привлеченный к этому, так это совсем иная песня, и с логикой работы кода уж точно никак не должна быть связана.
Дело в том что я самоучка, хочу разобраться как работают в веб-студиях
А учимся мы все сами, и даже, если обучение в учебном заведении, все равно сами, преподаватели лишь разъясняют материал и помогают его усвоить. Хотим научится, получим знания, нет, так весь деканат не в состоянии будет что либо сделать. | |
|
|
|
|
|
|
|
для: confirm
(21.09.2014 в 15:53)
| | Проверка if ($_FILES) {нижепредставленный код} else {$error = "Не выбрали изображение"; } не работает, давайте пока ее оставим.
<?php
if(!$_FILES['userfile']['error']) //если ошибка равна 0, начинаем работать с файлом
{
$directory ='../s/';//папка, куда будет загружаться начальная картинка и ее сжатая копия
$w = 900; $h = 600; //задаем размеры результирующего изображения
$origin_name = basename($_FILES['userfile']['name']); //получаем только имя оригинала
$size = getimagesize($_FILES['userfile']['tmp_name']); //получаем массив $size[] с данными о графическом файле. Если значение $size[2] равно 1 это gif файл, 2 -> jpg(jpeg), 3 -> png, 6 -> bmp, 15 - > wbmp
if (!$size)//Если в переменную попала ложь (ПЕРВАЯ ПРОВЕРКА)
exit ("<h2>Это не изображение!</h2>Первая проверка не пройдена.
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
if($size[2]==1) {$error = "Загружен GIF формат. Загружаемый файл желательно должен иметь JPG формат.";}
else
{
if(($size[0]<$w) or ($size[1]<$h)) {$error = "Исходное изображение слишком мало!";}
else
{
//размер доступной памяти (с округлением)
$mem = intval(ini_get('memory_limit')/100)*100; //в МБ, при доступных 128, выдаст 100, и т.д.
$img_mem = $size[0] * $size[1] * 4; //размер памяти, который потребуется для создания ресурса из загруженного файла = ширина * высота * 4
$draft = $w * $h * 4; //плюс требуется память под эскиз
if($draft + $img_mem > $mem*1024*1024) {$error = "Большое изображение!";} //если памяти не хватит значит сообщаем что слишком большое прислали
//если хватает памяти, вот тут и загружаем сразу в ресурс загруженный временный файл
//без всякого предварительного его перемещения move_uploaded_file() в каталог, а потом еще и удаления
//а открывая ресурс сразу и проверяем - изображение ли это или же под расширением изображения подсунули мусор
else if($istochnik = imagecreatefromstring(file_get_contents($_FILES['userfile']['tmp_name'])))
{
//переменная $istochnik - это открытый ресурс загруженного изображения, с ним теперь можно делать все что требуется
$koaf=$w/$h;//коэфициент сжатия уменьшенной копии
$src_koaf=$size[0]/$size[1];//коэфициент сжатия оригинала
if($koaf<$src_koaf) $h=$w/$src_koaf;
else $w=$h*$src_koaf;
$rezultat = imagecreatetruecolor($w,$h); // создаём пустую пропорциональную картинку
imagecopyresampled($rezultat, $istochnik, 0, 0, 0, 0, $w, $h, $size[0] ,$size[1] );
$date=date('Y-m-d_H-i-s'); //вычисляем дату и время вплоть до секунд для названия
imagejpeg($rezultat, $directory.$date.".jpg", 100); //сохраняем изображение с наилучшим качеством
$error = "Фотография успешно загружена!";
}
else //(ВТОРАЯ ПРОВЕРКА)
exit ("<h2>Это НЕ изображение!</h2> Вторая проверка не пройдена.
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
}
}
}
else if ($_FILES['userfile']['error'] == 4) {$error = "Не выбрана фотография!";}
include('index.php');
?>
|
1)Файл с формой index.php имеет лишь одно поле для загрузки файла и ниже вывод $error.
2)Компонент и шаблон лежат в одном каталоге.
3)нужно просто загружать в папку фотографии лишнее обрезать и сжимать их до 900 на 600,
4) на счет того, как называть файлы, буду думать потом, когда буду делать панель для удаления этих файлов.
Вроде все условия | |
|
|
|
|
|
|
|
для: Sarat
(21.09.2014 в 19:58)
| | Проверка if ($_FILES) {нижепредставленный код} else {$error = "Не выбрали изображение"; } не работает, давайте пока ее оставим.
<?php
if($_FILES) {
header('Content-type: text/html; charset=utf-8');
echo '<pre>';
print_r($_FILES);
echo '</pre>';
//и сохраните сразу в переменных данные, с ним потом работать будет удобнее, чем обращаться к массиву
list($bW, $bH, $type) = getimagesize($_FILES['fl']['tmp_name']);
echo 'Тип загруженного изображения: ' . $type . '<br>
Ширина загруженного изображения: ' . $bW . '<br>
Высота загруженного изображения: ' . $bH;
}
?>
<form method="post" enctype="multipart/form-data">
<input type="file" name="fl" />
<button>GO</button>
</form>
|
Работает? Да и с чего бы оно не работало, если нет отправки файла, то массив $_FILES пуст, то есть проверка его на условие истинности вернет 0. А не пустой массив вернет 1.
"Загружен GIF формат. Загружаемый файл желательно должен иметь JPG формат."
Почему желательно, что значит возможно и GIF формат? Тут уж по логике должна быть однозначность, если возвращаете, значит только JPEG. Но а чем провинился PNG, ведь это тоже полноцветное изображение? Вы потом сохраните его в формате JPEG, какие проблемы?
А это,
<?
exit ("<h2>Это не изображение!</h2>Первая проверка не пройдена.
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
|
для пользователя хуже и не придумать. А если плохой мальчик, так и совсем не нужно, просто выход и все.
<? imagejpeg($rezultat, $directory.$date.".jpg", 100); //сохраняем изображение с наилучшим качеством
|
Это плохо, да и совсем не нужно, уж точно не для печати вы их храните, а сохранив с качеством даже 80, вряд ли заметите на глаз разницу, но вот размер уже будет гораздо меньше, и даже качество 90 даст по размеру выигрыш.
В остальном мне, как я уже сказал, все равно, вы же не для меня это пишите. ) Просто так не подходят к задаче решаемой. Как бы это вам объяснить, более доходчиво.
Есть описанные типы данных, с которыми вы будете работать, это строки, числа, числа с плавающей точкой, загружаемые файлы разных типов, и никак не может быть, чтобы форма передавала данные:
Материал = лес
Тип = горбыль
как и подобает, строковые значения, и вдруг действительно начала гнать на сервер натуральный лес, и натурально горбыль. А зная, что такое не возможно, зная какие типы данных мы можем ожидать, мы можем написать единственный, универсальный для любого количества форм код, который будет обрабатывать данные и отправлять пользователю ошибки, если они есть, и будет это делать автоматически, и эту проверку не надо прописывать для каждой принимаемой формы, нам остается только выполнять конечный результат - помещать данные на свои места.
Никогда не пытайтесь писать код для одного случая, потом почти на 100% тоже самое для другого случая и так далее. Вот почему надо основательно продумывать всю структуру кода, чтобы она послужила основой или сразу пишется как основа чего-то универсального.
PS. Кстати, у вас не видно обрезки, о которой вы все беспокоились, у вас просто уменьшение изображения. | |
|
|
|
|
|
|
|
для: confirm
(21.09.2014 в 20:52)
| | Вот именно нет обрезки)) как лучше обрезать?
А сохраяю я сейчас 95 качеством, файл в 2 раза меньше чем 100 процентный, а разницы не видно. | |
|
|
|
|
|
|
|
для: Sarat
(22.09.2014 в 12:06)
| | Сохраните с качеством по умолчанию (75), и тоже вряд ли заметите разницу.
А как обрезать? Если у вас есть изображение, которое после уменьшения рассчитанного по его высоте приобрело размеры 1200 х 600, а вам нужно только 900 х 600?
Если взять из него начиная слева, то значит аргументу $src_x функции imagecopyresampled() нужно передать значение 0 (обрезается справа), если же нужно обрезать слева и справа, значит нужно отрезок 900 отцентрировать на отрезке 1200:
(1200 - 600) / 2 = 150
и предать аргументу $src_x полученное значение. Аргумент $src_w при этом всегда имеет значение требуемое - 900.
Это из курса школьной арифметики ) | |
|
|
|
|
|
|
|
для: confirm
(22.09.2014 в 12:52)
| | Альберт Эйнштейн тоже не очень учился в школе)) | |
|
|
|
|
|
|
|
для: Sarat
(22.09.2014 в 14:16)
| | Могу вас уверить, что таблицу умножения он тем не менее знал. ;)
Вопрос как обрезать ведь по сути не принадлежит непосредственно программированию, это обычная житейская ситуация. Надо вам из метровой доски вырезать кусок размером 60 см из центральной части, что вы бы делали? Естественно отняли бы из одного метра (100 см) 60 см, разделил бы полученное пополам, узнав таким образом сколько слева и справа останется. Ну а то, что для помещения отрезка 60 см на метре, достаточно отметить отступ слева, не оперируя что там справа будет, это по самой логике понятно.
Вот где в этом процессе программирование? Ваша беда в том, как начинающего, что вы воспринимаете программирование как сугубо механическое шевеление мозгами, которое основано исключительно на описании языка программирования. А это не так. Думать надо "человеческими образами", воплощая их в байты кода программного, в чем как раз и состоит задача языка программирования.
Вы должны работать как режиссер снимающий картину. Чтобы ее снять нужен сценарий, который описывает не только фабулу, но и флору с фауной, в которой и развивается фабула. Затем представив все мезансцены, переходите к конкретным их героям, и только на этом этапе можете решить, что будет более раскрывать трагичность повествования, фраза героя - "Умираю, но не сдаюсь!" или же - "Ой, бля, опять убили :("
Ваши ответы на мои вопросы позволяют сделать мне заключение - вы, как режиссер, не зная героев, не видя мезанцен, фабулы, и не имея сценария, сразу пригласили на главную роль популярнейшего актера, и теперь решаете что ему сказать, в то время как остальная съемочная группа в замешательстве, ибо даже о декорациях нужных она не имеет ни малейшего представления.
Знаете о "законах подлости"? Возвращаясь к вашему отношению как именовать файлы - не стоит заморочки, потому как вероятность мала, можно привести один из них:
Закон Мэрфи - Даже если непpиятность не может случиться, она случается.
Не знаю существует ли такой, если нет, значит будет моим подобным законом - Чем больше программист уверен, что событие не произойдет, тем больше вероятность, что оно наступит.
Что значит обрезать фото программно? Это значит резать его вслепую. Вам ранее Trianon вопрос задавал по этому поводу. А ведь, если обрезать 10рх, то может и не так страшно, но а если вырезается приличная часть да еще по центру, будет ли результат всегда ожидаемый?
Вы пишите административный раздел, а это значит, что многие вопросы, которые приходится решать для страниц пользователей, отпадают. Администратор может работать даже под конкретным браузером, не умрет от этого. Поэтому не проблематично иметь администратору браузер с поддержкой HTML5, которая позволит на стороне клиента перед загрузкой узнать и тип загружаемого файла, и допустимые размеры, и делать обрезку изображения визуально. Можно даже сразу и размер его уменьшить, и готовое оправить на сервер, серверу только проверить условия останется и все.
Для этого требуется Javascript, собственно без него нормальный административный раздел представить сложно. А под него есть готовые плагины обрезания изображения, вернее они не вырезают ничего, они просто накладывают на фото рамку, которой выбирается нужная часть на фото, а серверу оправляются координаты, по которым и вырезается нужное из загруженного. HTML5 просто позволит это сделать без предварительной загрузки файла на сервер.
В общем надо более масштабно представлять все, находить для этого необходимые инструменты, а их и готовых полно. | |
|
|
|
|
|
|
|
для: confirm
(19.09.2014 в 04:04)
| | как обрезать уши, я уже голову сломал! Только вычислил сколько обрезать!
$k_ist=$w/$h;//коэфициент сжатия уменьшенной копии
$k_orig=$size[0]/$size[1];//коэфициент сжатия оригинала
if($k_ist>$k_orig) $h=$w/$k_orig;
else $w=$h*$k_orig;
$rezultat = imagecreatetruecolor($w,$h); // создаём пустую пропорциональную картинку
imagecopyresampled($rezultat, $istochnik, 0, 0, 0, 0, $w, $h, $size[0] ,$size[1] );
$x_rez = ($w - 900)/2; $y_rez = ($h - 600)/2; //вычисляем сколько нужно отрезать (с каких координат накладывать изображение)
|
Здесь в imagecopyresampled не получается вставить координаты $x_rez и $y_rez, какую функцию вызвать для обрезки фото, что второй раз обращаться к imagecopyresampled уже с пропорциональным результатом? | |
|
|
|
|
|
|
|
для: Sarat
(24.09.2014 в 11:32)
| | А что это вы занялись вычислением по обрезке после того как выполнили изменение размера?
После того как высчитали какая будет ширина после сжатия:
$k_orig=$size[0]/$size[1];//коэфициент сжатия оригинала
if($k_ist>$k_orig) $h=$w/$k_orig;
else $w=$h*$k_orig;
и цетрируйте отрезок 900 на ней, получая Х-координату с которой нужно взять отрезок 900 с оригинала, и только потом imagecopyresampled().
Еще раз мысленно отпилите из метровой доски отрезок 60 см с ее центральной части. | |
|
|
|
|
|
|
|
для: confirm
(24.09.2014 в 11:45)
| | imagecopyresampled нужно дать выполнить свою роль, функция уменьшает пропорционально картинку, если в ней выставлять координаты, то картинка будет искажена . Разве возможно в ней лишнее обрезать? | |
|
|
|
|
|
|
|
для: Sarat
(24.09.2014 в 12:03)
| | Ну-ка еще раз внимательно читаем, что делает функция imagecopyresampled. Если вам надо выпилить часть из доски, вы что сперва выпилите, а лишь затем начнете вычислять сколько отложить от начала доски чтобы получилось по центру? Ну абсурд же, не так ли? А почему в программировании должно быть абсурдно? | |
|
|
|
|
|
|
|
для: confirm
(24.09.2014 в 12:14)
| | Фу, ну вроде дошло, если это школьная программа, то как минимум для одаренных детей!
<?php
else if($istochnik = imagecreatefromstring(file_get_contents($_FILES['userfile']['tmp_name'])))
{
$k_rez=$w/$h;//коэфициент сжатия уменьшенной копии
$k_orig=$size[0]/$size[1];//коэфициент сжатия оригинала
if($k_rez>$k_orig) $h=$w/$k_orig;
else $w=$h*$k_orig;
$otn_w = $size[0]/$w; $otn_h = $size[1]/$h; //вычисляем оношение ширин и высот для координат imagecopyresampled
$x_rez = (($w - 900)/2)*$otn_w; $y_rez = (($h - 600)/2)*$otn_h; //вычисляем сколько нужно отрезать (с каких координат накладывать изображение)
$rezultat = imagecreatetruecolor(900,600);
imagecopyresampled($rezultat, $istochnik, 0 , 0 , $x_rez , $y_rez , $w, $h, $size[0] ,$size[1] );
$date=date('Y-m-d_H-i-s'); //вычисляем дату и время вплоть до секунд для названия
imagejpeg($rezultat, $directory.$date.".jpg",95); //сохраняем изображение с оптимальным кач-м
imagedestroy ($rezultat); imagedestroy ($istochnik); //освобождаем память
$error = "Фотография успешно загружена!";
}
?>
|
Кстати, мы забыли удалить в прошлых версиях imagedestroy ($rezultat); imagedestroy ($istochnik); | |
|
|
|
|
|
|
|
для: Sarat
(24.09.2014 в 12:43)
| | Да... Кто читать будет?
imagecopyresampled() копирует прямоугольную часть одного изображения на другое изображение, интерполируя значения пикселов таким образом, чтобы уменьшение размера изображения не уменьшало его четкости.
Приучите себя сразу - в именованиях переменных не использовать жаргона, типа _rez, потому как это rezultat. Результат по английски, это - result. Но его сокращать до res и использовать в данном случае не удобно, ибо это сокращение может говорить, что речь идет о неком ресурсе - resource. Вы оперируете в данном случае координатой, а по английски это - coordinate, а значит не мудрите и $y_coord, в таком случае.
Исходное изображение, это большое изображение, а значит его размеры можно описывать используя имена переменных в верхнем регистре, типа: $sW, $sH, а для копии малой, в нижнем: $sw, $sh. Или имя источника изображения (большое), это - sourse (источник), а приемник его копируемой части, это - destination (получатель), и тогда:
<?php
//для проверки условий получаем:
list($src_W, $src_H, $type) = getimagesize($_FILES['userfile']['tmp_name']);
$dst_w = 900;//ширина приемника
$dst_h = 600; //высота приемника
//отношение сторон, и больше ничего не надо из вашей арифметики,
//у вас фиксированное условие
$ratio = $src_w / $src_w;
//сегмент ширины на исходном изображении который будет копироваться
$src_segment = $src_H * $ratio;
//по полученным данным проверяем, и если ОК
if($src = imagecreatefromstring(file_get_contents($_FILES['userfile']['tmp_name']))) {
//приемник
$dst = imagecreatetruecolor($dst_w, $dst_h);
//координата x с которой будет начинаться сегмент
$src_x = ($src_W - $src_segment) / 2;
//забираем из большого часть, купируем ее, уменьшая
imagecopyresampled($dst, $src, 0, 0, $src_x, 0, $dst_W, $dst_H, $src_segment, $src_h);
//сохраняем
imagejpeg($dst, 'image_name.jpg');
//высвобождаем ресурсы
imagedestroy($src);
imagedestroy($dst);
}
|
А то каша невообразимая, не понять о каких тараканах идет речь.
Вам нужно чтобы высота результат было 600, так на кой леший тогда нужно:
$y_rez = ($h - 600)/2; ?
Я же вам показывал как на результате отложить отрезок, но вы то копировать будет из большого, и на нем нужно брать отрезок, что же вы в лоб просто копируете совсем не думая.
PS. Для всяких аргументов, типа так именую потому, что лучше понимаю или удобнее - зато другим не понятно, а если не понятно нормального английского, то тогда уж пишите так:
<?php
list($ширина_источника, $высота_источника, $тип_источника) = getimagesize('test.jpg');
$ширина_приемника = 900;
$высота_приемника = 600;
$отношение_сторон = $ширина_приемника / $высота_приемника;
$ширина_копируемого_сегмента_источника = $высота_источника * $отношение_сторон;
if($ширина_копируемого_сегмента_источника < $ширина_источника) {
if($источник = imagecreatefromstring(file_get_contents('test.jpg'))) {
$приемник = imagecreatetruecolor($ширина_приемника, $высота_приемника);
$горизонтальная_координата_источника = ($ширина_источника - $ширина_копируемого_сегмента_источника ) / 2;
imagecopyresampled($приемник,
$источник,
0,
0,
$горизонтальная_координата_источника,
0,
$ширина_приемника,
$высота_приемника,
$ширина_копируемого_сегмента_источника,
$высота_источника);
imagejpeg($приемник, 'очень_очень_случайное_число.jpg');
imagedestroy($источник);
imagedestroy($приемник);
}
}
|
и вам понятно, и другим тоже. Вот только зачем... | |
|
|
|
|
|
|
|
для: confirm
(24.09.2014 в 13:38)
| | Завтра попробую все это запихать в функцию.
Вам нужно чтобы высота результат было 600, так на кой леший тогда нужно:
$y_rez = ($h - 600)/2; ?
- я хотел сделать скрипт более универсальным, чтобы и с вертикальной фотографии вырезалась середина по вертикали высотой 600
При вызове этой функции, хочу, чтобы взависимости от заданных аргументов, она либо пропорционально сжимала до заданных ширина Х высота (это могут быть как минимально требуемые, так и максимальные размеры), Либо прописать в аргументах фиксированный размер и пустить картину под подрезку (как у нас тут), при этом и вертикальной ориентацией не брезговать. Уж не до такой степени наш пользователь , добавляющий фото бестолковый, а универсальности много добавит скрипту.
Ну а если невозможно будет сделать это в одной функции, придётся делать две. | |
|
|
|
|
|
|
|
для: Sarat
(24.09.2014 в 20:28)
| | я хотел сделать скрипт более универсальным, чтобы и с вертикальной фотографии вырезалась середина по вертикали высотой 600
Нет, это уже другое понятие, это не обрезка уже будет, а вырезка области. Такое тем более в слепую лучше не делать.
Если же вы все таки в это понятие вкладываете обрезать и слева, и справа, то вы поставите свой скрипт в замешательство - посчитать то он посчитает, а вот что делать ему не поймет. Нужно определять по ориентации изображения какой сегмент брать - ширины или высоты, и какая координата смещается - горизонтальная или вертикальная.
Универсальный скрипт для загрузки фото и не только уменьшить пропорционально, обрезать и уменьшить, вырезать и уменьшить, уменьшение/обрезка/вырезка плюс наложение и прочие эффекты, написать можно. Все это будет одна функция, кроме описания причины ошибок, это должна быть отдельная функция, так как ее запрос будет требоваться еще до операции над изображением. | |
|
|
|
|
|
|
|
для: confirm
(18.09.2014 в 13:39)
| | > //размер памяти, который потребуется для создания ресурса из загруженного файла
> $img_mem = $size[0] * $size[1] * 4;
А тут точно множитель 4, а не 5 ?
Помнится мне, раньше движок, помимо полноцветного массива, создавал байтовый, под палитровую картинку не иначе. И с учетом этого в коэффициенте аппетита памяти жила твердая пятерка.
Сейчас не так? | |
|
|
|
|
|
|
|
для: Trianon
(25.09.2014 в 14:55)
| | Создается ресурс, в котором по байту на канал цвета плюс бай на альфа канал. В случае если цвет это не 24-бита, а более, значит тогда и ресурс будет больше. Конечно же это надо проверять и учитывать, просто опущено для простоты, ибо такие изображения не так часты. | |
|
|
|
|
|
|
|
для: confirm
(25.09.2014 в 15:17)
| | Я о другом спросил.
пятикратное (к числу пикселей) выделение памяти функциями imagecreate я наблюдал, давно, правда - лет 7 назад - в ходе практической проверки на одной из версий php.
Четверка в формуле - из вполне логичных теоретических соображений, или подтверждалась экспериментом? | |
|
|
|
|
|
|
|
для: Trianon
(25.09.2014 в 20:47)
| | Ну так функции GD возвращающие информацию о цвете точки ресурса возвращают четыре 8-битных значения - R, G, B, A. Других пока не видел в ней. Так что более глубокий цвет, я так понимаю, для GD из разряда фантастики. | |
|
|
|
|
|
|
|
для: confirm
(25.09.2014 в 22:03)
| | я не говорю, что цвет более глубокий.
Цвет обычный.
Просто там, где GD должно было хавать 200 (к примеру) мегабайт,
оно хавало 250. И т.п.
Наблюдалось в отклике memory_get_usage на крупных, естественно, изображениях.
Впечатление такое, что библиотека резервирует лишний блок памяти просто на всякий случай. Потом его отдает вместе с основным. | |
|
|
|
|
|
|
|
для: Trianon
(25.09.2014 в 22:09)
| | А вот о чем. Понятно, что память будет требоваться не только под сам ресурс, ну это не десятки мегабайт, и чтобы такой объем GD требовала не замечал.
Тут скорее другое, например при создании эффектов, есть те, ресурсы под который явно не указываются, но они будут созданы, следовательно и память "молча" будет занята, но ведь она потребуется только, если воспользоваться подобной операцией, на всякий случай сразу память подгребать не будет то библиотека. | |
|
|
|
|
|
|
|
для: confirm
(25.09.2014 в 22:29)
| |
<?php
$h = 160; $v = 240;
echo "<style>
table {border-collapse: collapse;}
td,th { border: 1px solid #666666; align: center; }
</style><table>";
$j = $im = imagecreate(1, 1);
$k = 0; $t = 0; $p =$q =$r = 0;
$a = memory_get_usage();
echo '<tr><td>$h*$v</td><td>$h*$v*4</td><td>$h*$v*5</td><td>memory</td></tr>';
for($k = 0; $k < 10; $k++, $t = $h, $h = $v, $v = $t*2)
{
$im = imagecreatetruecolor($h, $v);
$t = memory_get_usage();
$im = null;
$p = $h*$v*4; $q = $h*$v*5; $r = $t - $a;
echo "\r\n<tr><td>$h*$v</td><td>$p</td><td>$q</td><td>$r</td></tr>";
}
echo "</table>";
?>
|
| |
|
|
|
|
|
|
|
для: Trianon
(26.09.2014 в 00:55)
| |
<?
$h = 160; $v = 240;
echo "<table border=1>";
$im = imagecreate(1, 1);
imagedestroy($im);
$k = 0; $t = 0; $p =$q =$r = 0;
$a = memory_get_usage();
echo '<tr><td>$h*$v</td><td>$h*$v*4</td><td>$h*$v*5</td><td>memory</td></tr>';
for($k = 0; $k < 10; $k++, $t = $h, $h = $v, $v = $t*2)
{
$im = imagecreatetruecolor($h, $v);
$t = memory_get_usage();
imagedestroy($im);
$p = $h*$v*4; $q = $h*$v*5; $r = $t - $a;
echo "\r\n<tr><td>$h*$v</td><td>$p</td><td>$q</td><td>$r</td></tr>";
}
echo "</table>";
|
И уже другая картина, да и посчитать точно не возможно. Собственно вы умножаете на 5, чтобы подогнать под ответ. ) Достаточно резервировать память под подобные операции.
PS. Вообще-то память на изображение можно считать сразу по параметрам его полученным от getimagesize():
ширина * высота * бит на канал * число каналов / 8
И кто-то резервирует сверху 0.5, кто-то больше. | |
|
|
|
|
|
|
|
для: confirm
(26.09.2014 в 01:05)
| | Ок. не буду умножать на пять.
Вот так - аргумент, или все еще фэйк?
<?php
$h = 160; $v = 240;
echo "<style>
table {border-collapse: collapse;}
td,th { border: 1px solid #0; text-align: right; }
</style><table>";
$im = imagecreate(1, 1);
imagedestroy($im);
$k = 0; $t = 0; $p =$q =$r = 0;
$a = memory_get_usage();
echo '<tr><td>$h*$v</td><td>memory</td><td>factor<td>error,%</td></tr>';
for($k = 0; $k < 12; $k++, $t = $h, $h = $v, $v = $t*2)
{
$im = imagecreatetruecolor($h, $v);
$t = memory_get_usage();
imagedestroy($im);
$r = $v*$h; // число пикселей
$t -= $a; // число байт
$p = $t /= $r; //байт на пиксель
$q = $p - round($p); // ошибка абс.
$q /= $t; // ошибка отн.
$q = number_format($q*100, 2);
$p = number_format($p, 2);
echo "\r\n<tr><td>$h*$v</td><td>$r</td><td>$p</td><td>$q</td></tr>";
}
echo "</table>";
?>
|
PS. Вообще-то $im = null от imagedestroy($im) не отличается почти ничем.
И первую картинку я тоже оставил не просто так. Хотя это и мелочи.
Собственно, вопрос-то изначальный - очень простой.
На какую память можно рассчитывать, открывая картинку? | |
|
|
|
|
|
|
|
для: confirm
(26.09.2014 в 01:05)
| | честно говоря, спорить надоело.
Как говорится, хочешь что-то узнать достоверно - сделай сам.
php-5.6.0.tar.gz/php-5.6.0/ext/gd/libgd/gd.c строки 175...230
Жирным я показал, почему множить следует на пятерку. вернее на размер int + 1
Интересно, как оно выглядит на 64-битовых системах... Там небось вообще девятка выползет.
gdImagePtr gdImageCreateTrueColor (int sx, int sy)
{
int i;
gdImagePtr im;
if (overflow2(sx, sy)) {
return NULL;
}
if (overflow2(sizeof(unsigned char *), sy)) {
return NULL;
}
if (overflow2(sizeof(int), sx)) {
return NULL;
}
im = (gdImage *) gdMalloc(sizeof(gdImage));
memset(im, 0, sizeof(gdImage));
im->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
im->AA_opacity = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
im->polyInts = 0;
im->polyAllocated = 0;
im->brush = 0;
im->tile = 0;
im->style = 0;
for (i = 0; i < sy; i++) {
im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int));
im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
}
im->sx = sx;
im->sy = sy;
im->transparent = (-1);
im->interlace = 0;
im->trueColor = 1;
/* 2.0.2: alpha blending is now on by default, and saving of alpha is
* off by default. This allows font antialiasing to work as expected
* on the first try in JPEGs -- quite important -- and also allows
* for smaller PNGs when saving of alpha channel is not really
* desired, which it usually isn't!
*/
im->saveAlphaFlag = 0;
im->alphaBlendingFlag = 1;
im->thick = 1;
im->AA = 0;
im->AA_polygon = 0;
im->cx1 = 0;
im->cy1 = 0;
im->cx2 = im->sx - 1;
im->cy2 = im->sy - 1;
im->interpolation = NULL;
im->interpolation_id = GD_BILINEAR_FIXED;
return im;
}
|
PS. Sarat, извините, что устроил тут оффтопик.
Просто сколько памяти резервировать под картинку - вопрос более чем практический. | |
|
|
|
|
|
|
|
для: Trianon
(26.09.2014 в 10:33)
| | Причем тут все таки 5?
Изображение характеризуется глубиной цвета, то есть бит на канал, числом каналов, наличием эскиза и метаданных. GD не тот инструмент, который бы учитывал во всех своих инструментах эти тонкости. Даже getimagesize должна возвращать число каналов 3 для RGB картинок и 4 для CMYK, но она вполне может глючить с PNG типом вообще ничего не возвращая.
А что касается практической точки зрения, то проверка на доступную память, это чтобы не пролететь, не более. А для этого достаточно резервировать память. Рассчитывать ее впритык, не знаю, я лично не представляю сервиса назначение которого, это изображения с очень большим разрешением гонять под GD, максимум это разрешение цифровых мыльниц, это где-то 30-50 МБ на фото надо.
Другое дело сервис для профессионалов от фото, ну вряд ли GD подходит для этого. | |
|
|
|
|
|
|
|
для: confirm
(26.09.2014 в 13:11)
| | >Причем тут все таки 5?
так а я уже не настаиваю на пятерке, если Вы не заметили.
Но то, что не четверка - факт. Четверка взята из Вашего кода.
Я имею в виду php-код в Вашем комментарии (18.09.2014 в 13:39) в этой теме.
>Изображение характеризуется глубиной цвета, то есть бит на канал, числом каналов, наличием эскиза и метаданных. GD не тот инструмент, который бы учитывал во всех своих инструментах эти тонкости. Даже getimagesize должна возвращать число каналов 3 для RGB картинок и 4 для CMYK, но она вполне может глючить с PNG типом вообще ничего не возвращая.
>
кто б спорил. только все это, хотя и верно, но в данном случае - малость сбоку.
>А что касается практической точки зрения, то проверка на доступную память, это чтобы не пролететь, не более.
ну да. Только чтоб не пролететь, умножать надо в том коде на пятерку (в 32битной сборке)
А в 64битной - на девятку.
пруф - код gd extension , непосредственно резервирующий память - я только что привел. | |
|
|
|
|
|
|
|
для: Trianon
(26.09.2014 в 14:09)
| | Узнавать надо так:
$mem = round((ширина * высота * бит на канал * число каналов / 8 + выравнивание по байту или мегабайту) * 1.65);
если уж на то пошло, а не какую-то эмпирически вычисленную 5 или 9. Проблема только в том, что "подручный" инструмент РНР для этого не всегда возвращает корректное, хотя, если уж так хочется, то можно написать и свой собственный. | |
|
|
|
|
|
|
|
для: confirm
(26.09.2014 в 14:42)
| | >если уж на то пошло, а не какую-то эмпирически вычисленную 5 или 9.
о боги... твою налево, для кого я там жирным выделил...
Confirm, Вы код смотрели? какое число каналов? какое бит на канал?
вся эмпирика закончилась, когда я привел (26.09.2014 в 10:33) выдержку из актуального на данный момент source'а графического расширения. Действующий код: sx, sy - размеры изображения.
for (i = 0; i < sy; i++) {
im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int));
im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
}
|
И извините, в то, что Вы не понимаете, что этот код означает, я не поверю.
А откуда Вы взяли свой 1.65? :) | |
|
|
|
|
|
|
|
для: Trianon
(26.09.2014 в 15:14)
| | Я не понимаю другого, сути этого разговора. Доказать, что библиотеке похер что из себя представляет изображение, то есть его параметры или что?
1.65, это резервирование. Еще раз говорю, все ваши расчеты на впритык ну может педанту и потребуются, а на практике достаточно зарезервировать память, ибо есть функции GD, в которых она будет без всякого уведомления увеличивать ее потребление, кроме уже зарезервированной под открытый ресурс. | |
|
|
|
|
|
|
|
для: confirm
(26.09.2014 в 15:50)
| | >Я не понимаю другого, сути этого разговора. Доказать, что библиотеке похер что из себя представляет изображение, то есть его параметры или что?
Да нет, вобщем-то... какой смысл доказывать что-то про поведение открытого кода..
Оно такое, каким является, а не такое, как про него кто-то что-то думает.
>1.65, это резервирование. Еще раз говорю, все ваши расчеты на впритык ну может педанту и потребуются, а на практике достаточно зарезервировать память, ибо есть функции GD, в которых она будет без всякого уведомления увеличивать ее потребление, кроме уже зарезервированной под открытый ресурс.
Это не мои, это Ваши расчеты. Я их всего лишь поправил слегка.
Вернее, изначально я лишь спросил, не ошиблись ли Вы случайно?
Спросил не подколки ради, а потому, что сам довольно давно в предмете пристально не копался, а он - предмет - за те 5 лет, что я в него не лез, мог оказаться и исправлен.
Потом понял, что истина Вас не беспокоит, и ответил на свой вопрос сам.
Сперва эмпирически, а потом - строго по коду.
Что до идеи просто докинуть 65%, не опираясь на логику.
Да, так можно.
Хотя при 64битной сборке на платформе, на которой int займет 64/8 = 8 байт, и выделенный библиотекой размер окажется кратен 9 - не спасет :) | |
|
|
|
|
|
|
|
для: Trianon
(26.09.2014 в 16:10)
| | Дошло, суть вопроса - почему библиотека использует более чем.
Не знаю, возможно из расчета на будущее, когда она будет способна работать и с большей глубиной цвета. Но в настоящее время она оперирует только 8-ю битами на цвет, тремя каналами плюс альфа каналом и все. Например, CMYK jpeg она может вообще не открыть.
Ну думаю понятно и то, что открывая ресурс я должен ориентироваться на эти параметра изображения, а если уж "подстраиваться" под библиотеку, то нужно не умножать на 5 или 9, а корректировать не 1.65, а на более реальную цифру. Иначе я не понимаю логики - плюнуть на основные параметры изображения, не рассчитывая по ним необходимую память, а вместо этого сперва открыть ресурс, узнать с помощью memory_get_usage реальное, и только потом принять решение. Поэтому вопросы к чему бит на ресурс, число каналов ... меня удивили. | |
|
|
|
|
|
|
|
для: confirm
(26.09.2014 в 16:21)
| | ну а что делать - авторы библиотеки решили, что вся эта экономия им нафиг не срослась. Предположения о запасах на будущее в высшей степени сомнительны. Все куда прагматичнее.
Удобно хранить каждый пиксель в типе int (и вероятно, альфа-канал - в типе char) - они и хранят.
То что при этом не учитываются строгие параметры цветности и кому-то рвет шаблон расходуется изрядное количество лишней памяти - пофиг.
У меня машины с 64-битной сборкой, и возможности поглядеть на поведение кода в такой среде - нет.
Может у Вас есть? | |
|
|
|
|
|
|
|
для: Trianon
(26.09.2014 в 16:39)
| | Нет, сборка тоже 32-битная, хотя машина с ОС 64-бит.
А никто и не говорил, что GD, это нечто тонкое в плане инструмента, есть у нее некие "свои" трактовки и в расчетах фильтров, например неожиданный результат работы новой функции imagesetinterpolation() в зависимости от метода. Или это результат недосмотра, ошибки, или как всегда. | |
|
|
|
|
|
|
|
для: Sarat
(18.09.2014 в 11:26)
| | Вот форма
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Панель управления</title>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body bgcolor="#c1a25f">
<table width="100%" border="0" align="center" cellpadding="0" cellspacing="0" class="main_border">
<tr>
<td>
<table width="100%" border="1" cellspacing="0" cellpadding="0">
<?php include ("blocks/header.php"); ?>
<tr>
<?php include ("blocks/ltd.php"); ?>
<td width="70%">
<?php
include ("component_add_slide.php");
resize('../s/', 600, 300, 500, 300);
echo "
<h2>Редактирование главной фотографии</h2>
<form method='post' enctype='multipart/form-data'>
<label>Загрузка фотографии
<input type='file' name='userfile' id='file'></label><br>
<input type=submit value='Добавить'><input type=reset value='Сбросить'>
<h2 align=center>".$error."</h2>
</form>
";
?>
<p>
</p>
</td>
<?php include ("blocks/rtd.php"); ?>
</tr>
<?php include ("blocks/footer.php"); ?>
</table>
</td>
</tr>
</table>
</body>
</html>
|
как я только не ухищрялся с аргументами resize('../s/', 600, 300, 500, 300); всё работает, никаких недочетов, все правильно обрезает!
Вот код файла с функцией
<?php
function resize($directory='../s/', $dst_w=900, $dst_h=600, $dst_w_fix=0, $dst_h_fix=0) // значения по умолчанию
{ global $error;
if($_FILES)
{
if(!$_FILES['userfile']['error']) //если ошибка равна 0, начинаем работать с файлом
{
$origin_name = basename($_FILES['userfile']['name']); //получаем только имя оригинала
list($src_w, $src_h, $type) = getimagesize($_FILES['userfile']['tmp_name']); //Если значение $type равно 1 это gif файл, 2 -> jpg(jpeg), 3 -> png, 6 -> bmp, 15 - > wbmp
if (!$src_w || !$src_h || !$type)//Если в переменную попала ложь (ПЕРВАЯ ПРОВЕРКА)
exit ("<h2>Это не изображение!</h2>Первая проверка не пройдена.
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
if($type==1) {$error = "Загружен GIF формат. Загружаемый файл желательно должен иметь JPG формат.";}
else
{
if(($src_w<$dst_w) || ($src_h<$dst_h) or ($src_w<$dst_w_fix) || ($src_h<$dst_h_fix)) {$error = "Исходное изображение слишком мало!";}
else
{
//размер доступной памяти (с округлением)
$mem = intval(ini_get('memory_limit')/100)*100; //в МБ, при доступных 128, выдаст 100, и т.д.
$img_mem = $src_w * $src_h * 4; //размер памяти, который потребуется для создания ресурса из загруженного файла = ширина * высота * 4
$draft = $dst_w * $dst_h * 4; //плюс требуется память под эскиз
if($draft + $img_mem > $mem*1024*1024) {$error = "Большое изображение!";} //если памяти не хватит значит сообщаем что слишком большое прислали, если хватает памяти, загружаем сразу в ресурс загруженный временный файл
else if($src = imagecreatefromstring(file_get_contents($_FILES['userfile']['tmp_name']))) //переменная $src - это открытый ресурс загруженного изображения, с ним теперь можно делать все что требуется
{
$factor_dst=$dst_w/$dst_h;//коэфициент сжатия уменьшенной копии
$factor_src=$src_w/$src_h;//коэфициент сжатия оригинала
if($factor_dst > $factor_src) $dst_h = $dst_w/$factor_src; //меняяя знак > на < можно получит фото где $dst_w или $dst_h будет максимальной заданному
else $dst_w = $dst_h*$factor_src;
if(!$dst_w_fix || !$dst_h_fix){$dst = imagecreatetruecolor($dst_w,$dst_h);} //если размеры для обрезанной картинки не заданы, то создаем пропорциональную
else {$dst = imagecreatetruecolor($dst_w_fix,$dst_h_fix);
$aspect_w = $src_w/$dst_w; $aspect_h = $src_h/$dst_h; //вычисляем оношение ширин и высот для координат imagecopyresampled
$x_dst = (($dst_w - $dst_w_fix)/2)*$aspect_w; $y_dst = (($dst_h - $dst_h_fix)/2)*$aspect_h; //вычисляем сколько нужно отрезать (с каких координат накладывать изображение)
}
imagecopyresampled($dst, $src, 0 , 0 , $x_dst , $y_dst , $dst_w, $dst_h, $src_w ,$src_h );
$date=date('Y-m-d_H-i-s'); //вычисляем дату и время вплоть до секунд для названия
imagejpeg($dst, $directory.$date.".jpg",95); //сохраняем изображение с наилучшим качеством
imagedestroy ($dst); imagedestroy ($src); //освобождаем память
$error = "Фотография успешно загружена!";
}
else //(ВТОРАЯ ПРОВЕРКА)
exit ("<h2>Это НЕ изображение!</h2> Вторая проверка не пройдена.
<input name='back' type='button' value='Вернуться назад' onclick='history.back ()'>");
}
}
}
else if ($_FILES['userfile']['error'] == 4) {$error = "Не выбрана фотография!";}
}
}
?>
|
| |
|
|
|
|
|
|
|
для: Sarat
(25.09.2014 в 13:59)
| | У меня опять вопрос. Теперь другого характера. Мои фотографии сохраняются в известную директорию.
Как отобразить их на одной странице, да чтобы там была возможностью удаления любой фотографии?
Наведите на правильный путь! Спасибо! | |
|
|
|
|
|
|
|
для: Sarat
(26.09.2014 в 19:54)
| | Ну как выводить, с помощью html тега img. Путь известен, обходите директорию, получайте имена и выводите. Можно glob() использовать. Вот только все в известной директории... Все это сколько? И удобно ли их все вывести на странице?
А что касается удаления, то на странице ничего принадлежащее серверу удалить нельзя. Значит кроме фото нужна еще и ссылка с параметром идентифицирующем фото, получив которую сервер будет знать какое фото нужно удалить. | |
|
|
|
|
|
|
|
для: confirm
(26.09.2014 в 20:34)
| | а можно ли как то открыть файлы фотографий в худшем качестве например, или в меньшем размере, для того чтобы администратору просто показать какая это фотография (для дальнейшего удаления) ну и главное для экономии трафика?
Т.е. как бы так файл открыть, чтобы не атрибутами width, height тега img размер задавать а реально средствами php его уменьшать (только чтобы прочитать, открыть файл и не делать маленьких копий) | |
|
|
|
|
|
|
|
для: Sarat
(30.09.2014 в 10:24)
| | Давайте так - создайте новую тему, в которой опишите это вопрос. Эта тема слишком велика уже, чтобы в ней удобно было "копаться". | |
|
|
|
|
|
|
|
для: Sarat
(30.09.2014 в 10:24)
| | Не хочется создавать новой темы? Или все уже решено.
Тем не менее, в качестве размышлений.
С худшим качеством или малым размером и средствами РНР - то перелопачивать файлы каждый раз когда требуется их просмотр для редактирования. Плюс усложняется само построение страницы - либо атрибут src обращается к отдельному файлу скрипту на лету перелопачивая качество/уменьшая размер, либо к этой же странице, в начале которой поместить обработчик запроса от картинок.
Если для вас есть смысл в этом, делайте, но экономия трафика сомнительна, если беспокоится только о КБ.
Средствами HTML, это указать атрибутам width, height размеры в процентах меньше 100. Браузер выведет с указанным размером, но реально загружать будет изображения как есть.
Накладно.
Создавать эскиз для служебных целей, это не такая уж и непосильная задача, тем более выполняющаяся всего лишь раз. Удаляя изображение больше, не сложно удалить и его эскиз, если по уму организовать именование файлов, то есть чтобы и большое и малое имело общую маску.
Какие могут быть проблемы.
Если изображения только удаляется, то проблемы не будет, но если изображения редактируется, например, существующее замещается новым и в случае даже если они у вас "бесхозные", чего в принципе быть не должно, имя должно остаться тем же. А это значит, что заменив текущее фото другим, вы не обязательно увидите новое, браузер покажет старое, из кеша. Особенно в этом плане "лютует" FF.
Такая проблема решается добавлением к имени изображения GET-параметра, в качестве которого выводят текущую на момент выдачи файла метку времени. Но это порождает новую проблему - не будут браться из кеша все файлы, даже те, что не подвергались изменениям. Поэтому в качестве GET-параметра нужно передавать время последнего изменения файла, тогда браузер будет делать запросы только на измененные файлы.
Это в качестве нагрузки, для размышления на будущее.
Все бы ничего, но получение времени последнего изменения файла, это файловая операция, да если еще выводится не одно изображение... Как ни крути, но опять возвращаемся к старому вопросу - как хранить. А хранить изображения, иные файлы безхозно нельзя, а у хорошего завхоза всегда будет тетрадочка учета прихода и расхода, а в ней все важные и требующиеся параметры приходов расписаны, и что на какой полочке. И он не будет чертыхаться о бочки с семгой, зная что идет к ящикам с пивом, и несложно посчитать их количество, и все, что касается его всегда под рукою.
Если что, то только новая тема. | |
|
|
|
|
|
|
|
для: Sarat
(18.09.2014 в 11:26)
| | Перенесите длинный текст комментария последнего поста, иначе прокрутка по горизонтали.
if ($_FILES['userfile']['error'] == 4) - это не означает, что пользователь не выбрал изображение, это означает, что выбранное не загружено, так что это не пойдет. Не выбрано изображение, это однозначное массив $_FILES пуст.
И что вы в конце концов делаете - для администрирования или же для пользователей? | |
|
|
|
|
|
|
|
для: confirm
(25.09.2014 в 14:10)
| | Для администрирования. А чем же плох? | |
|
|
|
|
|
|
|
для: Sarat
(25.09.2014 в 14:59)
| | Что именно плохо, скрипт?
Во-первых, это не универсальность. Во-вторых, негоже ошибки, которые могут возникнуть при загрузке изображения трактовать как вам вздумается. И в третьих - полю типа file установите атрибут required, который не позволит отправить форму, если изображение для загрузки не выбрано, а администратора обязать работать под браузером поддерживающим HTML5. | |
|
|
| |
|
|
|
|
для: Deed
(25.09.2014 в 18:54)
| | Это не для GD. | |
|
|
|
|
|
|
|
для: Deed
(25.09.2014 в 18:54)
| | не совсем. там нет ничего про метод cropThumbnailImage. вот он как раз самый полезный. а вообще да, GD лучше не пользоваться. тормознутая и убогая | |
|
|
|
|