mirror of
https://github.com/moodle/moodle.git
synced 2025-04-14 13:02:07 +02:00
MDL-63349 assignfeedback_editpdf: Rotate submitted image automatically
This commit is contained in:
parent
a31719f91a
commit
4a6edc5767
@ -1130,4 +1130,47 @@ class stored_file {
|
||||
public function compare_to_string($content) {
|
||||
return $this->get_contenthash() === file_storage::hash_from_string($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a rotated image for this stored_file based on exif information.
|
||||
*
|
||||
* @return array|false False when a problem occurs, else the image data and image size.
|
||||
* @since Moodle 3.8
|
||||
*/
|
||||
public function rotate_image() {
|
||||
$content = $this->get_content();
|
||||
$mimetype = $this->get_mimetype();
|
||||
|
||||
if ($mimetype === "image/jpeg" && function_exists("exif_read_data")) {
|
||||
$exif = @exif_read_data("data://image/jpeg;base64," . base64_encode($content));
|
||||
if (isset($exif['ExifImageWidth']) && isset($exif['ExifImageLength']) && isset($exif['Orientation'])) {
|
||||
$rotation = [
|
||||
3 => -180,
|
||||
6 => -90,
|
||||
8 => -270,
|
||||
];
|
||||
$orientation = $exif['Orientation'];
|
||||
if ($orientation !== 1) {
|
||||
$source = @imagecreatefromstring($content);
|
||||
$data = @imagerotate($source, $rotation[$orientation], 0);
|
||||
if (!empty($data)) {
|
||||
if ($orientation == 1 || $orientation == 3) {
|
||||
$size = [
|
||||
'width' => $exif["ExifImageWidth"],
|
||||
'height' => $exif["ExifImageLength"],
|
||||
];
|
||||
} else {
|
||||
$size = [
|
||||
'height' => $exif["ExifImageWidth"],
|
||||
'width' => $exif["ExifImageLength"],
|
||||
];
|
||||
}
|
||||
imagedestroy($source);
|
||||
return [$data, $size];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return [false, false];
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.8 ===
|
||||
|
||||
* The rotate_image function has been added to the stored_file class (MDL-63349)
|
||||
* The yui checknet module is removed. Call \core\session\manager::keepalive instead.
|
||||
* The generate_uuid() function has been deprecated. Please use \core\uuid::generate() instead.
|
||||
* Remove lib/pear/auth/RADIUS.php (MDL-65746)
|
||||
|
@ -56,6 +56,10 @@ class document_services {
|
||||
const STAMPS_FILEAREA = 'stamps';
|
||||
/** Filename for combined pdf */
|
||||
const COMBINED_PDF_FILENAME = 'combined.pdf';
|
||||
/** Temporary place to save JPG Image to PDF file */
|
||||
const TMP_JPG_TO_PDF_FILEAREA = 'tmp_jpg_to_pdf';
|
||||
/** Temporary place to save (Automatically) Rotated JPG FILE */
|
||||
const TMP_ROTATED_JPG_FILEAREA = 'tmp_rotated_jpg';
|
||||
/** Hash of blank pdf */
|
||||
const BLANK_PDF_HASH = '4c803c92c71f21b423d13de570c8a09e0a31c718';
|
||||
|
||||
@ -187,9 +191,28 @@ EOD;
|
||||
$pluginfiles = $plugin->get_files($submission, $user);
|
||||
foreach ($pluginfiles as $filename => $file) {
|
||||
if ($file instanceof \stored_file) {
|
||||
if ($file->get_mimetype() === 'application/pdf') {
|
||||
$mimetype = $file->get_mimetype();
|
||||
// PDF File, no conversion required.
|
||||
if ($mimetype === 'application/pdf') {
|
||||
$files[$filename] = $file;
|
||||
} else if ($convertedfile = $converter->start_conversion($file, 'pdf')) {
|
||||
} else if ($plugin->allow_image_conversion() && $mimetype === "image/jpeg") {
|
||||
// Rotates image based on the EXIF value.
|
||||
list ($rotateddata, $size) = $file->rotate_image();
|
||||
if ($rotateddata) {
|
||||
$file = self::save_rotated_image_file($assignment, $userid, $attemptnumber,
|
||||
$rotateddata, $filename);
|
||||
}
|
||||
// Save as PDF file if there is no available converter.
|
||||
if (!$converter->can_convert_format_to('jpg', 'pdf')) {
|
||||
$pdffile = self::save_jpg_to_pdf($assignment, $userid, $attemptnumber, $file, $size);
|
||||
if ($pdffile) {
|
||||
$files[$filename] = $pdffile;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The file has not been converted to PDF, try to convert it to PDF.
|
||||
if (!isset($files[$filename])
|
||||
&& $convertedfile = $converter->start_conversion($file, 'pdf')) {
|
||||
$files[$filename] = $convertedfile;
|
||||
}
|
||||
} else if ($converter->can_convert_format_to('html', 'pdf')) {
|
||||
@ -967,4 +990,83 @@ EOD;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert jpg file to pdf file
|
||||
* @param int|\assign $assignment Assignment
|
||||
* @param int $userid User ID
|
||||
* @param int $attemptnumber Attempt Number
|
||||
* @param \stored_file $file file to save
|
||||
* @param null|array $size size of image
|
||||
* @return \stored_file
|
||||
* @throws \file_exception
|
||||
* @throws \stored_file_creation_exception
|
||||
*/
|
||||
private static function save_jpg_to_pdf($assignment, $userid, $attemptnumber, $file, $size=null) {
|
||||
// Temporary file.
|
||||
$filename = $file->get_filename();
|
||||
$tmpdir = make_temp_directory('assignfeedback_editpdf' . DIRECTORY_SEPARATOR
|
||||
. self::TMP_JPG_TO_PDF_FILEAREA . DIRECTORY_SEPARATOR
|
||||
. self::hash($assignment, $userid, $attemptnumber));
|
||||
$tempfile = $tmpdir . DIRECTORY_SEPARATOR . $filename . ".pdf";
|
||||
// Determine orientation.
|
||||
$orientation = 'P';
|
||||
if (!empty($size['width']) && !empty($size['height'])) {
|
||||
if ($size['width'] > $size['height']) {
|
||||
$orientation = 'L';
|
||||
}
|
||||
}
|
||||
// Save JPG image to PDF file.
|
||||
$pdf = new pdf();
|
||||
$pdf->SetHeaderMargin(0);
|
||||
$pdf->SetFooterMargin(0);
|
||||
$pdf->SetMargins(0, 0, 0, true);
|
||||
$pdf->setPrintFooter(false);
|
||||
$pdf->setPrintHeader(false);
|
||||
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
|
||||
$pdf->AddPage($orientation);
|
||||
$pdf->SetAutoPageBreak(false);
|
||||
// Width has to be define here to fit into A4 page. Otherwise the image will be inserted with original size.
|
||||
if ($orientation == 'P') {
|
||||
$pdf->Image('@' . $file->get_content(), 0, 0, 210);
|
||||
} else {
|
||||
$pdf->Image('@' . $file->get_content(), 0, 0, 297);
|
||||
}
|
||||
$pdf->setPageMark();
|
||||
$pdf->save_pdf($tempfile);
|
||||
$filearea = self::TMP_JPG_TO_PDF_FILEAREA;
|
||||
$pdffile = self::save_file($assignment, $userid, $attemptnumber, $filearea, $tempfile);
|
||||
if (file_exists($tempfile)) {
|
||||
unlink($tempfile);
|
||||
rmdir($tmpdir);
|
||||
}
|
||||
return $pdffile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save rotated image data to file.
|
||||
* @param int|\assign $assignment Assignment
|
||||
* @param int $userid User ID
|
||||
* @param int $attemptnumber Attempt Number
|
||||
* @param resource $rotateddata image data to save
|
||||
* @param string $filename name of the image file
|
||||
* @return \stored_file
|
||||
* @throws \file_exception
|
||||
* @throws \stored_file_creation_exception
|
||||
*/
|
||||
private static function save_rotated_image_file($assignment, $userid, $attemptnumber, $rotateddata, $filename) {
|
||||
$filearea = self::TMP_ROTATED_JPG_FILEAREA;
|
||||
$tmpdir = make_temp_directory('assignfeedback_editpdf' . DIRECTORY_SEPARATOR
|
||||
. $filearea . DIRECTORY_SEPARATOR
|
||||
. self::hash($assignment, $userid, $attemptnumber));
|
||||
$tempfile = $tmpdir . DIRECTORY_SEPARATOR . basename($filename);
|
||||
imagejpeg($rotateddata, $tempfile);
|
||||
$newfile = self::save_file($assignment, $userid, $attemptnumber, $filearea, $tempfile);
|
||||
if (file_exists($tempfile)) {
|
||||
unlink($tempfile);
|
||||
rmdir($tmpdir);
|
||||
}
|
||||
return $newfile;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -637,4 +637,12 @@ class assign_submission_file extends assign_submission_plugin {
|
||||
|
||||
return $sets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the plugin allows image file conversion
|
||||
* @return bool
|
||||
*/
|
||||
public function allow_image_conversion() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -146,4 +146,12 @@ abstract class assign_submission_plugin extends assign_plugin {
|
||||
public function submission_is_empty(stdClass $data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the plugin allows image file conversion
|
||||
* @return bool
|
||||
*/
|
||||
public function allow_image_conversion() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
This files describes API changes in the assign code.
|
||||
=== 3.8 ===
|
||||
* The allow_image_conversion method has been added to the submissionplugins. It determines whether the submission plugin
|
||||
allows image conversion or not. By default conversion is not allowed (except when overwritten in the submission plugin)
|
||||
* Webservice function mod_assign_get_submission_status, return value 'warnofungroupedusers', changed from PARAM_BOOL to PARAM_ALPHA. See the description for possible values.
|
||||
* The following functions have been finally deprecated and can not be used anymore:
|
||||
* assign_scale_used()
|
||||
|
Loading…
x
Reference in New Issue
Block a user