ImageTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace Test;
  8. use OC;
  9. use OC\Image;
  10. use OCP\IAppConfig;
  11. use OCP\IConfig;
  12. class ImageTest extends \Test\TestCase {
  13. public static function tearDownAfterClass(): void {
  14. @unlink(OC::$SERVERROOT . '/tests/data/testimage2.png');
  15. @unlink(OC::$SERVERROOT . '/tests/data/testimage2.jpg');
  16. parent::tearDownAfterClass();
  17. }
  18. public function testConstructDestruct(): void {
  19. $img = new Image();
  20. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  21. $this->assertInstanceOf('\OC\Image', $img);
  22. $this->assertInstanceOf('\OCP\IImage', $img);
  23. unset($img);
  24. $imgcreate = imagecreatefromjpeg(OC::$SERVERROOT . '/tests/data/testimage.jpg');
  25. $img = new Image();
  26. $img->setResource($imgcreate);
  27. $this->assertInstanceOf('\OC\Image', $img);
  28. $this->assertInstanceOf('\OCP\IImage', $img);
  29. unset($img);
  30. $base64 = base64_encode(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif'));
  31. $img = new Image();
  32. $img->loadFromBase64($base64);
  33. $this->assertInstanceOf('\OC\Image', $img);
  34. $this->assertInstanceOf('\OCP\IImage', $img);
  35. unset($img);
  36. $img = new Image();
  37. $this->assertInstanceOf('\OC\Image', $img);
  38. $this->assertInstanceOf('\OCP\IImage', $img);
  39. unset($img);
  40. }
  41. public function testValid(): void {
  42. $img = new Image();
  43. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  44. $this->assertTrue($img->valid());
  45. $text = base64_encode('Lorem ipsum dolor sir amet …');
  46. $img = new Image();
  47. $img->loadFromBase64($text);
  48. $this->assertFalse($img->valid());
  49. $img = new Image();
  50. $this->assertFalse($img->valid());
  51. }
  52. public function testMimeType(): void {
  53. $img = new Image();
  54. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  55. $this->assertEquals('image/png', $img->mimeType());
  56. $img = new Image();
  57. $this->assertEquals('', $img->mimeType());
  58. $img = new Image();
  59. $img->loadFromData(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  60. $this->assertEquals('image/jpeg', $img->mimeType());
  61. $img = new Image();
  62. $img->loadFromBase64(base64_encode(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif')));
  63. $this->assertEquals('image/gif', $img->mimeType());
  64. }
  65. public function testWidth(): void {
  66. $img = new Image();
  67. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  68. $this->assertEquals(128, $img->width());
  69. $img = new Image();
  70. $img->loadFromData(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  71. $this->assertEquals(1680, $img->width());
  72. $img = new Image();
  73. $img->loadFromBase64(base64_encode(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif')));
  74. $this->assertEquals(64, $img->width());
  75. $img = new Image();
  76. $this->assertEquals(-1, $img->width());
  77. }
  78. public function testHeight(): void {
  79. $img = new Image();
  80. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  81. $this->assertEquals(128, $img->height());
  82. $img = new Image();
  83. $img->loadFromData(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  84. $this->assertEquals(1050, $img->height());
  85. $img = new Image();
  86. $img->loadFromBase64(base64_encode(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif')));
  87. $this->assertEquals(64, $img->height());
  88. $img = new Image();
  89. $this->assertEquals(-1, $img->height());
  90. }
  91. public function testSave(): void {
  92. $img = new Image();
  93. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  94. $img->resize(16);
  95. $img->save(OC::$SERVERROOT . '/tests/data/testimage2.png');
  96. $this->assertEquals(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage2.png'), $img->data());
  97. $img = new Image();
  98. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.jpg');
  99. $img->resize(128);
  100. $img->save(OC::$SERVERROOT . '/tests/data/testimage2.jpg');
  101. $this->assertEquals(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage2.jpg'), $img->data());
  102. }
  103. public function testData(): void {
  104. $img = new Image();
  105. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  106. $raw = imagecreatefromstring(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.png'));
  107. // Preserve transparency
  108. imagealphablending($raw, true);
  109. imagesavealpha($raw, true);
  110. ob_start();
  111. imagepng($raw);
  112. $expected = ob_get_clean();
  113. $this->assertEquals($expected, $img->data());
  114. $appConfig = $this->createMock(IAppConfig::class);
  115. $appConfig->expects($this->once())
  116. ->method('getValueInt')
  117. ->with('preview', 'jpeg_quality', 80)
  118. ->willReturn(80);
  119. $config = $this->createMock(IConfig::class);
  120. $config->expects($this->once())
  121. ->method('getSystemValueInt')
  122. ->with('preview_max_memory', 256)
  123. ->willReturn(256);
  124. $img = new Image(null, $appConfig, $config);
  125. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.jpg');
  126. $raw = imagecreatefromstring(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  127. imageinterlace($raw, true);
  128. ob_start();
  129. imagejpeg($raw, null, 80);
  130. $expected = ob_get_clean();
  131. $this->assertEquals($expected, $img->data());
  132. $img = new Image();
  133. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.gif');
  134. $raw = imagecreatefromstring(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif'));
  135. ob_start();
  136. imagegif($raw);
  137. $expected = ob_get_clean();
  138. $this->assertEquals($expected, $img->data());
  139. }
  140. public function testDataNoResource(): void {
  141. $img = new Image();
  142. $this->assertNull($img->data());
  143. }
  144. /**
  145. * @depends testData
  146. */
  147. public function testToString(): void {
  148. $img = new Image();
  149. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  150. $expected = base64_encode($img->data());
  151. $this->assertEquals($expected, (string)$img);
  152. $img = new Image();
  153. $img->loadFromData(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  154. $expected = base64_encode($img->data());
  155. $this->assertEquals($expected, (string)$img);
  156. $img = new Image();
  157. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.gif');
  158. $expected = base64_encode($img->data());
  159. $this->assertEquals($expected, (string)$img);
  160. }
  161. public function testResize(): void {
  162. $img = new Image();
  163. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  164. $this->assertTrue($img->resize(32));
  165. $this->assertEquals(32, $img->width());
  166. $this->assertEquals(32, $img->height());
  167. $img = new Image();
  168. $img->loadFromData(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  169. $this->assertTrue($img->resize(840));
  170. $this->assertEquals(840, $img->width());
  171. $this->assertEquals(525, $img->height());
  172. $img = new Image();
  173. $img->loadFromBase64(base64_encode(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif')));
  174. $this->assertTrue($img->resize(100));
  175. $this->assertEquals(100, $img->width());
  176. $this->assertEquals(100, $img->height());
  177. }
  178. public function testPreciseResize(): void {
  179. $img = new Image();
  180. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  181. $this->assertTrue($img->preciseResize(128, 512));
  182. $this->assertEquals(128, $img->width());
  183. $this->assertEquals(512, $img->height());
  184. $img = new Image();
  185. $img->loadFromData(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  186. $this->assertTrue($img->preciseResize(64, 840));
  187. $this->assertEquals(64, $img->width());
  188. $this->assertEquals(840, $img->height());
  189. $img = new Image();
  190. $img->loadFromBase64(base64_encode(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif')));
  191. $this->assertTrue($img->preciseResize(1000, 1337));
  192. $this->assertEquals(1000, $img->width());
  193. $this->assertEquals(1337, $img->height());
  194. }
  195. public function testCenterCrop(): void {
  196. $img = new Image();
  197. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  198. $img->centerCrop();
  199. $this->assertEquals(128, $img->width());
  200. $this->assertEquals(128, $img->height());
  201. $img = new Image();
  202. $img->loadFromData(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  203. $img->centerCrop();
  204. $this->assertEquals(1050, $img->width());
  205. $this->assertEquals(1050, $img->height());
  206. $img = new Image();
  207. $img->loadFromBase64(base64_encode(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif')));
  208. $img->centerCrop(512);
  209. $this->assertEquals(512, $img->width());
  210. $this->assertEquals(512, $img->height());
  211. }
  212. public function testCrop(): void {
  213. $img = new Image();
  214. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  215. $this->assertTrue($img->crop(0, 0, 50, 20));
  216. $this->assertEquals(50, $img->width());
  217. $this->assertEquals(20, $img->height());
  218. $img = new Image();
  219. $img->loadFromData(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.jpg'));
  220. $this->assertTrue($img->crop(500, 700, 550, 300));
  221. $this->assertEquals(550, $img->width());
  222. $this->assertEquals(300, $img->height());
  223. $img = new Image();
  224. $img->loadFromBase64(base64_encode(file_get_contents(OC::$SERVERROOT . '/tests/data/testimage.gif')));
  225. $this->assertTrue($img->crop(10, 10, 15, 15));
  226. $this->assertEquals(15, $img->width());
  227. $this->assertEquals(15, $img->height());
  228. }
  229. public static function sampleProvider() {
  230. return [
  231. ['testimage.png', [200, 100], [100, 100]],
  232. ['testimage.jpg', [840, 840], [840, 525]],
  233. ['testimage.gif', [200, 250], [200, 200]]
  234. ];
  235. }
  236. /**
  237. * @dataProvider sampleProvider
  238. *
  239. * @param string $filename
  240. * @param int[] $asked
  241. * @param int[] $expected
  242. */
  243. public function testFitIn($filename, $asked, $expected): void {
  244. $img = new Image();
  245. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/' . $filename);
  246. $this->assertTrue($img->fitIn($asked[0], $asked[1]));
  247. $this->assertEquals($expected[0], $img->width());
  248. $this->assertEquals($expected[1], $img->height());
  249. }
  250. public static function sampleFilenamesProvider() {
  251. return [
  252. ['testimage.png'],
  253. ['testimage.jpg'],
  254. ['testimage.gif']
  255. ];
  256. }
  257. /**
  258. * Image should not be resized if it's already smaller than what is required
  259. *
  260. * @dataProvider sampleFilenamesProvider
  261. *
  262. * @param string $filename
  263. */
  264. public function testScaleDownToFitWhenSmallerAlready($filename): void {
  265. $img = new Image();
  266. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/' . $filename);
  267. $currentWidth = $img->width();
  268. $currentHeight = $img->height();
  269. // We pick something larger than the image we want to scale down
  270. $this->assertFalse($img->scaleDownToFit(4000, 4000));
  271. // The dimensions of the image should not have changed since it's smaller already
  272. $resizedWidth = $img->width();
  273. $resizedHeight = $img->height();
  274. $this->assertEquals(
  275. $currentWidth, $img->width(), "currentWidth $currentWidth resizedWidth $resizedWidth \n"
  276. );
  277. $this->assertEquals(
  278. $currentHeight, $img->height(),
  279. "currentHeight $currentHeight resizedHeight $resizedHeight \n"
  280. );
  281. }
  282. public static function largeSampleProvider() {
  283. return [
  284. ['testimage.png', [200, 100], [100, 100]],
  285. ['testimage.jpg', [840, 840], [840, 525]],
  286. ];
  287. }
  288. /**
  289. * @dataProvider largeSampleProvider
  290. *
  291. * @param string $filename
  292. * @param int[] $asked
  293. * @param int[] $expected
  294. */
  295. public function testScaleDownWhenBigger($filename, $asked, $expected): void {
  296. $img = new Image();
  297. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/' . $filename);
  298. //$this->assertTrue($img->scaleDownToFit($asked[0], $asked[1]));
  299. $img->scaleDownToFit($asked[0], $asked[1]);
  300. $this->assertEquals($expected[0], $img->width());
  301. $this->assertEquals($expected[1], $img->height());
  302. }
  303. public function convertDataProvider() {
  304. return [
  305. [ 'image/gif'],
  306. [ 'image/jpeg'],
  307. [ 'image/png'],
  308. ];
  309. }
  310. /**
  311. * @dataProvider convertDataProvider
  312. */
  313. public function testConvert($mimeType): void {
  314. $img = new Image();
  315. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage.png');
  316. $tempFile = tempnam(sys_get_temp_dir(), 'img-test');
  317. $img->save($tempFile, $mimeType);
  318. $this->assertEquals($mimeType, image_type_to_mime_type(exif_imagetype($tempFile)));
  319. }
  320. public function testMemoryLimitFromFile(): void {
  321. $img = new Image();
  322. $img->loadFromFile(OC::$SERVERROOT . '/tests/data/testimage-badheader.jpg');
  323. $this->assertFalse($img->valid());
  324. }
  325. public function testMemoryLimitFromData(): void {
  326. $data = file_get_contents(OC::$SERVERROOT . '/tests/data/testimage-badheader.jpg');
  327. $img = new Image();
  328. $img->loadFromData($data);
  329. $this->assertFalse($img->valid());
  330. }
  331. }