/** * @dataProvider getParamsForWatermarks * @covers Imbo\Image\Transformation\Watermark::transform */ public function testApplyToImageTopLeftWithOnlyWidthAndDefaultWatermark($params, $colors) { $blob = file_get_contents(FIXTURES_DIR . '/white.png'); $image = new Image(); $image->setBlob($blob); $image->setWidth($this->width); $image->setHeight($this->height); $transformation = $this->getTransformation(); $transformation->setDefaultImage($this->watermarkImg); $expectedWatermark = $this->watermarkImg; if (isset($params['img'])) { $expectedWatermark = $params['img']; } $storage = $this->getMock('Imbo\\Storage\\StorageInterface'); $storage->expects($this->once())->method('getImage')->with('someUser', $expectedWatermark)->will($this->returnValue(file_get_contents(FIXTURES_DIR . '/black.png'))); $request = $this->getMock('Imbo\\Http\\Request\\Request'); $request->expects($this->once())->method('getUser')->will($this->returnValue('someUser')); $event = new Event(); $event->setArguments(['image' => $image, 'params' => $params, 'storage' => $storage, 'request' => $request]); $imagick = new Imagick(); $imagick->readImageBlob($blob); $transformation->setImagick($imagick)->transform($event); foreach ($colors as $c) { $this->verifyColor($imagick, $c['x'], $c['y'], $c['colors']); } }
/** * Prepare an image * * This method should prepare an image object from php://input. The method must also figure out * the width, height, mime type and extension of the image. * * @param EventInterface $event The current event * @throws ImageException */ public function prepareImage(EventInterface $event) { $request = $event->getRequest(); // Fetch image data from input $imageBlob = $request->getContent(); if (empty($imageBlob)) { $e = new ImageException('No image attached', 400); $e->setImboErrorCode(Exception::IMAGE_NO_IMAGE_ATTACHED); throw $e; } // Open the image with imagick to fetch the mime type $imagick = new Imagick(); try { $imagick->readImageBlob($imageBlob); $mime = $imagick->getImageMimeType(); $size = $imagick->getImageGeometry(); } catch (ImagickException $e) { $e = new ImageException('Invalid image', 415); $e->setImboErrorCode(Exception::IMAGE_INVALID_IMAGE); throw $e; } if (!Image::supportedMimeType($mime)) { $e = new ImageException('Unsupported image type: ' . $mime, 415); $e->setImboErrorCode(Exception::IMAGE_UNSUPPORTED_MIMETYPE); throw $e; } // Store relevant information in the image instance and attach it to the request $image = new Image(); $image->setMimeType($mime)->setExtension(Image::getFileExtension($mime))->setBlob($imageBlob)->setWidth($size['width'])->setHeight($size['height'])->setOriginalChecksum(md5($imageBlob)); $request->setImage($image); }
/** * @covers Imbo\Image\Transformation\SmartSize::transform * @dataProvider getSmartSizeArguments */ public function testSmartSize($imageDimensions, $params, $cropParams) { $imagick = $this->getMock('Imagick'); $imagick->expects($this->any())->method('cropImage')->with($cropParams['width'], $cropParams['height'], $cropParams['left'], $cropParams['top']); $image = new Image(); $image->setWidth($imageDimensions['width']); $image->setHeight($imageDimensions['height']); $response = new Response(); $event = $this->getMock('Imbo\\EventManager\\Event'); $event->expects($this->at(0))->method('getArgument')->with('image')->will($this->returnValue($image)); $event->expects($this->at(1))->method('getArgument')->with('params')->will($this->returnValue($params)); $event->expects($this->at(2))->method('getResponse')->will($this->returnValue($response)); $transformation = new SmartSize(); $transformation->setImagick($imagick); $transformation->transform($event); }
/** * Handle GET and HEAD requests * * @param EventInterface */ public function getImage(EventInterface $event) { $request = $event->getRequest(); $response = $event->getResponse(); $eventManager = $event->getManager(); $publicKey = $request->getPublicKey(); $imageIdentifier = $request->getImageIdentifier(); $image = new Model\Image(); $image->setImageIdentifier($imageIdentifier)->setPublicKey($publicKey); $response->setModel($image); // Load image details from database $eventManager->trigger('db.image.load'); // Set a long max age as the image itself won't change $response->setMaxAge(31536000); // Custom Imbo headers, based on original $response->headers->add(['X-Imbo-OriginalMimeType' => $image->getMimeType(), 'X-Imbo-OriginalWidth' => $image->getWidth(), 'X-Imbo-OriginalHeight' => $image->getHeight(), 'X-Imbo-OriginalFileSize' => $image->getFilesize(), 'X-Imbo-OriginalExtension' => $image->getExtension()]); // Trigger loading of the image $eventManager->trigger('storage.image.load'); // Trigger possible image transformations $eventManager->trigger('image.transform'); }
/** * @covers Imbo\Model\Image::getData */ public function testGetData() { $metadata = ['foo' => 'bar', 'bar' => 'foo']; $mimeType = 'image/png'; $blob = 'some string'; $filesize = strlen($blob); $checksum = md5($blob); $extension = 'png'; $width = 123; $height = 234; $added = new DateTime(); $updated = new DateTime(); $user = '******'; $identifier = 'identifier'; $this->image->setMetadata($metadata)->setMimeType($mimeType)->setBlob($blob)->setExtension($extension)->setWidth($width)->setHeight($height)->setAddedDate($added)->setUpdatedDate($updated)->setUser($user)->setImageIdentifier($identifier)->hasBeenTransformed(true)->setOriginalChecksum($checksum); $this->assertSame(['filesize' => $filesize, 'mimeType' => $mimeType, 'extension' => $extension, 'metadata' => $metadata, 'width' => $width, 'height' => $height, 'addedDate' => $added, 'updatedDate' => $updated, 'user' => $user, 'imageIdentifier' => $identifier, 'checksum' => $checksum, 'originalChecksum' => $checksum, 'hasBeenTransformed' => true], $this->image->getData()); }
/** * Load images * * @param EventInterface $event An event instance */ public function loadImages(EventInterface $event) { $query = $this->getImagesQuery(); $params = $event->getRequest()->query; $returnMetadata = false; if ($params->has('page')) { $query->page($params->get('page')); } if ($params->has('limit')) { $query->limit($params->get('limit')); } if ($params->has('metadata')) { $query->returnMetadata($params->get('metadata')); $returnMetadata = true; } if ($params->has('from')) { $query->from($params->get('from')); } if ($params->has('to')) { $query->to($params->get('to')); } if ($params->has('sort')) { $sort = $params->get('sort'); if (is_array($sort)) { $query->sort($sort); } } if ($params->has('ids')) { $ids = $params->get('ids'); if (is_array($ids)) { $query->imageIdentifiers($ids); } } if ($params->has('checksums')) { $checksums = $params->get('checksums'); if (is_array($checksums)) { $query->checksums($checksums); } } if ($params->has('originalChecksums')) { $checksums = $params->get('originalChecksums'); if (is_array($checksums)) { $query->originalChecksums($checksums); } } $publicKey = $event->getRequest()->getPublicKey(); $response = $event->getResponse(); $database = $event->getDatabase(); // Create the model and set some pagination values $model = new Model\Images(); $model->setLimit($query->limit())->setPage($query->page()); $images = $database->getImages($publicKey, $query, $model); $modelImages = array(); foreach ($images as $image) { $entry = new Model\Image(); $entry->setFilesize($image['size'])->setWidth($image['width'])->setHeight($image['height'])->setPublicKey($publicKey)->setImageIdentifier($image['imageIdentifier'])->setChecksum($image['checksum'])->setOriginalChecksum(isset($image['originalChecksum']) ? $image['originalChecksum'] : null)->setMimeType($image['mime'])->setExtension($image['extension'])->setAddedDate($image['added'])->setUpdatedDate($image['updated']); if ($returnMetadata) { $entry->setMetadata($image['metadata']); } $modelImages[] = $entry; } // Add images to the model $model->setImages($modelImages); if ($params->has('fields')) { $fields = $params->get('fields'); if (is_array($fields)) { $model->setFields($fields); } } $lastModified = $database->getLastModified($publicKey); $response->setModel($model)->setLastModified($lastModified); }
/** * Resize the image * * @param Image $image The image to resize * @param int $targetWidth The resize target width * @param int $tartHeight The resize target height */ private function resize(Image $image, $targetWidth, $targetHeight) { $this->imagick->setOption('jpeg:size', $targetWidth . 'x' . $targetHeight); $this->imagick->thumbnailImage($targetWidth, $targetHeight); $image->setWidth($targetWidth)->setHeight($targetHeight)->hasBeenTransformed(true); }
/** * {@inheritdoc} */ public function load($publicKey, $imageIdentifier, Image $image) { $row = $this->getImageProperties($publicKey, $imageIdentifier); $image->setWidth($row['width'])->setHeight($row['height'])->setFilesize($row['size'])->setMimeType($row['mime'])->setExtension($row['extension'])->setAddedDate(new DateTime('@' . $row['added'], new DateTimeZone('UTC')))->setUpdatedDate(new DateTime('@' . $row['updated'], new DateTimeZone('UTC'))); return true; }
/** * Insert some images to test the query functionality * * All images added is owned by "publickey", unless $alternatePublicKey is set to true * * @param boolean $alternatePublicKey Whether to alternate between 'publickey' and * 'publickey2' when inserting images * @return array Returns an array with two elements where the first is the timestamp of when * the first image was added, and the second is the timestamp of when the last * image was added */ private function insertImages($alternatePublicKey = false) { $now = time(); $start = $now; $images = array(); foreach (array('image.jpg', 'image.png', 'image1.png', 'image2.png', 'image3.png', 'image4.png') as $i => $fileName) { $path = FIXTURES_DIR . '/' . $fileName; $info = getimagesize($path); $publicKey = 'publickey'; if ($alternatePublicKey && $i % 2 === 0) { $publickey2 = 'publickey2'; } $image = new Image(); $image->setMimeType($info['mime'])->setExtension(substr($fileName, strrpos($fileName, '.') + 1))->setWidth($info[0])->setHeight($info[1])->setBlob(file_get_contents($path))->setAddedDate(new DateTime('@' . $now++, new DateTimeZone('UTC')))->setOriginalChecksum(md5_file($path)); $imageIdentifier = md5($image->getBlob()); // Add the image $this->adapter->insertImage($publicKey, $imageIdentifier, $image); // Insert some metadata $this->adapter->updateMetadata($publicKey, $imageIdentifier, array('key' . $i => 'value' . $i)); } // Remove the last increment to get the timestamp for when the last image was added $end = $now - 1; return array($start, $end); }
/** * @dataProvider getMimeTypes */ public function testSetsTheCorrectMimeTypeWhenAMappedOneIsUsed($set, $get) { $this->image->setMimeType($set); $this->assertSame($get, $this->image->getMimeType()); }
/** * @dataProvider getOriginalMimeTypes * @covers Imbo\Http\Response\ResponseFormatter::negotiate */ public function testUsesTheOriginalMimeTypeOfTheImageIfConfigDisablesContentNegotiationForImages($originalMimeType, $expectedFormatter) { // Use a real object since the code we are testing uses get_class(), which won't work as // expected when the object used is a mock $image = new Image(); $image->setMimeType($originalMimeType); $requestHeaders = $this->getMock('Symfony\\Component\\HttpFoundation\\HeaderBag'); $this->request->headers = $requestHeaders; $this->contentNegotiation->expects($this->any())->method('isAcceptable')->will($this->returnValue(1)); $this->response->expects($this->never())->method('setVary'); $this->response->expects($this->once())->method('getModel')->will($this->returnValue($image)); $event = $this->getMock('Imbo\\EventManager\\Event'); $event->expects($this->any())->method('getRequest')->will($this->returnValue($this->request)); $event->expects($this->any())->method('getResponse')->will($this->returnValue($this->response)); $event->expects($this->any())->method('getConfig')->will($this->returnValue(['contentNegotiateImages' => false])); $this->responseFormatter->negotiate($event); $this->assertSame($expectedFormatter, $this->responseFormatter->getFormatter()); }
/** * @covers Imbo\EventListener\ExifMetadata::__construct * @covers Imbo\EventListener\ExifMetadata::populate * @covers Imbo\EventListener\ExifMetadata::save */ public function testCanGetAndSaveProperties() { $listener = new ExifMetadata(); $publicKey = 'foobar'; $image = new Image(); $image->setBlob(file_get_contents(FIXTURES_DIR . '/exif-logo.jpg')); $request = $this->getMock('Imbo\\Http\\Request\\Request'); $request->expects($this->exactly(2))->method('getImage')->will($this->returnValue($image)); $request->expects($this->once())->method('getPublicKey')->will($this->returnValue($publicKey)); $database = $this->getMock('Imbo\\Database\\DatabaseInterface'); $database->expects($this->once())->method('updateMetadata')->with($this->equalTo($publicKey), $this->equalTo('753e11e00522ff1e95600d8f91c74e8e'), $this->arrayHasKey('gps:location')); $event = $this->getMock('Imbo\\EventManager\\Event'); $event->expects($this->exactly(2))->method('getRequest')->will($this->returnValue($request)); $event->expects($this->once())->method('getDatabase')->will($this->returnValue($database)); $properties = $listener->populate($event); $this->assertSame('SAMSUNG', $properties['exif:Make']); $this->assertSame('GT-I9100', $properties['exif:Model']); $listener->save($event); }
/** * Draw border inside (on top of) the existing image * * @param string $color * @param integer $borderWidth * @param integer $borderHeight * @param Image $image */ private function drawBorderInside($color, $borderWidth, $borderHeight, Image $image) { $imageWidth = $image->getWidth(); $imageHeight = $image->getHeight(); $rect = new ImagickDraw(); $rect->setStrokeColor($color); $rect->setFillColor($color); $rect->setStrokeAntialias(false); // Left $rect->rectangle(0, 0, $borderWidth - 1, $imageHeight); // Right $rect->rectangle($imageWidth - $borderWidth, 0, $imageWidth, $imageHeight); // Top $rect->rectangle(0, 0, $imageWidth, $borderHeight - 1); // Bottom $rect->rectangle(0, $imageHeight - $borderHeight, $imageWidth, $imageHeight); // Draw the border $this->imagick->drawImage($rect); }
/** * Fetch POIs from metadata for the image * * @param EventInterface $event * @param Image $image * @return array Array with POIs */ private function getPoisFromMetadata(EventInterface $event, Image $image) { $metadata = $event->getDatabase()->getMetadata($image->getUser(), $image->getImageIdentifier()); return isset($metadata['poi']) ? $metadata['poi'] : []; }
/** * {@inheritdoc} */ public function generate(Image $image) { return md5($image->getBlob()); }