Поворот и обрезка

Я вращаюсь и обрезаю изображение с помощью PHP, но получаю черную рамку, я знаю, что вы можете изменить цвет фона, но я хочу повернуть и обрезать изображение, чтобы заполнить все изображение. В основном что-то похожее на background-size: cover; (слева) в CSS по сравнению background-size: contain; (правильно).

См. Изображение ниже, справа – это то, что я получил сейчас, остальное – это то, чего я хочу достичь. Число градусов для вращения является динамическим, а изображение должно быть произведено, а исходное изображение – квадратным (200×200).

Иллюстрация проблемы

EDIT: Вот мой быстрый и грязный код:

 $rotate = imagecreatefromjpeg($image); // part of code created by www.thewebhelp.com, modified $square_size = 200; $original_width = imagesx($rotate); $original_height = imagesy($rotate); if($original_width > $original_height){ $new_height = $square_size; $new_width = $new_height*($original_width/$original_height); } if($original_height > $original_width){ $new_width = $square_size; $new_height = $new_width*($original_height/$original_width); } if($original_height == $original_width){ $new_width = $square_size; $new_height = $square_size; } $new_width = round($new_width); $new_height = round($new_height); $smaller_image = imagecreatetruecolor($new_width, $new_height); $square_image = imagecreatetruecolor($square_size, $square_size); imagecopyresampled($smaller_image, $rotate, 0, 0, 0, 0, $new_width, $new_height, $original_width, $original_height); if($new_width>$new_height){ $difference = $new_width-$new_height; $half_difference = round($difference/2); imagecopyresampled($square_image, $smaller_image, 0-$half_difference+1, 0, 0, 0, $square_size+$difference, $square_size, $new_width, $new_height); } if($new_height>$new_width){ $difference = $new_height-$new_width; $half_difference = round($difference/2); imagecopyresampled($square_image, $smaller_image, 0, 0-$half_difference+1, 0, 0, $square_size, $square_size+$difference, $new_width, $new_height); } if($new_height == $new_width){ imagecopyresampled($square_image, $smaller_image, 0, 0, 0, 0, $square_size, $square_size, $new_width, $new_height); } $degrees = rand(1,360); $square_image = imagerotate($square_image, $degrees, 0); imagejpeg($square_image,NULL,100); 

Замените эти строки примерно в конце кода:

 $degrees = rand(1,360); $square_image = imagerotate($square_image, $degrees, 0); imagejpeg($square_image,NULL,100); 

С этим:

 $degrees = rand(1,360); $square_image = imagerotate($square_image, $degrees, 0); $rotated_size = imagesx($square_image); $enlargement_coeff = ($rotated_size - $square_size) * 1.807; $enlarged_size = round($rotated_size + $enlargement_coeff); $enlarged_image = imagecreatetruecolor($enlarged_size, $enlarged_size); $final_image = imagecreatetruecolor($square_size, $square_size); imagecopyresampled($enlarged_image, $square_image, 0, 0, 0, 0, $enlarged_size, $enlarged_size, $rotated_size, $rotated_size); imagecopyresampled($final_image, $enlarged_image, 0, 0, round($enlarged_size / 2) - ($square_size / 2), round($enlarged_size / 2) - ($square_size / 2), $square_size, $square_size, $square_size, $square_size); imagejpeg($final_image,NULL,100); 

Вот логика этого:

1) После выполнения imagerotate () наше новое изображение изменило свои размеры, поскольку каждое вращение обычно приводит к большему изображению. Поскольку источник представляет собой квадратное изображение, мы берем либо ширину, либо высоту, чтобы определить размеры повернутого изображения.

2) Когда исходное изображение вращается, даже немного, размеры самого большого квадрата используемых пиксельных данных из исходного изображения всегда будут меньше, чем исходное невращающееся квадратное изображение. Поэтому, чтобы создать новое квадратное изображение того же размера, что и начальное квадратное изображение, но без артефакта «черной границы», как вы его называете, нам нужно увеличить повернутое изображение, так что наибольший квадрат используемого пикселя данные из исходного изображения во вращающемся изображении могут достигать начального квадратного изображения.

Ключевое значение здесь 1.807 . Это значение в основном показывает, сколько пикселей вам нужно увеличить повернутое изображение для каждого пикселя разницы между его размерами и размерами исходного невращенного изображения. Вероятно, есть лучшая математическая формула для извлечения этого значения, к сожалению, я сосать в Math, так что это трудный способ придумать это значение.

  • Вращение 45/135/225/315 градусов всегда будет производить наибольшее изображение с наименьшим квадратом данных пикселя.
  • Зная это, вы сравниваете размеры исходного изображения и его 45-градусной версии. В нашем случае исходное изображение – 200×200, а версия с 45 градусами – около 283×283
  • В программе, подобной Photoshop, вы определяете, сколько раз вам нужно увеличить 45-градусную версию изображения, чтобы иметь возможность извлечь квадрат размером 200×200 из него без «черной границы» – в нашем случае 283×283 изображение должно быть увеличено до изображения 433×433, поэтому мы могли бы извлечь квадрат размером 200×200
  • 433 – 283 = 150 -> означает, что нам нужно увеличить максимально возможное повернутое изображение на 150 пикселей, чтобы извлечь из него квадрат размером 200×200.
  • 283 – 200 = 83 -> 83 пикселей – это разница между максимально возможным поворотным изображением и оригинальным невращаемым изображением.
  • «Маленькое» преобразование – «большая» площадь, которую мы можем использовать, и, следовательно, «меньший» размер расширения, который нам нужно применить. И поскольку поворот на 45 градусов привел к разнице в 83 пикселя между исходным изображением и преобразованным изображением, которое требовало увеличения на 150 пикселей, мы можем сделать:
  • 150/83 = 1.807 -> означает, что разница в 1 пикселе между исходным изображением и повернутым изображением требует, чтобы повернутое изображение было увеличено на 1,807 пикселя, так что мы можем извлечь из него квадрат, который имеет те же размеры, что и исходное изображение

3) Зная, что для каждой разницы в 1 пиксель нам нужно увеличить с 1,807 пикселями, мы проверяем, в чем разница между нашим размером вращения и размером оригинального изображения и умножаем его на это значение, чтобы посмотреть, какие размеры должны иметь увеличенное изображение:

 $enlargement_coeff = ($rotated_size - $square_size) * 1.807; $enlarged_size = round($rotated_size + $enlargement_coeff); 

4) Мы идем вперед и генерируем увеличенное повернутое изображение.

 imagecopyresampled($enlarged_image, $square_image, 0, 0, 0, 0, $enlarged_size, $enlarged_size, $rotated_size, $rotated_size); 

5) Наконец, мы извлекаем квадрат размером 200×200 из нашего увеличенного повернутого изображения, используя его центральные координаты в качестве эталона

 imagecopyresampled($final_image, $enlarged_image, 0, 0, round($enlarged_size / 2) - ($square_size / 2), round($enlarged_size / 2) - ($square_size / 2), $square_size, $square_size, $square_size, $square_size); 

Чтобы сломать это, ($square_size / 2) возвращает координаты X и Y центральной точки в увеличенном повернутом изображении. round($enlarged_size / 2) возвращает количество пикселов, которые вам нужны, слева от центра вдоль оси X и над центром вдоль оси Y, чтобы получить квадрат 200 × 200.


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