2013-04-27 23 views
5

Tôi đang xoay và cắt ảnh bằng PHP, nhưng tôi nhận được viền màu đen hiển thị, tôi biết bạn có thể thay đổi màu nền, nhưng tôi muốn xoay và cắt hình ảnh để lấp đầy toàn bộ hình ảnh. Về cơ bản, có điều gì đó tương tự như background-size: cover; (bên trái) trong CSS so với background-size: contain; (bên phải).Xoay và cắt

Xem hình ảnh bên dưới, bên phải là những gì tôi có ngay bây giờ, còn lại là những gì tôi muốn đạt được. Số lượng độ quay là động và hình ảnh được tạo ra và hình ảnh nguồn đều là hình vuông (200x200).

Illustration of problem

EDIT: Đây là mã nhanh chóng và dơ bẩn của tôi:

$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); 
+0

Hiển thị mã của bạn. – sachleen

+0

Tôi nghĩ rằng tương tự 'background-size' của bạn không phù hợp với những gì bạn yêu cầu. – Ejaz

+0

http://stackoverflow.com/a/22511805/2106820 –

Trả lời

5

Thay thế những dòng này ở vào khoảng cuối của mã của bạn:

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

Với điều này:

$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); 

Dưới đây là logic đằng sau đó:

1) Sau khi thực hiện imagerotate() hình ảnh mới của chúng tôi đã thay đổi kích thước của nó, vì mỗi luân thường kết quả trong một hình ảnh lớn hơn. Vì nguồn là hình vuông, chúng tôi lấy chiều rộng hoặc chiều cao để xác định kích thước của hình ảnh được xoay.

2) Khi hình ảnh gốc được xoay, thậm chí một chút, kích thước của hình vuông lớn nhất của dữ liệu pixel có thể sử dụng từ hình ảnh gốc sẽ luôn nhỏ hơn hình ảnh vuông không được bảo vệ ban đầu. Do đó, để tạo hình ảnh vuông mới có cùng kích thước với hình vuông ban đầu, nhưng không có tạo hình "viền đen", như bạn gọi, chúng tôi cần phóng to hình ảnh được xoay sao cho hình vuông có thể sử dụng lớn nhất dữ liệu từ hình ảnh gốc trong hình ảnh được xoay có thể trở nên lớn như hình vuông ban đầu.

Giá trị khóa ở đây là 1.807. Giá trị này về cơ bản cho biết số lượng pixel bạn cần để phóng to hình ảnh xoay cho mỗi pixel khác nhau giữa kích thước của nó và kích thước của hình ảnh không được bảo vệ ban đầu. Có lẽ một công thức toán học tốt hơn để lấy giá trị này, thật không may tôi hút Math, vì vậy đây là cách khó để tìm ra giá trị đó.

  • Xoay vòng 45/135/225/315 độ sẽ luôn tạo ra hình ảnh lớn nhất với hình vuông nhỏ nhất có thể sử dụng.
  • Biết điều này, bạn so sánh kích thước của hình ảnh gốc và phiên bản xoay 45 độ của nó. Trong trường hợp của chúng tôi, hình ảnh gốc là 200x200 và phiên bản xoay 45 độ là khoảng 283x283
  • Trong một chương trình như Photoshop, bạn xác định số lần bạn cần phóng to phiên bản hình ảnh 45 độ xoay để có thể trích xuất hình vuông 200x200 từ nó, không có "viền đen" - trong trường hợp của chúng tôi, hình ảnh 283x283 cần được phóng to hình ảnh 433x433, vì vậy chúng tôi có thể trích xuất một hình vuông 200x200
  • 433 - 283 = 150 -> chúng ta cần phóng to hình ảnh xoay lớn nhất có thể với 150 pixel để có thể trích xuất hình vuông 200x200 từ nó.
  • 283 - 200 = 83 -> 83 pixel là sự khác biệt giữa hình ảnh xoay lớn nhất có thể và hình ảnh không được bảo vệ ban đầu.
  • Biến đổi "nhỏ hơn" - khu vực hình vuông "lớn hơn" chúng ta có thể sử dụng và do đó - số lượng mở rộng chúng ta cần áp dụng càng nhỏ. Và vì xoay vòng 45 độ dẫn đến sự khác biệt 83 pixel giữa hình ảnh gốc và hình ảnh được chuyển đổi yêu cầu mở rộng 150 pixel, chúng tôi có thể làm:
  • 150/83 = 1.807 -> nghĩa là chênh lệch 1 pixel giữa hình ảnh gốc và hình ảnh xoay yêu cầu hình ảnh được xoay được mở rộng với 1,807 pixel, để chúng tôi có thể trích xuất một hình vuông từ hình vuông có cùng kích thước với hình ảnh gốc

3) Biết rằng đối với mỗi khác biệt 1 pixel chúng tôi cần phóng to với 1.807 pixel, chúng tôi kiểm tra sự khác biệt giữa kích thước hình ảnh được xoay và kích thước hình ảnh ban đầu của chúng ta và nhân nó với giá trị đó, để xem kích thước của hình ảnh được phóng to là:

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

4) Chúng tôi tiếp tục và tạo hình ảnh được phóng to.

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

5) Cuối cùng, chúng tôi trích xuất một 200x200 vuông từ hình ảnh xoay mở rộng của chúng tôi, sử dụng trung tâm của nó phối như tài liệu tham khảo

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); 

Để phá vỡ xuống ($square_size/2) trả về X và Y tọa độ của điểm trung tâm trong hình ảnh được phóng to. round($enlarged_size/2) trả về số lượng pixel bạn cần để lại từ trung tâm dọc theo trục X, và phía trên trung tâm dọc theo trục Y, để có hình vuông 200x200.


Tôi hy vọng bạn hiểu được logic, mặc dù tôi hiểu sự giải thích của tôi nghe có vẻ hơi mơ hồ, vì vậy xin vui lòng hỏi thêm!

+0

Wow! Cảm ơn lời giải thích chi tiết đó. Giải pháp của bạn hoạt động, nhưng có rất nhiều tổn thất về chất lượng do việc thay đổi kích thước, bạn có thể khắc phục điều đó không? – aNewStart847