3 namespace Drupal\Tests\file_mdm_exif\Kernel;
5 use Drupal\file_mdm\FileMetadataInterface;
6 use Drupal\Tests\file_mdm\Kernel\FileMetadataManagerTestBase;
7 use lsolesen\pel\PelEntryAscii;
8 use lsolesen\pel\PelEntryRational;
9 use lsolesen\pel\PelEntrySRational;
12 * Tests that File Metadata EXIF plugin works properly.
14 * @group File Metadata
16 class FileMetadataExifTest extends FileMetadataManagerTestBase {
23 public static $modules = [
35 public function setUp() {
37 $this->installConfig(['file_mdm_exif']);
43 public function testExifPlugin() {
44 // Prepare a copy of test files.
45 file_unmanaged_copy(drupal_get_path('module', 'simpletest') . '/files/image-test.jpg', 'public://', FILE_EXISTS_REPLACE);
46 file_unmanaged_copy(drupal_get_path('module', 'simpletest') . '/files/image-test.png', 'public://', FILE_EXISTS_REPLACE);
47 file_unmanaged_copy(drupal_get_path('module', 'file_mdm') . '/tests/files/test-exif.jpeg', 'public://', FILE_EXISTS_REPLACE);
48 file_unmanaged_copy(drupal_get_path('module', 'file_mdm') . '/tests/files/test-exif.jpeg', 'temporary://', FILE_EXISTS_REPLACE);
49 // The image files that will be tested.
52 // Pass a path instead of the URI.
53 'uri' => drupal_get_path('module', 'file_mdm') . '/tests/files/test-exif.jpeg',
59 ['ShutterSpeedValue', [106, 32]],
60 ['ApertureValue', [128, 32]],
61 [['exif', 'aperturevalue'], [128, 32]],
62 [[2, 'aperturevalue'], [128, 32]],
63 [['exif', 0x9202], [128, 32]],
64 [[2, 0x9202], [128, 32]],
69 'uri' => 'public://test-exif.jpeg',
73 ['ShutterSpeedValue', [106, 32]],
77 // Remote storage file. Let the file be copied to a local temp copy.
78 'uri' => 'dummy-remote://test-exif.jpeg',
79 'copy_to_temp' => TRUE,
83 ['ShutterSpeedValue', [106, 32]],
87 // JPEG Image with GPS data.
88 'uri' => drupal_get_path('module', 'file_mdm') . '/tests/files/1024-2006_1011_093752.jpg',
92 ['FocalLength', [8513, 256]],
93 ['GPSLatitudeRef', 'S'],
94 ['GPSLatitude', [[33, 1], [51, 1], [2191, 100]]],
95 ['GPSLongitudeRef', 'E'],
96 ['GPSLongitude', [[151, 1], [13, 1], [1173, 100]]],
100 // JPEG Image with no EXIF data.
101 'uri' => 'public://image-test.jpg',
107 'uri' => drupal_get_path('module', 'file_mdm') . '/tests/files/sample-1.tiff',
111 ['BitsPerSample', [8, 8, 8, 8]],
115 // PNG should not have any data.
116 'uri' => 'public://image-test.png',
122 $fmdm = $this->container->get('file_metadata_manager');
124 // Walk through test files.
125 foreach ($image_files as $image_file) {
126 $file_metadata = $fmdm->uri($image_file['uri']);
127 if (!$file_metadata) {
128 $this->fail("File not found: {$image_file['uri']}");
131 if (isset($image_file['copy_to_temp'])) {
132 $file_metadata->copyUriToTemp();
134 $this->assertEqual($image_file['count_keys'], $this->countMetadataKeys($file_metadata, 'exif'));
135 foreach ($image_file['test_keys'] as $test) {
136 $entry = $file_metadata->getMetadata('exif', $test[0]);
137 $this->assertEqual($test[1], $entry ? $entry['value'] : NULL);
141 // Test loading metadata from an in-memory object.
142 $file_metadata_from = $fmdm->uri($image_files[0]['uri']);
143 $metadata = $file_metadata_from->getMetadata('exif');
144 $new_file_metadata = $fmdm->uri('public://test-output.jpeg');
145 $new_file_metadata->loadMetadata('exif', $metadata);
146 $this->assertEqual($image_files[0]['count_keys'], $this->countMetadataKeys($new_file_metadata, 'exif'));
147 foreach ($image_files[0]['test_keys'] as $test) {
148 $entry = $file_metadata->getMetadata('exif', $test[0]);
149 $this->assertEqual($test[1], $new_file_metadata->getMetadata('exif', $test[0])['value']);
152 // Test removing metadata.
153 $fmdm->release($image_files[0]['uri']);
154 $this->assertFalse($fmdm->has($image_files[0]['uri']));
155 $file_metadata = $fmdm->uri($image_files[0]['uri']);
156 $this->assertEqual($image_files[0]['count_keys'], $this->countMetadataKeys($file_metadata, 'exif'));
157 $this->assertTrue($file_metadata->removeMetadata('exif', 'shutterspeedValue'));
158 $this->assertTrue($file_metadata->removeMetadata('exif', 'apertureValue'));
159 $this->assertFalse($file_metadata->removeMetadata('exif', 'bar'));
160 $this->assertEqual($image_files[0]['count_keys'] - 2, $this->countMetadataKeys($file_metadata, 'exif'));
161 $this->assertNull($file_metadata->getMetadata('exif', 'shutterspeedValue'));
162 $this->assertNull($file_metadata->getMetadata('exif', 'apertureValue'));
163 $this->assertNotNull($file_metadata->getMetadata('exif', 'orientation'));
167 * Test writing metadata to JPEG file.
169 public function testJpegExifSaveToFile() {
170 $fmdm = $this->container->get('file_metadata_manager');
172 // Copy test file to public://.
173 file_unmanaged_copy(drupal_get_path('module', 'image_effects') . '/tests/images/portrait-painting.jpg', 'public://', FILE_EXISTS_REPLACE);
174 $file_uri = 'public://portrait-painting.jpg';
175 $file_metadata = $fmdm->uri($file_uri);
177 // Check values via exif_read_data before operations.
178 $data = @exif_read_data($file_uri);
179 $this->assertEqual(8, $data['Orientation']);
180 $this->assertFalse(isset($data['Artist']));
181 $this->assertEqual('Canon', $data['Make']);
182 $this->assertEqual(800, $data['ISOSpeedRatings']);
184 // Change the Orientation tag from IFD0.
185 $this->assertEqual(8, $file_metadata->getMetadata('exif', 'orientation')['value']);
186 $this->assertTrue($file_metadata->setMetadata('exif', 'orientation', 4));
187 $this->assertEqual(4, $file_metadata->getMetadata('exif', 'orientation')['value']);
188 // Add the Artist tag to IFD0.
189 $this->assertEqual(48, $this->countMetadataKeys($file_metadata, 'exif'));
190 $this->assertNull($file_metadata->getMetadata('exif', 'artist'));
191 $artist_tag = $this->container->get('file_mdm_exif.tag_mapper')->resolveKeyToIfdAndTag('artist');
192 $artist = new PelEntryAscii($artist_tag['tag'], 'shot by foo!');
193 $file_metadata->setMetadata('exif', 'artist', $artist);
194 $this->assertEqual('shot by foo!', $file_metadata->getMetadata('exif', 'artist')['value']);
195 $this->assertEqual(49, $this->countMetadataKeys($file_metadata, 'exif'));
196 // Setting an unknown tag leads to failure.
197 $this->assertFalse($file_metadata->setMetadata('exif', 'bar', 'qux'));
198 // Remove the Make tag from IFD0.
199 $this->assertEqual('Canon', $file_metadata->getMetadata('exif', 'make')['value']);
200 $this->assertTrue($file_metadata->removeMetadata('exif', 'make'));
201 $this->assertNull($file_metadata->getMetadata('exif', 'make'));
202 $this->assertEqual(48, $this->countMetadataKeys($file_metadata, 'exif'));
204 // Add the ImageDescription tag to IFD1.
205 $this->assertNull($file_metadata->getMetadata('exif', [1, 'imagedescription']));
206 $desc_tag = $this->container->get('file_mdm_exif.tag_mapper')->resolveKeyToIfdAndTag([1, 'imagedescription']);
207 $desc = new PelEntryAscii($desc_tag['tag'], 'awesome!');
208 $file_metadata->setMetadata('exif', [1, 'imagedescription'], $desc);
209 $this->assertEqual('awesome!', $file_metadata->getMetadata('exif', [1, 'imagedescription'])['value']);
210 $this->assertEqual(49, $this->countMetadataKeys($file_metadata, 'exif'));
211 // Remove the Compression tag from IFD1.
212 $this->assertEqual(6, $file_metadata->getMetadata('exif', [1, 'compression'])['value']);
213 $this->assertTrue($file_metadata->removeMetadata('exif', [1, 'compression']));
214 $this->assertNull($file_metadata->getMetadata('exif', [1, 'compression']));
215 $this->assertEqual(48, $this->countMetadataKeys($file_metadata, 'exif'));
217 // Add the BrightnessValue tag to EXIF.
218 $this->assertNull($file_metadata->getMetadata('exif', ['exif', 'brightnessvalue']));
219 $brightness_tag = $this->container->get('file_mdm_exif.tag_mapper')->resolveKeyToIfdAndTag(['exif', 'brightnessvalue']);
220 $brightness = new PelEntrySRational($brightness_tag['tag'], [12, 4]);
221 $file_metadata->setMetadata('exif', ['exif', 'brightnessvalue'], $brightness);
222 $this->assertEqual('12/4', $file_metadata->getMetadata('exif', ['exif', 'brightnessvalue'])['text']);
223 $this->assertEqual(49, $this->countMetadataKeys($file_metadata, 'exif'));
224 // Remove the ISOSpeedRatings tag from EXIF.
225 $this->assertEqual(800, $file_metadata->getMetadata('exif', ['exif', 'isospeedratings'])['value']);
226 $this->assertTrue($file_metadata->removeMetadata('exif', ['exif', 'isospeedratings']));
227 $this->assertNull($file_metadata->getMetadata('exif', ['exif', 'isospeedratings']));
228 $this->assertEqual(48, $this->countMetadataKeys($file_metadata, 'exif'));
230 // Add the RelatedImageFileFormat tag to INTEROP.
231 $this->assertNull($file_metadata->getMetadata('exif', ['interop', 'RelatedImageFileFormat']));
232 $ff_tag = $this->container->get('file_mdm_exif.tag_mapper')->resolveKeyToIfdAndTag(['interop', 'RelatedImageFileFormat']);
233 $ff = new PelEntryAscii($ff_tag['tag'], 'qux');
234 $file_metadata->setMetadata('exif', ['interop', 'RelatedImageFileFormat'], $ff);
235 $this->assertEqual('qux', $file_metadata->getMetadata('exif', ['interop', 'RelatedImageFileFormat'])['text']);
236 $this->assertEqual(49, $this->countMetadataKeys($file_metadata, 'exif'));
237 // Remove the InteroperabilityIndex tag from INTEROP.
238 $this->assertEqual('R98', $file_metadata->getMetadata('exif', ['interop', 'InteroperabilityIndex'])['value']);
239 $this->assertTrue($file_metadata->removeMetadata('exif', ['interop', 'InteroperabilityIndex']));
240 $this->assertNull($file_metadata->getMetadata('exif', ['interop', 'InteroperabilityIndex']));
241 $this->assertEqual(48, $this->countMetadataKeys($file_metadata, 'exif'));
243 // Add Longitude/Latitude tags to GPS.
244 $this->assertNull($file_metadata->getMetadata('exif', 'GPSLatitudeRef'));
245 $this->assertNull($file_metadata->getMetadata('exif', 'GPSLatitude'));
246 $this->assertNull($file_metadata->getMetadata('exif', 'GPSLongitudeRef'));
247 $this->assertNull($file_metadata->getMetadata('exif', 'GPSLongitude'));
248 $atr_tag = $this->container->get('file_mdm_exif.tag_mapper')->resolveKeyToIfdAndTag('GPSLatitudeRef');
249 $at_tag = $this->container->get('file_mdm_exif.tag_mapper')->resolveKeyToIfdAndTag('GPSLatitude');
250 $otr_tag = $this->container->get('file_mdm_exif.tag_mapper')->resolveKeyToIfdAndTag('GPSLongitudeRef');
251 $ot_tag = $this->container->get('file_mdm_exif.tag_mapper')->resolveKeyToIfdAndTag('GPSLongitude');
252 $atr = new PelEntryAscii($atr_tag['tag'], 'N');
253 $at = new PelEntryRational($at_tag['tag'], [46, 1], [37, 1], [59448, 10000]);
254 $otr = new PelEntryAscii($otr_tag['tag'], 'E');
255 $ot = new PelEntryRational($ot_tag['tag'], [12, 1], [17, 1], [488112, 10000]);
256 $file_metadata->setMetadata('exif', 'GPSLatitudeRef', $atr);
257 $file_metadata->setMetadata('exif', 'GPSLatitude', $at);
258 $file_metadata->setMetadata('exif', 'GPSLongitudeRef', $otr);
259 $file_metadata->setMetadata('exif', 'GPSLongitude', $ot);
260 $this->assertEqual('N', $file_metadata->getMetadata('exif', 'GPSLatitudeRef')['text']);
261 $this->assertNotNull($file_metadata->getMetadata('exif', 'GPSLatitude')['text']);
262 $this->assertEqual('E', $file_metadata->getMetadata('exif', 'GPSLongitudeRef')['text']);
263 $this->assertNotNull($file_metadata->getMetadata('exif', 'GPSLongitude')['text']);
264 $this->assertEqual(52, $this->countMetadataKeys($file_metadata, 'exif'));
266 // Save metadata to file.
267 $this->assertTrue($file_metadata->saveMetadataToFile('exif'));
269 // Check results via exif_read_data.
270 $data = @exif_read_data($file_uri);
271 $this->assertEqual(4, $data['Orientation']);
272 $this->assertEqual('shot by foo!', $data['Artist']);
273 $this->assertFalse(isset($data['Make']));
274 $this->assertEqual('12/4', $data['BrightnessValue']);
275 $this->assertFalse(isset($data['ISOSpeedRatings']));
276 $this->assertEqual('qux', $data['RelatedFileFormat']);
277 $this->assertFalse(isset($data['InterOperabilityIndex']));
278 $this->assertEqual('N', $data['GPSLatitudeRef']);
279 $this->assertEqual(['46/1', '37/1', '59448/10000'], $data['GPSLatitude']);
280 $this->assertEqual('E', $data['GPSLongitudeRef']);
281 $this->assertEqual(['12/1', '17/1', '488112/10000'], $data['GPSLongitude']);
283 // Test writing metadata to a file that has no EXIF info.
284 file_unmanaged_copy(drupal_get_path('module', 'simpletest') . '/files/image-2.jpg', 'public://', FILE_EXISTS_REPLACE);
285 $test_2 = $fmdm->uri('public://image-2.jpg');
286 $this->assertEqual(0, $this->countMetadataKeys($test_2, 'exif'));
287 // Load EXIF metadata from previous file processed.
288 $test_2->loadMetadata('exif', $file_metadata->getMetadata('exif'));
289 // Save metadata to file.
290 $this->assertTrue($test_2->saveMetadataToFile('exif'));
291 $this->assertEqual(52, $this->countMetadataKeys($test_2, 'exif'));
292 // Check results via exif_read_data.
293 $data = @exif_read_data('public://image-2.jpg');
294 $this->assertEqual(4, $data['Orientation']);
295 $this->assertEqual('shot by foo!', $data['Artist']);
296 $this->assertEqual('12/4', $data['BrightnessValue']);
297 $this->assertEqual('qux', $data['RelatedFileFormat']);
298 $this->assertEqual('N', $data['GPSLatitudeRef']);
299 $this->assertEqual(['46/1', '37/1', '59448/10000'], $data['GPSLatitude']);
300 $this->assertEqual('E', $data['GPSLongitudeRef']);
301 $this->assertEqual(['12/1', '17/1', '488112/10000'], $data['GPSLongitude']);
303 // Check that after save, file metadata is retrieved from file first time,
304 // then from cache in further requests.
305 $file_metadata = NULL;
306 $this->assertTrue($fmdm->release($file_uri));
307 $file_metadata = $fmdm->uri($file_uri);
308 $this->assertEqual(52, $this->countMetadataKeys($file_metadata, 'exif'));
309 $this->assertIdentical(FileMetadataInterface::LOADED_FROM_FILE, $file_metadata->isMetadataLoaded('exif'));
310 $file_metadata = NULL;
311 $this->assertTrue($fmdm->release($file_uri));
312 $file_metadata = $fmdm->uri($file_uri);
313 $this->assertEqual(52, $this->countMetadataKeys($file_metadata, 'exif'));
314 $this->assertIdentical(FileMetadataInterface::LOADED_FROM_CACHE, $file_metadata->isMetadataLoaded('exif'));
318 * Test writing metadata to TIFF file.
320 public function testTiffExifSaveToFile() {
321 $fmdm = $this->container->get('file_metadata_manager');
323 // Copy test file to public://.
324 file_unmanaged_copy(drupal_get_path('module', 'file_mdm') . '/tests/files/sample-1.tiff', 'public://', FILE_EXISTS_REPLACE);
325 $file_uri = 'public://sample-1.tiff';
326 $file_metadata = $fmdm->uri($file_uri);
328 // Check values via exif_read_data before operations.
329 $data = @exif_read_data($file_uri);
330 $this->assertEqual(1, $data['Orientation']);
331 $this->assertEqual(2, $data['PhotometricInterpretation']);
333 // Change tags from IFD0.
334 $this->assertEqual(1, $file_metadata->getMetadata('exif', 'orientation')['value']);
335 $this->assertTrue($file_metadata->setMetadata('exif', 'orientation', 4));
336 $this->assertEqual(4, $file_metadata->getMetadata('exif', 'orientation')['value']);
337 $this->assertEqual(2, $file_metadata->getMetadata('exif', 'PhotometricInterpretation')['value']);
338 $this->assertTrue($file_metadata->setMetadata('exif', 'PhotometricInterpretation', 4));
339 $this->assertEqual(4, $file_metadata->getMetadata('exif', 'PhotometricInterpretation')['value']);
341 // Save metadata to file.
342 $this->assertTrue($file_metadata->saveMetadataToFile('exif'));
344 // Check results via exif_read_data.
345 $data = @exif_read_data($file_uri);
346 $this->assertEqual(4, $data['Orientation']);
347 $this->assertEqual(4, $data['PhotometricInterpretation']);