/** * {@inheritdoc} */ public function transform(File $file, $self = false) { if ($file->type() !== 'image/jpeg') { return $file; // Exif only in JPGs } $width = $file->width(); $height = $file->height(); $exif = $file->exif(); $this->setConfig('degrees', 0); // Reset degrees $options = array('dest_w' => $width, 'dest_h' => $height, 'source_w' => $width, 'source_h' => $height, 'quality' => $this->getConfig('quality'), 'overwrite' => $self, 'target' => sprintf('%s-exif-%s', $file->name(), $exif['orientation'] ?: 0)); switch ($exif['orientation']) { case 2: // Flip horizontally $options['source_x'] = $width; $options['source_w'] = -$width; break; case 3: // Rotate 180 degrees $this->setConfig('degrees', 180); break; case 4: case 5: case 7: // Flip vertically $options['source_y'] = $height; $options['source_h'] = -$height; // Also rotate -90 degrees for orientation 5 if ($exif['orientation'] == 5) { $this->setConfig('degrees', -90); } // Or rotate 90 degrees for orientation 7 if ($exif['orientation'] == 7) { $this->setConfig('degrees', 90); } break; case 6: $this->setConfig('degrees', -90); break; case 8: $this->setConfig('degrees', 90); break; default: // Correct, strip exif only break; } if ($degrees = $this->getConfig('degrees')) { $options['postCallback'] = array($this, 'rotate'); } return $this->_process($file, $options); }
/** * Transform the image using the defined options. * * @param \Transit\File $file * @param array $options * @return \Transit\File * @throws \DomainException */ protected function _process(File $file, array $options) { if (!$file->isImage()) { throw new DomainException(sprintf('%s is not a valid image', $file->basename())); } $sourcePath = $file->path(); $mimeType = $file->type(); // Create an image to work with switch ($mimeType) { case 'image/gif': $sourceImage = imagecreatefromgif($sourcePath); break; case 'image/png': $sourceImage = imagecreatefrompng($sourcePath); break; case 'image/jpg': case 'image/jpeg': case 'image/pjpeg': $sourceImage = imagecreatefromjpeg($sourcePath); break; default: throw new DomainException(sprintf('%s can not be transformed', $mimeType)); break; } // Gather options $options = $options + array('dest_x' => 0, 'dest_y' => 0, 'dest_w' => null, 'dest_h' => null, 'source_x' => 0, 'source_y' => 0, 'source_w' => $file->width(), 'source_h' => $file->height(), 'quality' => 100, 'overwrite' => false, 'target' => ''); $targetImage = imagecreatetruecolor($options['dest_w'], $options['dest_h']); // If gif/png allow transparencies if ($mimeType === 'image/gif' || $mimeType === 'image/png') { imagealphablending($targetImage, false); imagesavealpha($targetImage, true); imagefilledrectangle($targetImage, 0, 0, $options['dest_w'], $options['dest_h'], imagecolorallocatealpha($targetImage, 255, 255, 255, 127)); } // Lets take our source and apply it to the temporary file and resize imagecopyresampled($targetImage, $sourceImage, $options['dest_x'], $options['dest_y'], $options['source_x'], $options['source_y'], $options['dest_w'], $options['dest_h'], $options['source_w'], $options['source_h']); // Now write the transformed image to the server if ($options['overwrite']) { $options['target'] = $file->name(); } else { if (!$options['target']) { $class = explode('\\', get_class($this)); $class = str_replace('transformer', '', strtolower(end($class))); $options['target'] = sprintf('%s-%s-%sx%s', $file->name(), $class, round($options['dest_w']), round($options['dest_h'])); } } $targetPath = sprintf('%s%s.%s', $file->dir(), $options['target'], $file->ext()); switch ($mimeType) { case 'image/gif': imagegif($targetImage, $targetPath); break; case 'image/png': imagepng($targetImage, $targetPath); break; case 'image/jpg': case 'image/jpeg': case 'image/pjpeg': imagejpeg($targetImage, $targetPath, $options['quality']); break; } // Clear memory imagedestroy($sourceImage); imagedestroy($targetImage); return new File($targetPath); }
/** * Find a valid target path taking into account file existence and overwriting. * * @param \Transit\File|string $file * @param bool $overwrite * @return string */ public function findDestination($file, $overwrite = false) { if ($file instanceof File) { $name = $file->name(); $ext = '.' . $file->ext(); } else { $name = $file; $ext = ''; if ($pos = mb_strrpos($name, '.')) { $ext = mb_substr($name, $pos, mb_strlen($name) - $pos); $name = mb_substr($name, 0, $pos); } } $target = $this->_directory . $name . $ext; if (!$overwrite) { $no = 1; while (file_exists($target)) { $target = sprintf('%s%s-%s%s', $this->_directory, $name, $no, $ext); $no++; } } return $target; }
/** * Test that move() doesn't overwrite files but appends an incremented number. */ public function testMoveNoOverwrite() { $testPath = TEST_DIR . '/vertical-test.jpg'; $movePath = TEMP_DIR . '/vertical-test-1.jpg'; copy($this->baseFile, $testPath); $file = new File($testPath); $this->assertFalse(file_exists($movePath)); $this->assertEquals('vertical-test', $file->name()); $file->move(TEMP_DIR); $this->assertTrue(file_exists($movePath)); $this->assertEquals('vertical-test-1', $file->name()); $file->delete(); }