Изображение PHP: сгенерированное изображение имеет правую и нижнюю черную границу на рабочем сервере, но не на моей локальной машине - PullRequest
0 голосов
/ 01 марта 2019

Это приложение написано мной, я протестировал его на своем локальном компьютере, и образ, сгенерированный моим приложением, великолепен без ошибок на моем локальном сервере разработки.Мое приложение - это API, пользователь использует его для создания мозаичного изображения.В основном она использует библиотеку PHP Image GD.

Проблема : сгенерированное изображение имеет правую и нижнюю черные границы шириной в один пиксель, но это происходит только на рабочем сервере Это не на моем локальном сервере.Граница создается только в том случае, если изображение прозрачное (в моем случае: изображение типа «контур», «инвертировать», «черное». Посмотрите на код ниже).Но иногда границы в основном присутствуют, а иногда нет.

Я уверен, что с моим кодом все в порядке, и мое приложение работает безупречно.Я протестировал в обеих средах один и тот же тип изображения, одно и то же измерение и одну и ту же конфигурацию для моего приложения ... и, тем не менее, рабочий сервер генерирует изображение с границей.

Вот фрагменткод моего приложения, на который с подозрением смотрится:

$src = $img->filePath;
$src_outline = $img->filePathComplements['outline'];
$src_invert = $img->filePathComplements['invert'];
$src_black = $img->filePathComplements['black'];
$info_text = is_array($img->info) ? join($img->info, ', ') : (is_string($img->info) ? $img->info : '');

$w = $img->widthOriginal;
$h = $img->heightOriginal;
$x = $img->fit->x + $this->packer->getPageMarginLeft() + $this->packer->getMarginLeft() +
        $this->packer->getVerticalBorderWidth() + $this->packer->getVerticalBordefOffset();
$y = $img->fit->y + $this->packer->getPageMarginTop() + $this->packer->getMarginTop();
$info_y = $y + $h + $this->packer->getImageInfoMargin();

// Create main and complement images
$image_main = imagecreatefrompng($src);
$image_outline = imagecreatefrompng($src_outline);
$image_invert = imagecreatefrompng($src_invert);
$image_black = imagecreatefrompng($src_black);

list($w_px_original, $h_px_original) = getimagesize($src);

$image_main_resampled = Image::imageCreateTrueColorTransparent($w, $h);
$image_outline_resampled = Image::imageCreateTrueColorTransparent($w, $h);
$image_invert_resampled = Image::imageCreateTrueColorTransparent($w, $h);
$image_black_resampled = Image::imageCreateTrueColorTransparent($w, $h);

// Resample images from original dimension to DPI-based dimension
imagecopyresampled($image_main_resampled, $image_main, 0, 0, 0, 0, $w, $h, $w_px_original, $h_px_original);
imagecopyresampled($image_outline_resampled, $image_outline, 0, 0, 0, 0, $w, $h, $w_px_original, $h_px_original);
imagecopyresampled($image_invert_resampled, $image_invert, 0, 0, 0, 0, $w, $h, $w_px_original, $h_px_original);
imagecopyresampled($image_black_resampled, $image_black, 0, 0, 0, 0, $w, $h, $w_px_original, $h_px_original);

// Add image to all containers
// Parameters are: Destination image, source image, destination starting coordinates (x, y),
// source starting coordinates (x, y), source dimension (width, height).
imagecopy($container_main, $image_main_resampled, $x, $y, 0, 0, $w, $h);
imagecopy($container_outline, $image_outline_resampled, $x, $y, 0, 0, $w, $h);
imagecopy($container_invert, $image_invert_resampled, $x, $y, 0, 0, $w, $h);
imagecopy($container_black, $image_black_resampled, $x, $y, 0, 0, $w, $h);

// Add info to main and outline images
$info = Image::imageDrawTextBordered($w, $info_h, INFO_FONT_SIZE, INFO_BORDER_SIZE, $info_text);
imagecopy($container_main, $info, $x, $info_y, 0, 0, $w, $info_h);
imagecopy($container_outline, $info, $x, $info_y, 0, 0, $w, $info_h);

И Image::imageCreateTrueColorTransparent():

/**
 * Creates and returns image resource of a true color transparent image.
 * @param $width
 * @param $height
 * @return resource
 */
public static function imageCreateTrueColorTransparent($width, $height) {
    $im = imagecreatetruecolor($width, $height);

    imagealphablending($im, false);
    imagesavealpha($im, true);

    $transparent = imagecolorallocatealpha($im, 0, 0, 0, 127);
    imagefill($im, 0, 0, $transparent);

    return $im;
}

Пример результата с моей локальной машины (нажмите, чтобы посмотреть в оригинальном размере):The example of result from my local machine

Пример результата с рабочего сервера (нажмите, чтобы посмотреть в оригинальном размере): The example of result from the production server

Я имеюЯ провел здесь исследование Stackoverflow, и я получил два потока, которые сказали, что проблема была вызвана функцией imagecopyresampled().Тем не менее, я не уверен в этом, так как мое приложение работает без ошибок на моей локальной машине.Вот список обсуждений:

Любая помощь будет признательна, пожалуйста, уточните, если вы знаете, что является причиной этого и / или вы когда-либо испытывали это.Заранее спасибо.

1 Ответ

0 голосов
/ 26 июля 2019

Эта функция изменяет размер изображения независимо от его формата или наличия альфа-канала / прозрачности.

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

Размер заполнения рассчитывается независимо для двух осей на основе разницы в размерах между исходным изображением и измененным размеромimage.

Например, для изображения размером 256x128 пикселей, размер которого должен быть изменен до 16x16 пикселей, требуется следующий отступ:

256 / 16 = 16   columns on the right
128 / 16 = 8    rows on the bottom

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

Padded image

/** Resize an image resource.
 *
 * @param resource $src_image Original image resource.
 * @param int $dest_x Destination image x position.
 * @param int $dest_y  Destination image y position.
 * @param int $dest_width Destination width.
 * @param int $dest_height Destination height.
 * @param int $src_width Source width (can be less than full-width to get a subregion).
 * @param int $src_height Source height (can be less than full-height to get a subregion).
 * @return false|resource Resized image as resource, false on error.
 */
function resize_resource($src_image, $dest_x, $dest_y, $dest_width, $dest_height, $src_width, $src_height) {

    $img_width = imagesx($src_image);
    $img_height = imagesy($src_image);

    // Create a padded version of source image cloning rows/columns of pixels from last row/column
    // to ensure full coverage of right and bottom borders after rescaling.

    // Compute padding sizes.
    $pad_width = (int)ceil($img_width / $dest_width);
    $pad_height = (int)ceil($img_height / $dest_height);

    $padded = imagecreatetruecolor($img_width + $pad_width, $img_height + $pad_height);
    if ($padded === false) return false;

    imagealphablending($padded, false);

    $transparent = imagecolorallocatealpha($padded, 0, 0, 0, 127);
    imagefill($padded, 0, 0, $transparent);
    imagecopy($padded, $src_image, 0, 0, 0, 0, $img_width, $img_height);

    // Clone last column.
    for ($i = 0; $i < $pad_width; ++$i)
        imagecopy($padded, $src_image, $i + $img_width, 0, $img_width - 1, 0, 1, $img_height);

    // Clone last row.
    for ($i = 0; $i < $pad_height; ++$i)
        imagecopy($padded, $src_image, 0, $i + $img_height, 0, $img_height - 1, $img_width, 1);

    // Fill remaining padding area on bottom-right with color of bottom-right original image pixel.
    $pad_pixel = imagecolorat($padded, $img_width - 1, $img_height - 1);
    $pad_color = imagecolorallocatealpha($padded, ($pad_pixel >> 16) & 0xFF,
        ($pad_pixel >> 8) & 0xFF, $pad_pixel & 0xFF, ($pad_pixel >> 24) & 0x7F);
    imagefilledrectangle($padded, $img_width, $img_height,
        $img_width + $pad_width - 1, $img_height + $pad_height - 1, $pad_color);

    // Create new rescaled image.

    $new = imagecreatetruecolor($dest_width, $dest_height);
    if ($new === false) return false;

    imagealphablending($new, false);
    $transparent = imagecolorallocatealpha($new, 0, 0, 0, 127);
    imagefill($new, 0, 0, $transparent);

    imagecopyresampled($new, $padded, 0, 0, $dest_x, $dest_y, $dest_width, $dest_height, $src_width, $src_height);

    return $new;
}

ПРИМЕЧАНИЕ: дляДля корректного отображения прозрачности в конечном изображении необходимо правильно использовать следующий код, просто перед тем, какзапись на диск:

$transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
imagecolortransparent ($img, $transparent);

в случае изображений с индексированным цветом или следующий код:

imagesavealpha($img, true);

в случае изображений с альфа-каналом.Где $ img - это ресурс изображения с измененным размером, возвращаемый функцией, описанной выше.

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

...