ImageCropper.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <?php
  2. namespace App\Services\OCR;
  3. use Intervention\Image\ImageManager;
  4. use Intervention\Image\Drivers\Gd\Driver;
  5. class ImageCropper
  6. {
  7. protected ImageManager $manager;
  8. public function __construct()
  9. {
  10. $this->manager = new ImageManager(new Driver());
  11. }
  12. /**
  13. * Crop answer area from exam paper image
  14. *
  15. * @param string $imagePath Full path to the image
  16. * @param array $coordinates ['x' => int, 'y' => int, 'width' => int, 'height' => int]
  17. * @return string Path to the cropped image
  18. */
  19. public function cropAnswerArea(string $imagePath, array $coordinates): string
  20. {
  21. $image = $this->manager->read($imagePath);
  22. // Get original dimensions
  23. $originalWidth = $image->width();
  24. $originalHeight = $image->height();
  25. // Default answer area: top-left corner (10% width, 15% height)
  26. $x = $coordinates['x'] ?? 0;
  27. $y = $coordinates['y'] ?? 0;
  28. $width = $coordinates['width'] ?? (int)($originalWidth * 0.1);
  29. $height = $coordinates['height'] ?? (int)($originalHeight * 0.15);
  30. // Crop the image
  31. $cropped = $image->crop($width, $height, $x, $y);
  32. // Save to temp directory
  33. $tempPath = storage_path('app/temp/answer_crops');
  34. if (!file_exists($tempPath)) {
  35. mkdir($tempPath, 0755, true);
  36. }
  37. $filename = 'answer_' . basename($imagePath);
  38. $outputPath = $tempPath . '/' . $filename;
  39. $cropped->save($outputPath);
  40. \Log::info('Cropped answer area', [
  41. 'original' => $imagePath,
  42. 'cropped' => $outputPath,
  43. 'dimensions' => "{$width}x{$height} at ({$x},{$y})"
  44. ]);
  45. return $outputPath;
  46. }
  47. /**
  48. * Crop answer area from a specific question's top-left corner
  49. *
  50. * @param string $imagePath Full path to the image
  51. * @param array $questionBbox Question's bounding box from Aliyun API
  52. * @return string Path to the cropped answer area
  53. */
  54. public function cropQuestionAnswerArea(string $imagePath, array $questionBbox): string
  55. {
  56. $image = $this->manager->read($imagePath);
  57. // Question bbox is typically: [{'x': int, 'y': int}, ...]
  58. // We need the top-left corner of the question area
  59. $minX = PHP_INT_MAX;
  60. $minY = PHP_INT_MAX;
  61. $maxX = 0;
  62. $maxY = 0;
  63. foreach ($questionBbox as $point) {
  64. $minX = min($minX, $point['x']);
  65. $minY = min($minY, $point['y']);
  66. $maxX = max($maxX, $point['x']);
  67. $maxY = max($maxY, $point['y']);
  68. }
  69. // Answer area: top-left corner of the question
  70. // Typically 10-15% of question width and height
  71. $questionWidth = $maxX - $minX;
  72. $questionHeight = $maxY - $minY;
  73. $answerWidth = (int)($questionWidth * 0.15);
  74. $answerHeight = (int)($questionHeight * 0.20);
  75. // Crop from top-left of question
  76. $cropped = $image->crop($answerWidth, $answerHeight, $minX, $minY);
  77. // Save to temp directory
  78. $tempPath = storage_path('app/temp/answer_crops');
  79. if (!file_exists($tempPath)) {
  80. mkdir($tempPath, 0755, true);
  81. }
  82. $filename = 'q_answer_' . uniqid() . '.jpg';
  83. $outputPath = $tempPath . '/' . $filename;
  84. $cropped->save($outputPath);
  85. return $outputPath;
  86. }
  87. }