Архив за Июль 2008

Масштабирование изображений

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

Итак, пусть у нас есть файл в любом поддерживаемом GD формате, и мы хотим создать “превьюшку” заданного размера в формате JPEG. Разработаем для этой цели функцию img_resize(). Код функции содержит подробные комментарии - так что чтение не должно вызвать затруднений.

/*
Функция img_resize(): генерация thumbnails
Параметры:
$src - имя исходного файла
$dest - имя генерируемого файла
$width, $height - ширина и высота генерируемого изображения, в пикселях
Необязательные параметры:
$rgb - цвет фона, по умолчанию - белый
$quality - качество генерируемого JPEG, по умолчанию - максимальное (100)
*/

function img_resize($src, $dest, $width, $height, $rgb=0xFFFFFF, $quality=100)
{
  if (!file_exists($src)) return false;

  $size = getimagesize($src);

  if ($size === false) return false;

  // Определяем исходный формат по MIME-информации, предоставленной
  // функцией getimagesize, и выбираем соответствующую формату
  // imagecreatefrom-функцию.
  $format = strtolower(substr($size['mime'], strpos($size['mime'], '/')+1));
  $icfunc = "imagecreatefrom" . $format;
  if (!function_exists($icfunc)) return false;

  $x_ratio = $width / $size[0];
  $y_ratio = $height / $size[1];

  $ratio = min($x_ratio, $y_ratio);
  $use_x_ratio = ($x_ratio == $ratio);

  $new_width = $use_x_ratio ? $width : floor($size[0] * $ratio);
  $new_height = !$use_x_ratio ? $height : floor($size[1] * $ratio);
  $new_left = $use_x_ratio ? 0 : floor(($width - $new_width) / 2);
  $new_top = !$use_x_ratio ? 0 : floor(($height - $new_height) / 2);

  // Читаем в память файл изображения с помощью функции imagecreatefrom...
  $isrc = $icfunc($src);
  // Создаем новое изображение
  $idest = imagecreatetruecolor($width, $height);

  // Заливка цветом фона
  imagefill($idest, 0, 0, $rgb);
  // Копируем существующее изображение в новое с изменением размера:
  imagecopyresampled(
    $idest, // Идентификатор нового изображения
    $isrc, // Идентификатор исходного изображения
     $new_left, $new_top, // Координаты (x,y) верхнего левого угла в новом изображении
    0, 0, // Координаты (x,y) верхнего левого угла копируемого блока
           // существующего изображения
    $new_width, // Новая ширина копируемого блока
    $new_height, // Новая высота копируемого блока
    $size[0], // Ширина исходного копируемого блока
    $size[1] // Высота исходного копируемого блока
  );
  // Сохраняем результат в JPEG-файле: функция imagejpeg, может выводить
  // результат своей работы не только в броузер, но и в файл. Для этого
  // следует указать имя файла в необязательном втором параметре.
  // Функция imagejpeg имеет и третий необязательный параметр - качество
  // изображения.
  imagejpeg($idest, $dest, $quality);

  imagedestroy($isrc);
  imagedestroy($idest);

  return true;
}
?>

Пример использования:

if (img_resize('original.jpg', 'small.jpg', 100, 100))
  echo 'Image resized OK';
else
  echo 'Resize failed!';
?>

Ссылки по теме:

Реагирование на события в JavaScript

Реагирование на события в JavaScript может быть организовано разными способами.

  • с помощью атрибута HTML: <body onload=”xyz();”>
  • с помощью атрибута onXXX, доступного в JavaScript: window.onload = xyz;

Однако в браузерах реализованы разные, конкурирующие механизмы обработки событий. Так, в Internet Explorer поддерживается присоединение событий к элементу с помощью метода attachEvent(). В этом случае имя события равнозначно имени атрибута HTML, поэтому, в частности, используется обозначение “onload”, хотя само событие называется “load”.

Во всех остальных браузерах поддерживается метод addEventListener(), являющийся составной частью модели W3C. В данном случае указывается имя события, поэтому вместо “onload” используется обозначение “load”.

В следующем примере показано, каким образом событие присоединяется к кнопке с учетом типа браузера:

<script type="text/javascript">
function eventHandler() {
  window.alert("Event fired!");
}

window.onload = function() {
  var button = document.getElementById("eventButton");
  if (button.addEventListener) {
    button.addEventListener("click", eventHandler, false);
  } else if (button.attachEvent) {
    button.attachEvent("onclick", eventHandler);
  }
};
</script>
<input type="button" id="eventButton" value="Click me!" />

Обработчики событий можно также удалить. Для этой цели в Internet Explorer служит метод detachEvent(), тогда как в остальных браузерах этот метод называется removeEventListener() в соответствии с моделью W3C.

Всплывание событий

Обработка событий в браузерах осуществляется в соответствии с одним из двух принципов. Так, в Internet Explorer применяется принцип так называемого всплывания событий: событие сначала запускается из того элемента, где оно наступает, а затем оно всплывает вверх по структуре модели DOM. Следовательно, фиксировать такое событие и реагировать на него можно в самых разных местах документа. Рассмотрим для примера следующую разметку документа:

<div><p><em>JavaScript</em> Phrasebook</p></div>

Если курсор мыши оказывается над текстом JavaScript, то событие mouseover сначала запускается в элементе <em>, а затем всплывает вверх до элементов <p> и <div>.

В конкурирующей модели W3C, которая поддерживается в браузерах Mozilla и Opera, события сначала погружаются вниз до целевого элемента, а затем всплывают вверх. Следовательно, в приведенном выше примере событие сначала опускается последовательно от элемента <div> до элементов <p> и <em>, а затем всплывает вверх до элементов <p> и <div>. При вводе процесса прослушивание событий в качестве третьего параметра функции addEventListener() можно указать порядок перехвата события: во время его погружения (логическое событие true) или всплывания (логическое событие false).

После того, как событие будет перехвачено, его погружение или всплывание можно прекратить. В Internet Explorer для этой цели свойству canselBubble присваивается логическое значение false:

window.event.canselBubble = false;

В модели W3C поддерживается метод stopPropagation():

e.stopPropagation();

Как видите, в Internet Explorer текущее событие всегда доступно посредством свойства window.event, тогда как в остальных браузерах событие автоматически воспринимается в качестве параметра (в данном случае e) функции прослушивания событий.

Ссылки по теме:

Блокировка таблиц

Для таблиц типа MyISAM использование транзакций недоступно. Однако их можно эмулировать при помощи операторов LOCK TABLES И UNLOCK TABLES. В отличие от полноценных транзакций, данные операторы блокируют всю таблицу, в результате чего никто не может работать с таблицами до тех пор, пока они остаются заблокированными. Оператор LOCK TABLES выполняет блокировку таблиц, а UNLOCK TABLES снимает блокировку.

Замечание
Все таблицы, заблокированные в текущем соединении, разблокируются при повторном вызове оператора LOCK TABLES.

Замечание
Операторы LOCK TABLES и UNLOCK TABLES имеют синонимы LOCK TABLE и UNLOCK TABLE соответственно.

LOCK TABLES categories WRITE;
INSERT INTO categories VALUES (NULL, 'Мониторы');
INSERT INTO categories VALUES (NULL, 'Принтеры');
UNLOCK TABLES;

Листинг демонстрирует блокировку таблицы categories на время добавления данных в таблицу. Следует обратить внимание, что после оператора LOCK TABLES указывается имя блокируемой таблицы, при снятии блокировки указания имени таблицы уже не требуется. Основная причина применения блокировки таблицы при помощи LOCK TABLES - это увеличение скорости обновления таблиц и добавления больших объемов данных.

При использовании блокировок можно явно указать тип блокировки - на чтение (READ) или на запись (WRITE). Различие между блокировками на чтение и запись заключается в том, что и клиент, установивший блокировку на чтение, и остальные клиенты могут только читать из таблицы данные. При блокировке на запись установивший ее клиент может как вносить записи в таблицу, так и читать, в то время как доступ других клиентов блокируется. Причем все остальные клиенты ожидают, когда блокировка будет отменена оператором UNLOCK TABLES.

Один оператор LOCK TABLES может блокировать сразу несколько таблиц, причем рекомендуется блокировать все таблицы, которые участвуют в запросах внутри блокировки. Это связано с тем, что пока блокировка, установленная LOCK TABLES, активна, невозможно получить доступ ни к каким таблицам, которые не были блокированы этим оператором.

Блокировки по записи (WRITE) имеют более высокий приоритет, чем блокировки по чтению (READ), чтобы гарантировать, что обновления данных пройдут как можно быстрее. Это означает, что если один или несколько клиентов устанавливают блокировку на чтение (READ), а затем другой клиент устанавливает блокировку на запись (WRITE) по этим же таблицам, то остальные клиенты будут ожидать, пока блокировка по записи не будет снята.