Выбор миниатюры по внешней ссылке - PullRequest
3 голосов
/ 12 февраля 2010

Я пытаюсь создать сценарий, который извлекает список миниатюрных изображений по внешней ссылке, так же, как это делает Facebook, когда вы делитесь ссылкой, и могу выбрать миниатюрное изображение, связанное с этим сообщением.

Мой скрипт в настоящее время работает так:

  • file_get_contents по URL
  • preg_match_all для совпадения с любым <img src="" в содержимом
  • Определяет полный URL-адрес каждого изображения и сохраняет его в массиве
  • Если есть <10 изображений, он проходит через и использует <code>getimagesize, чтобы найти ширину и высоту
  • Если имеется> 10 изображений, оно проходит через и использует fread и imagecreatefromstring, чтобы найти ширину и высоту (для скорости)
  • Как только все ширина и высота проработаны, он проходит по циклу и добавляет только изображения в новый массив, который имеет минимальную ширину и высоту (поэтому отображаются только большие изображения, меньшие изображения с меньшей вероятностью будут описывать URL)
  • Каждое изображение имеет новые размеры (пропорционально уменьшенные) и возвращается ...

<img src="'.$image[0].'" width="'.$image[1].'" height="'.$image[2].'"><br><br>

На данный момент это работает нормально, но у меня может возникнуть ряд проблем:

  1. SPEED! Если URL содержит много изображений на странице, обработка может занять значительно больше времени
  2. ПАМЯТЬ! Использование getimagesize или fread & imagecreatefromstring сохранит все изображение в памяти, любые большие изображения на странице могут поглотить память сервера и уничтожить мой скрипт (и сервер)

Одно решение, которое я нашел, - это возможность получить ширину и высоту изображения из заголовка изображения без необходимости загрузки всего изображения, хотя я нашел только некоторый код, чтобы сделать это для JPG (он должен был бы поддерживать GIF & PNG).

Может кто-нибудь сделать какие-либо предложения, чтобы помочь мне с любой проблемой, упомянутой выше, или, возможно, вы можете предложить другой способ сделать это, я открыт для идей ... Спасибо!

** Редактировать: Код ниже:

// Example images array
$images = array('http://blah.com/1.jpg', 'http://blah.com/2.jpg');

// Find the image sizes
$image_sizes = $this->image_sizes($images);

// Find the images that meet the minimum size
for ($i = 0; $i < count($image_sizes); $i++) {
    if ($image_sizes[$i][0] >= $min || $image_sizes[$i][1] >= $min) {                
        // Scale down the original image size
        $dimensions = $this->resize_dimensions($scale_width, $scale_height, $image_sizes[$i][0], $image_sizes[$i][1]);
        $img[] = array($images[$i], $dimensions['width'], $dimensions['height']);
    }
}

// Output the images
foreach ($img as $image) echo '<img src="'.$image[0].'" width="'.$image[1].'" height="'.$image[2].'"><br><br>';

/**
 * Retrieves the image sizes
 * Uses the getimagesize() function or the filesystem for speed increases
 */
public function image_sizes($images) {
    $out = array();
    if (count($images) < 10) {
        foreach ($images as $image) {
            list($width, $height) = @getimagesize($image);
            if (is_numeric($width) && is_numeric($height)) {
                $out[] = array($width, $height);
            }
            else {
                $out[] = array(0, 0);
            }
        }
    }
    else {
        foreach ($images as $image) {
            $handle = @fopen($image, "rb");
            $contents = "";
            if ($handle) {
                while(true) {
                    $data = fread($handle, 8192);
                    if (strlen($data) == 0) break;
                    $contents .= $data;
                }
                fclose($handle);
                $im = @imagecreatefromstring($contents);
                if ($im) {
                    $out[] = array(imagesx($im), imagesy($im));
                }
                else {
                    $out[] = array(0, 0);
                }
                @imagedestroy($im);
            }
            else {
                $out[] = array(0, 0);
            }
        }
    }
    return $out;
}

/**
 * Calculates restricted dimensions with a maximum of $goal_width by $goal_height 
 */
public function resize_dimensions($goal_width, $goal_height, $width, $height) {
    $return = array('width' => $width, 'height' => $height);

    // If the ratio > goal ratio and the width > goal width resize down to goal width
    if ($width/$height > $goal_width/$goal_height && $width > $goal_width) {
        $return['width'] = floor($goal_width);
        $return['height'] = floor($goal_width/$width * $height);
    }

    // Otherwise, if the height > goal, resize down to goal height
    else if ($height > $goal_height) {
        $return['width'] = floor($goal_height/$height * $width);
        $return['height'] = floor($goal_height);
    }   
    return $return;
}

Ответы [ 2 ]

1 голос
/ 14 февраля 2010

getimagesize читает только заголовок, но imagecreatefromstring читает все изображение. Изображение, считываемое GD, ImageMagick или GraphicsMagic, сохраняется в виде растрового изображения, поэтому оно потребляет ширину высоту (3 или 4) байта, и с этим ничего не поделаешь. Лучшее возможное решение вашей проблемы - сделать несколько запросов curl (см. http://ru.php.net/manual/en/function.curl-multi-select.php), а затем один за другим обработать полученные изображения с помощью GD или любой другой библиотеки. А чтобы уменьшить потребление памяти, вы можете хранить файлы изображений на диске, а не в памяти.

0 голосов
/ 12 февраля 2010

Единственная идея, которая приходит на ум при вашем текущем подходе (что впечатляет), - это проверить HTML на наличие существующих атрибутов ширины и высоты и вообще пропустить процесс чтения файла, если они существуют.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...