PageRenderTime 45ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/test/System.Web.Helpers.Test/WebImageTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 1162 lines | 875 code | 219 blank | 68 comment | 0 complexity | 1e6c8cbaff37cdadff4788a5edfaa65d MD5 | raw file
  1. using System.Drawing;
  2. using System.Drawing.Imaging;
  3. using System.IO;
  4. using System.Web.WebPages.TestUtils;
  5. using Moq;
  6. using Xunit;
  7. using Assert = Microsoft.TestCommon.AssertEx;
  8. namespace System.Web.Helpers.Test
  9. {
  10. public class WebImageTest
  11. {
  12. private static readonly byte[] _JpgImageBytes = TestFile.Create("LambdaFinal.jpg").ReadAllBytes();
  13. private static readonly byte[] _BmpImageBytes = TestFile.Create("logo.bmp").ReadAllBytes();
  14. private static readonly byte[] _PngImageBytes = TestFile.Create("NETLogo.png").ReadAllBytes();
  15. private static readonly byte[] _HiResImageBytes = TestFile.Create("HiRes.jpg").ReadAllBytes();
  16. [Fact]
  17. public void ConstructorThrowsWhenFilePathIsNull()
  18. {
  19. Assert.ThrowsArgument(() =>
  20. new WebImage(GetContext(), s => new byte[] { }, filePath: null), "filePath", "Value cannot be null or an empty string.");
  21. }
  22. [Fact]
  23. public void ConstructorThrowsWhenFilePathIsEmpty()
  24. {
  25. Assert.ThrowsArgument(() =>
  26. new WebImage(GetContext(), s => new byte[] { }, filePath: String.Empty), "filePath", "Value cannot be null or an empty string.");
  27. }
  28. [Fact]
  29. public void ConstructorThrowsWhenFilePathIsInvalid()
  30. {
  31. Assert.Throws<DirectoryNotFoundException>(() =>
  32. new WebImage(GetContext(), s => { throw new DirectoryNotFoundException(); }, @"x:\this\does\not\exist.jpg"));
  33. }
  34. [Fact]
  35. public void ConstructorThrowsWhenFileContentIsInvalid()
  36. {
  37. byte[] imageContent = new byte[] { 32, 111, 209, 138, 76, 32 };
  38. Assert.ThrowsArgument(() => new WebImage(imageContent), "content",
  39. "An image could not be constructed from the content provided.");
  40. }
  41. [Fact]
  42. public void FilePathReturnsCorrectPath()
  43. {
  44. // Arrange
  45. string imageName = @"x:\My-test-image.png";
  46. // Act
  47. WebImage image = new WebImage(GetContext(), s => _PngImageBytes, imageName);
  48. // Assert
  49. Assert.Equal(imageName, image.FileName);
  50. }
  51. [Fact]
  52. public void FilePathCanBeSet()
  53. {
  54. // Arrange
  55. string originalPath = @"x:\somePath.png";
  56. string newPath = @"x:\someOtherPath.jpg";
  57. // Act
  58. WebImage image = new WebImage(GetContext(), s => _PngImageBytes, originalPath);
  59. image.FileName = newPath;
  60. // Assert
  61. Assert.Equal(newPath, image.FileName);
  62. }
  63. [Fact]
  64. public void SimpleGetBytesClonesArray()
  65. {
  66. WebImage image = new WebImage(_PngImageBytes);
  67. byte[] returnedContent = image.GetBytes();
  68. Assert.False(ReferenceEquals(_PngImageBytes, returnedContent), "GetBytes should clone array.");
  69. Assert.Equal(_PngImageBytes, returnedContent);
  70. }
  71. [Fact]
  72. public void WebImagePreservesOriginalFormatFromFile()
  73. {
  74. WebImage image = new WebImage(_PngImageBytes);
  75. byte[] returnedContent = image.GetBytes();
  76. // If format was changed; content would be different
  77. Assert.Equal(_PngImageBytes, returnedContent);
  78. }
  79. [Fact]
  80. public void WebImagePreservesOriginalFormatFromStream()
  81. {
  82. WebImage image = null;
  83. byte[] originalContent = _PngImageBytes;
  84. using (MemoryStream stream = new MemoryStream(originalContent))
  85. {
  86. image = new WebImage(stream);
  87. } // dispose stream; WebImage should have no dependency on it
  88. byte[] returnedContent = image.GetBytes();
  89. // If format was changed; content would be different
  90. Assert.Equal(originalContent, returnedContent);
  91. }
  92. [Fact]
  93. public void WebImageCorrectlyReadsFromNoSeekStream()
  94. {
  95. WebImage image = null;
  96. byte[] originalContent = _PngImageBytes;
  97. using (MemoryStream stream = new MemoryStream(originalContent))
  98. {
  99. TestStream ts = new TestStream(stream);
  100. image = new WebImage(ts);
  101. } // dispose stream; WebImage should have no dependency on it
  102. byte[] returnedContent = image.GetBytes();
  103. // If chunks are not assembled correctly; content would be different and image would be corrupted.
  104. Assert.Equal(originalContent, returnedContent);
  105. Assert.Equal("png", image.ImageFormat);
  106. }
  107. [Fact]
  108. public void GetBytesWithNullReturnsClonesArray()
  109. {
  110. byte[] originalContent = _BmpImageBytes;
  111. WebImage image = new WebImage(originalContent);
  112. byte[] returnedContent = image.GetBytes();
  113. Assert.False(ReferenceEquals(originalContent, returnedContent), "GetBytes with string null should clone array.");
  114. Assert.Equal(originalContent, returnedContent);
  115. }
  116. [Fact]
  117. public void GetBytesWithSameFormatReturnsSameFormat()
  118. {
  119. byte[] originalContent = _JpgImageBytes;
  120. WebImage image = new WebImage(originalContent);
  121. byte[] returnedContent = image.GetBytes("jpeg");
  122. Assert.False(ReferenceEquals(originalContent, returnedContent), "GetBytes with string null should clone array.");
  123. Assert.Equal(originalContent, returnedContent);
  124. }
  125. [Fact]
  126. public void GetBytesWithDifferentFormatReturnsExpectedFormat()
  127. {
  128. byte[] originalContent = _BmpImageBytes;
  129. WebImage image = new WebImage(originalContent);
  130. // Request different format
  131. byte[] returnedContent = image.GetBytes("jpg");
  132. Assert.False(ReferenceEquals(originalContent, returnedContent), "GetBytes with string format should clone array.");
  133. using (MemoryStream stream = new MemoryStream(returnedContent))
  134. {
  135. using (Image tempImage = Image.FromStream(stream))
  136. {
  137. Assert.Equal(ImageFormat.Jpeg, tempImage.RawFormat);
  138. }
  139. }
  140. }
  141. [Fact]
  142. public void GetBytesWithSameFormatReturnsSameFormatWhenCreatedFromFile()
  143. {
  144. byte[] originalContent = _BmpImageBytes;
  145. // Format is not set during construction.
  146. WebImage image = new WebImage(_BmpImageBytes);
  147. byte[] returnedContent = image.GetBytes("bmp");
  148. Assert.False(ReferenceEquals(originalContent, returnedContent), "GetBytes with string format should clone array.");
  149. Assert.Equal(originalContent, returnedContent);
  150. }
  151. [Fact]
  152. public void GetBytesWithNoFormatReturnsInitialFormatEvenAfterTransformations()
  153. {
  154. byte[] originalContent = _BmpImageBytes;
  155. // Format is not set during construction.
  156. WebImage image = new WebImage(_BmpImageBytes);
  157. image.Crop(top: 10, bottom: 10);
  158. byte[] returnedContent = image.GetBytes();
  159. Assert.NotEqual(originalContent, returnedContent);
  160. using (MemoryStream stream = new MemoryStream(returnedContent))
  161. {
  162. using (Image tempImage = Image.FromStream(stream))
  163. {
  164. Assert.Equal(ImageFormat.Bmp, tempImage.RawFormat);
  165. }
  166. }
  167. }
  168. [Fact]
  169. public void GetBytesThrowsOnIncorrectFormat()
  170. {
  171. WebImage image = new WebImage(_JpgImageBytes);
  172. Assert.ThrowsArgument(
  173. () => image.GetBytes("bmpx"),
  174. "format",
  175. "\"bmpx\" is invalid image format. Valid values are image format names like: \"JPEG\", \"BMP\", \"GIF\", \"PNG\", etc.");
  176. }
  177. [Fact]
  178. public void GetBytesWithDifferentFormatReturnsExpectedFormatWhenCreatedFromFile()
  179. {
  180. // Format is not set during construction.
  181. WebImage image = new WebImage(_PngImageBytes);
  182. // Request different format
  183. byte[] returnedContent = image.GetBytes("jpg");
  184. WebImage newImage = new WebImage(returnedContent);
  185. Assert.Equal("jpeg", newImage.ImageFormat);
  186. }
  187. [Fact]
  188. public void GetImageFromRequestReturnsNullForIncorrectMimeType()
  189. {
  190. // Arrange
  191. Mock<HttpPostedFileBase> postedFile = new Mock<HttpPostedFileBase>();
  192. postedFile.Setup(c => c.FileName).Returns("index.cshtml");
  193. postedFile.Setup(c => c.ContentType).Returns("image/jpg");
  194. Mock<HttpFileCollectionBase> files = new Mock<HttpFileCollectionBase>();
  195. files.Setup(c => c[0]).Returns(postedFile.Object);
  196. Mock<HttpRequestBase> request = new Mock<HttpRequestBase>();
  197. request.Setup(r => r.Files).Returns(files.Object);
  198. // Act and Assert
  199. Assert.Null(WebImage.GetImageFromRequest(request.Object));
  200. }
  201. [Fact]
  202. public void GetImageFromRequestDeterminesMimeTypeFromExtension()
  203. {
  204. // Arrange
  205. Mock<HttpPostedFileBase> postedFile = new Mock<HttpPostedFileBase>();
  206. postedFile.Setup(c => c.FileName).Returns("index.jpeg");
  207. postedFile.Setup(c => c.ContentType).Returns("application/octet-stream");
  208. postedFile.Setup(c => c.ContentLength).Returns(1);
  209. postedFile.Setup(c => c.InputStream).Returns(new MemoryStream(_JpgImageBytes));
  210. Mock<HttpFileCollectionBase> files = new Mock<HttpFileCollectionBase>();
  211. files.Setup(c => c.Count).Returns(1);
  212. files.Setup(c => c[0]).Returns(postedFile.Object);
  213. Mock<HttpRequestBase> request = new Mock<HttpRequestBase>();
  214. request.Setup(r => r.Files).Returns(files.Object);
  215. // Act
  216. WebImage image = WebImage.GetImageFromRequest(request.Object);
  217. // Assert
  218. Assert.NotNull(image);
  219. Assert.Equal("jpeg", image.ImageFormat);
  220. }
  221. [Fact]
  222. public void GetImageFromRequestIsCaseInsensitive()
  223. {
  224. // Arrange
  225. Mock<HttpPostedFileBase> postedFile = new Mock<HttpPostedFileBase>();
  226. postedFile.SetupGet(c => c.FileName).Returns("index.JPg");
  227. postedFile.SetupGet(c => c.ContentType).Returns("application/octet-stream");
  228. postedFile.SetupGet(c => c.ContentLength).Returns(1);
  229. postedFile.SetupGet(c => c.InputStream).Returns(new MemoryStream(_JpgImageBytes));
  230. Mock<HttpFileCollectionBase> files = new Mock<HttpFileCollectionBase>();
  231. files.Setup(c => c.Count).Returns(1);
  232. files.Setup(c => c[0]).Returns(postedFile.Object);
  233. Mock<HttpRequestBase> request = new Mock<HttpRequestBase>();
  234. request.Setup(r => r.Files).Returns(files.Object);
  235. // Act
  236. WebImage image = WebImage.GetImageFromRequest(request.Object);
  237. // Assert
  238. Assert.NotNull(image);
  239. Assert.Equal("jpeg", image.ImageFormat);
  240. }
  241. [Fact]
  242. public void ImagePropertiesAreCorrectForBmpImage()
  243. {
  244. WebImage image = new WebImage(_BmpImageBytes);
  245. Assert.Equal("bmp", image.ImageFormat);
  246. Assert.Equal(108, image.Width);
  247. Assert.Equal(44, image.Height);
  248. }
  249. [Fact]
  250. public void ImagePropertiesAreCorrectForPngImage()
  251. {
  252. WebImage image = new WebImage(_PngImageBytes);
  253. Assert.Equal("png", image.ImageFormat);
  254. Assert.Equal(160, image.Width);
  255. Assert.Equal(152, image.Height);
  256. }
  257. [Fact]
  258. public void ImagePropertiesAreCorrectForJpgImage()
  259. {
  260. WebImage image = new WebImage(_JpgImageBytes);
  261. Assert.Equal("jpeg", image.ImageFormat);
  262. Assert.Equal(634, image.Width);
  263. Assert.Equal(489, image.Height);
  264. }
  265. [Fact]
  266. public void ResizePreservesRatio()
  267. {
  268. WebImage image = new WebImage(_JpgImageBytes);
  269. image.Resize(200, 100, preserveAspectRatio: true, preventEnlarge: true);
  270. Assert.Equal(130, image.Width);
  271. Assert.Equal(100, image.Height);
  272. }
  273. [Fact]
  274. public void ResizePreservesResolution()
  275. {
  276. MemoryStream output = null;
  277. Action<string, byte[]> saveAction = (_, content) => { output = new MemoryStream(content); };
  278. WebImage image = new WebImage(_HiResImageBytes);
  279. image.Resize(200, 100, preserveAspectRatio: true, preventEnlarge: true);
  280. image.Save(GetContext(), saveAction, @"x:\ResizePreservesResolution.jpg", "jpeg", forceWellKnownExtension: true);
  281. using (Image original = Image.FromStream(new MemoryStream(_HiResImageBytes)))
  282. {
  283. using (Image modified = Image.FromStream(output))
  284. {
  285. Assert.Equal(original.HorizontalResolution, modified.HorizontalResolution);
  286. Assert.Equal(original.VerticalResolution, modified.VerticalResolution);
  287. }
  288. }
  289. }
  290. [Fact]
  291. public void ResizePreservesFormat()
  292. {
  293. // Arrange
  294. WebImage image = new WebImage(_PngImageBytes);
  295. MemoryStream output = null;
  296. Action<string, byte[]> saveAction = (_, content) => { output = new MemoryStream(content); };
  297. // Act
  298. image.Resize(200, 100, preserveAspectRatio: true, preventEnlarge: true);
  299. // Assert
  300. Assert.Equal(image.ImageFormat, "png");
  301. image.Save(GetContext(), saveAction, @"x:\1.png", null, false);
  302. using (Image modified = Image.FromStream(output))
  303. {
  304. Assert.Equal(ImageFormat.Png, modified.RawFormat);
  305. }
  306. }
  307. [Fact]
  308. public void SaveUpdatesFileNameOfWebImageWhenForcingWellKnownExtension()
  309. {
  310. // Arrange
  311. var context = GetContext();
  312. // Act
  313. WebImage image = new WebImage(context, _ => _JpgImageBytes, @"c:\images\foo.jpg");
  314. image.Save(context, (_, __) => { }, @"x:\1.exe", "jpg", forceWellKnownExtension: true);
  315. // Assert
  316. Assert.Equal(@"x:\1.exe.jpeg", image.FileName);
  317. }
  318. [Fact]
  319. public void SaveUpdatesFileNameOfWebImageWhenFormatChanges()
  320. {
  321. // Arrange
  322. string imagePath = @"x:\images\foo.jpg";
  323. var context = GetContext();
  324. // Act
  325. WebImage image = new WebImage(context, _ => _JpgImageBytes, imagePath);
  326. image.Save(context, (_, __) => { }, imagePath, "png", forceWellKnownExtension: true);
  327. // Assert
  328. Assert.Equal(@"x:\images\foo.jpg.png", image.FileName);
  329. }
  330. [Fact]
  331. public void SaveKeepsNameIfFormatIsUnchanged()
  332. {
  333. // Arrange
  334. string imagePath = @"x:\images\foo.jpg";
  335. var context = GetContext();
  336. // Act
  337. WebImage image = new WebImage(context, _ => _JpgImageBytes, imagePath);
  338. image.Save(context, (_, __) => { }, imagePath, "jpg", forceWellKnownExtension: true);
  339. // Assert
  340. Assert.Equal(@"x:\images\foo.jpg", image.FileName);
  341. }
  342. [Fact]
  343. public void ResizeThrowsOnIncorrectWidthOrHeight()
  344. {
  345. WebImage image = new WebImage(_JpgImageBytes);
  346. Assert.ThrowsArgumentGreaterThan(
  347. () => image.Resize(-1, 100, preserveAspectRatio: true, preventEnlarge: true),
  348. "width",
  349. "0");
  350. Assert.ThrowsArgumentGreaterThan(
  351. () => image.Resize(100, -1, preserveAspectRatio: true, preventEnlarge: true),
  352. "height",
  353. "0");
  354. }
  355. [Fact]
  356. public void ResizeAndRotateDoesOperationsInRightOrder()
  357. {
  358. WebImage image = new WebImage(_JpgImageBytes);
  359. image.Resize(200, 100, preserveAspectRatio: true, preventEnlarge: true).RotateLeft();
  360. Assert.Equal(100, image.Width);
  361. Assert.Equal(130, image.Height);
  362. }
  363. [Fact]
  364. public void ClonePreservesAllInformation()
  365. {
  366. WebImage image = new WebImage(_JpgImageBytes);
  367. image.Resize(200, 100, preserveAspectRatio: true, preventEnlarge: true).RotateLeft();
  368. // this should preserve list of transformations
  369. WebImage cloned = image.Clone();
  370. Assert.Equal(100, cloned.Width);
  371. Assert.Equal(130, cloned.Height);
  372. }
  373. [Fact]
  374. public void ResizePreventsEnlarge()
  375. {
  376. WebImage image = new WebImage(_JpgImageBytes);
  377. int height = image.Height;
  378. int width = image.Width;
  379. image.Resize(width * 2, height, preserveAspectRatio: true, preventEnlarge: true);
  380. Assert.Equal(width, image.Width);
  381. Assert.Equal(height, image.Height);
  382. }
  383. [Fact]
  384. public void CropCreatesCroppedImage()
  385. {
  386. WebImage image = new WebImage(_JpgImageBytes);
  387. image.Crop(20, 20, 20, 20);
  388. Assert.Equal(594, image.Width);
  389. Assert.Equal(449, image.Height);
  390. }
  391. [Fact]
  392. public void CropThrowsOnIncorrectArguments()
  393. {
  394. WebImage image = new WebImage(_JpgImageBytes);
  395. Assert.ThrowsArgumentGreaterThanOrEqualTo(
  396. () => image.Crop(top: -1),
  397. "top",
  398. "0");
  399. Assert.ThrowsArgumentGreaterThanOrEqualTo(
  400. () => image.Crop(left: -1),
  401. "left",
  402. "0");
  403. Assert.ThrowsArgumentGreaterThanOrEqualTo(
  404. () => image.Crop(bottom: -1),
  405. "bottom",
  406. "0");
  407. Assert.ThrowsArgumentGreaterThanOrEqualTo(
  408. () => image.Crop(right: -1),
  409. "right",
  410. "0");
  411. }
  412. [Fact]
  413. public void RotateLeftReturnsRotatedImage()
  414. {
  415. WebImage image = new WebImage(_PngImageBytes);
  416. image.RotateLeft();
  417. Assert.Equal(152, image.Width);
  418. Assert.Equal(160, image.Height);
  419. }
  420. [Fact]
  421. public void RotateRightReturnsRotatedImage()
  422. {
  423. WebImage image = new WebImage(_PngImageBytes);
  424. image.RotateRight();
  425. Assert.Equal(152, image.Width);
  426. Assert.Equal(160, image.Height);
  427. }
  428. [Fact]
  429. public void FlipVerticalReturnsFlippedImage()
  430. {
  431. WebImage image = new WebImage(_PngImageBytes);
  432. image.FlipVertical();
  433. Assert.Equal(160, image.Width);
  434. Assert.Equal(152, image.Height);
  435. }
  436. [Fact]
  437. public void FlipHorizontalReturnsFlippedImage()
  438. {
  439. WebImage image = new WebImage(_PngImageBytes);
  440. image.FlipHorizontal();
  441. Assert.Equal(160, image.Width);
  442. Assert.Equal(152, image.Height);
  443. }
  444. [Fact]
  445. public void MultipleCombinedOperationsExecuteInRightOrder()
  446. {
  447. WebImage image = new WebImage(_JpgImageBytes);
  448. image.Resize(200, 100, preserveAspectRatio: true, preventEnlarge: true).RotateLeft();
  449. image.Crop(top: 10, right: 10).AddTextWatermark("plan9");
  450. Assert.Equal(90, image.Width);
  451. Assert.Equal(120, image.Height);
  452. }
  453. [Fact]
  454. public void AddTextWatermarkPreservesImageDimension()
  455. {
  456. WebImage image = new WebImage(_JpgImageBytes);
  457. image.AddTextWatermark("Plan9", fontSize: 16, horizontalAlign: "Left", verticalAlign: "Bottom", opacity: 50);
  458. Assert.Equal(634, image.Width);
  459. Assert.Equal(489, image.Height);
  460. }
  461. [Fact]
  462. public void AddTextWatermarkParsesHexColorCorrectly()
  463. {
  464. WebImage image = new WebImage(_JpgImageBytes);
  465. image.AddTextWatermark("Plan9", fontSize: 16, fontColor: "#FF0000", horizontalAlign: "Center", verticalAlign: "Middle");
  466. Assert.Equal(634, image.Width);
  467. Assert.Equal(489, image.Height);
  468. }
  469. [Fact]
  470. public void AddTextWatermarkParsesShortHexColorCorrectly()
  471. {
  472. WebImage image = new WebImage(_JpgImageBytes);
  473. image.AddTextWatermark("Plan9", fontSize: 16, fontColor: "#F00", horizontalAlign: "Center", verticalAlign: "Middle");
  474. Assert.Equal(634, image.Width);
  475. Assert.Equal(489, image.Height);
  476. }
  477. [Fact]
  478. public void AddTextWatermarkDoesNotChangeImageIfPaddingIsTooBig()
  479. {
  480. WebImage image = new WebImage(_JpgImageBytes);
  481. image.AddTextWatermark("Plan9", padding: 1000);
  482. Assert.Equal(634, image.Width);
  483. Assert.Equal(489, image.Height);
  484. }
  485. [Fact]
  486. public void AddTextWatermarkThrowsOnNegativeOpacity()
  487. {
  488. WebImage image = new WebImage(_JpgImageBytes);
  489. Assert.ThrowsArgumentOutOfRange(() => image.AddTextWatermark("Plan9", opacity: -1), "opacity", "Value must be between 0 and 100.");
  490. }
  491. [Fact]
  492. public void AddTextWatermarkThrowsOnTooBigOpacity()
  493. {
  494. WebImage image = new WebImage(_JpgImageBytes);
  495. Assert.ThrowsArgumentOutOfRange(() => image.AddTextWatermark("Plan9", opacity: 155), "opacity", "Value must be between 0 and 100.");
  496. }
  497. [Fact]
  498. public void AddTextWatermarkThrowsOnEmptyText()
  499. {
  500. WebImage image = new WebImage(_JpgImageBytes);
  501. Assert.ThrowsArgumentNullOrEmptyString(
  502. () => image.AddTextWatermark(""),
  503. "text");
  504. }
  505. [Fact]
  506. public void AddTextWatermarkThrowsOnIncorrectColorName()
  507. {
  508. WebImage image = new WebImage(_JpgImageBytes);
  509. Assert.Throws<ArgumentException>(
  510. () => image.AddTextWatermark("p9", fontColor: "super"),
  511. "The \"fontColor\" value is invalid. Valid values are names like \"White\", \"Black\", or \"DarkBlue\", or hexadecimal values in the form \"#RRGGBB\" or \"#RGB\".");
  512. }
  513. [Fact]
  514. public void AddTextWatermarkThrowsOnIncorrectHexColorValue()
  515. {
  516. WebImage image = new WebImage(_JpgImageBytes);
  517. Assert.Throws<ArgumentException>(
  518. () => image.AddTextWatermark("p9", fontColor: "#XXX"),
  519. "The \"fontColor\" value is invalid. Valid values are names like \"White\", \"Black\", or \"DarkBlue\", or hexadecimal values in the form \"#RRGGBB\" or \"#RGB\".");
  520. }
  521. [Fact]
  522. public void AddTextWatermarkThrowsOnIncorrectHexColorLength()
  523. {
  524. WebImage image = new WebImage(_JpgImageBytes);
  525. Assert.Throws<ArgumentException>(
  526. () => image.AddTextWatermark("p9", fontColor: "#F000"),
  527. "The \"fontColor\" value is invalid. Valid values are names like \"White\", \"Black\", or \"DarkBlue\", or hexadecimal values in the form \"#RRGGBB\" or \"#RGB\".");
  528. }
  529. [Fact]
  530. public void AddTextWatermarkThrowsOnIncorrectHorizontalAlignment()
  531. {
  532. WebImage image = new WebImage(_JpgImageBytes);
  533. Assert.Throws<ArgumentException>(
  534. () => image.AddTextWatermark("p9", horizontalAlign: "Justify"),
  535. "The \"horizontalAlign\" value is invalid. Valid values are: \"Right\", \"Left\", and \"Center\".");
  536. }
  537. [Fact]
  538. public void AddTextWatermarkThrowsOnIncorrectVerticalAlignment()
  539. {
  540. WebImage image = new WebImage(_JpgImageBytes);
  541. Assert.Throws<ArgumentException>(
  542. () => image.AddTextWatermark("p9", verticalAlign: "NotSet"),
  543. "The \"verticalAlign\" value is invalid. Valid values are: \"Top\", \"Bottom\", and \"Middle\".");
  544. }
  545. [Fact]
  546. public void AddTextWatermarkThrowsOnNegativePadding()
  547. {
  548. WebImage image = new WebImage(_JpgImageBytes);
  549. Assert.ThrowsArgumentGreaterThanOrEqualTo(
  550. () => image.AddTextWatermark("p9", padding: -10),
  551. "padding",
  552. "0");
  553. }
  554. [Fact]
  555. public void AddTextWatermarkThrowsOnIncorrectFontSize()
  556. {
  557. WebImage image = new WebImage(_JpgImageBytes);
  558. Assert.ThrowsArgumentGreaterThan(
  559. () => image.AddTextWatermark("p9", fontSize: -10),
  560. "fontSize",
  561. "0");
  562. Assert.ThrowsArgumentGreaterThan(
  563. () => image.AddTextWatermark("p9", fontSize: 0),
  564. "fontSize",
  565. "0");
  566. }
  567. [Fact]
  568. public void AddTextWatermarkThrowsOnIncorrectFontStyle()
  569. {
  570. WebImage image = new WebImage(_JpgImageBytes);
  571. Assert.Throws<ArgumentException>(
  572. () => image.AddTextWatermark("p9", fontStyle: "something"),
  573. "The \"fontStyle\" value is invalid. Valid values are: \"Regular\", \"Bold\", \"Italic\", \"Underline\", and \"Strikeout\".");
  574. }
  575. [Fact]
  576. public void AddTextWatermarkThrowsOnIncorrectFontFamily()
  577. {
  578. WebImage image = new WebImage(_JpgImageBytes);
  579. Assert.Throws<ArgumentException>(
  580. () => image.AddTextWatermark("p9", fontFamily: "something"),
  581. "The \"fontFamily\" value is invalid. Valid values are font family names like: \"Arial\", \"Times New Roman\", etc. Make sure that the font family you are trying to use is installed on the server.");
  582. }
  583. [Fact]
  584. public void AddImageWatermarkPreservesImageDimension()
  585. {
  586. WebImage watermark = new WebImage(_BmpImageBytes);
  587. WebImage image = new WebImage(_JpgImageBytes);
  588. image.AddImageWatermark(watermark, horizontalAlign: "LEFT", verticalAlign: "top", opacity: 50, padding: 10);
  589. Assert.Equal(634, image.Width);
  590. Assert.Equal(489, image.Height);
  591. }
  592. [Fact]
  593. public void CanAddTextAndImageWatermarks()
  594. {
  595. WebImage watermark = new WebImage(_BmpImageBytes);
  596. WebImage image = new WebImage(_JpgImageBytes);
  597. image.AddImageWatermark(watermark, horizontalAlign: "LEFT", verticalAlign: "top", opacity: 30, padding: 10);
  598. image.AddTextWatermark("plan9");
  599. Assert.Equal(634, image.Width);
  600. Assert.Equal(489, image.Height);
  601. }
  602. [Fact]
  603. public void AddImageWatermarkDoesNotChangeWatermarkImage()
  604. {
  605. WebImage watermark = new WebImage(_BmpImageBytes);
  606. WebImage image = new WebImage(_JpgImageBytes);
  607. image.AddImageWatermark(watermark, width: 54, height: 22, horizontalAlign: "LEFT", verticalAlign: "top", opacity: 50, padding: 10);
  608. Assert.Equal(108, watermark.Width);
  609. Assert.Equal(44, watermark.Height);
  610. }
  611. [Fact]
  612. public void AddImageWatermarkThrowsOnNullImage()
  613. {
  614. WebImage image = new WebImage(_JpgImageBytes);
  615. Assert.ThrowsArgumentNull(
  616. () => image.AddImageWatermark(watermarkImage: null),
  617. "watermarkImage");
  618. }
  619. [Fact]
  620. public void AddImageWatermarkThrowsWhenJustOneDimensionIsZero()
  621. {
  622. WebImage watermark = new WebImage(_BmpImageBytes);
  623. WebImage image = new WebImage(_JpgImageBytes);
  624. string message = "Watermark width and height must both be positive or both be zero.";
  625. Assert.Throws<ArgumentException>(
  626. () => image.AddImageWatermark(watermark, width: 0, height: 22), message);
  627. Assert.Throws<ArgumentException>(
  628. () => image.AddImageWatermark(watermark, width: 100, height: 0), message);
  629. }
  630. [Fact]
  631. public void AddImageWatermarkThrowsWhenOpacityIsIncorrect()
  632. {
  633. WebImage watermark = new WebImage(_BmpImageBytes);
  634. WebImage image = new WebImage(_JpgImageBytes);
  635. Assert.ThrowsArgumentOutOfRange(() => image.AddImageWatermark(watermark, opacity: -1), "opacity", "Value must be between 0 and 100.");
  636. Assert.ThrowsArgumentOutOfRange(() => image.AddImageWatermark(watermark, opacity: 120), "opacity", "Value must be between 0 and 100.");
  637. }
  638. [Fact]
  639. public void AddImageWatermarkThrowsOnNegativeDimensions()
  640. {
  641. WebImage watermark = new WebImage(_BmpImageBytes);
  642. WebImage image = new WebImage(_JpgImageBytes);
  643. Assert.ThrowsArgumentGreaterThanOrEqualTo(
  644. () => image.AddImageWatermark(watermark, width: -1),
  645. "width",
  646. "0");
  647. Assert.ThrowsArgumentGreaterThanOrEqualTo(
  648. () => image.AddImageWatermark(watermark, height: -1),
  649. "height",
  650. "0");
  651. }
  652. [Fact]
  653. public void AddImageWatermarkThrowsOnIncorrectHorizontalAlignment()
  654. {
  655. WebImage watermark = new WebImage(_BmpImageBytes);
  656. WebImage image = new WebImage(_JpgImageBytes);
  657. Assert.Throws<ArgumentException>(
  658. () => image.AddImageWatermark(watermark, horizontalAlign: "horizontal"),
  659. "The \"horizontalAlign\" value is invalid. Valid values are: \"Right\", \"Left\", and \"Center\".");
  660. }
  661. [Fact]
  662. public void AddImageWatermarkThrowsOnIncorrectVerticalAlignment()
  663. {
  664. WebImage watermark = new WebImage(_BmpImageBytes);
  665. WebImage image = new WebImage(_JpgImageBytes);
  666. Assert.Throws<ArgumentException>(
  667. () => image.AddImageWatermark(watermark, verticalAlign: "vertical"),
  668. "The \"verticalAlign\" value is invalid. Valid values are: \"Top\", \"Bottom\", and \"Middle\".");
  669. }
  670. [Fact]
  671. public void AddImageWatermarkThrowsOnNegativePadding()
  672. {
  673. WebImage watermark = new WebImage(_BmpImageBytes);
  674. WebImage image = new WebImage(_JpgImageBytes);
  675. Assert.ThrowsArgumentGreaterThanOrEqualTo(
  676. () => image.AddImageWatermark(watermark, padding: -10),
  677. "padding",
  678. "0");
  679. }
  680. [Fact]
  681. public void AddImageWatermarkDoesNotChangeImageIfWatermarkIsTooBig()
  682. {
  683. WebImage watermark = new WebImage(_JpgImageBytes);
  684. WebImage image = new WebImage(_BmpImageBytes);
  685. byte[] originalBytes = image.GetBytes("jpg");
  686. // This will use original watermark image dimensions which is bigger than the target image.
  687. image.AddImageWatermark(watermark);
  688. byte[] watermarkedBytes = image.GetBytes("jpg");
  689. Assert.Equal(originalBytes, watermarkedBytes);
  690. }
  691. [Fact]
  692. public void AddImageWatermarkWithFileNameThrowsExceptionWhenWatermarkDirectoryDoesNotExist()
  693. {
  694. var context = GetContext();
  695. WebImage image = new WebImage(_BmpImageBytes);
  696. Assert.Throws<DirectoryNotFoundException>(
  697. () => image.AddImageWatermark(context, s => { throw new DirectoryNotFoundException(); }, @"x:\path\does\not\exist", width: 0, height: 0, horizontalAlign: "Right", verticalAlign: "Bottom", opacity: 100, padding: 5));
  698. }
  699. [Fact]
  700. public void AddImageWatermarkWithFileNameThrowsExceptionWhenWatermarkFileDoesNotExist()
  701. {
  702. var context = GetContext();
  703. WebImage image = new WebImage(_BmpImageBytes);
  704. Assert.Throws<FileNotFoundException>(
  705. () => image.AddImageWatermark(context, s => { throw new FileNotFoundException(); }, @"x:\there-is-no-file.jpg", width: 0, height: 0, horizontalAlign: "Right", verticalAlign: "Bottom", opacity: 100, padding: 5));
  706. }
  707. [Fact]
  708. public void AddImageWatermarkWithFileNameThrowsExceptionWhenWatermarkFilePathIsNull()
  709. {
  710. var context = GetContext();
  711. WebImage image = new WebImage(_BmpImageBytes);
  712. Assert.ThrowsArgument(
  713. () => image.AddImageWatermark(context, s => _JpgImageBytes, watermarkImageFilePath: null, width: 0, height: 0, horizontalAlign: "Right", verticalAlign: "Bottom", opacity: 100, padding: 5),
  714. "filePath",
  715. "Value cannot be null or an empty string.");
  716. }
  717. [Fact]
  718. public void AddImageWatermarkWithFileNameThrowsExceptionWhenWatermarkFilePathIsEmpty()
  719. {
  720. var context = GetContext();
  721. WebImage image = new WebImage(_BmpImageBytes);
  722. Assert.ThrowsArgument(
  723. () => image.AddImageWatermark(context, s => _JpgImageBytes, watermarkImageFilePath: null, width: 0, height: 0, horizontalAlign: "Right", verticalAlign: "Bottom", opacity: 100, padding: 5),
  724. "filePath",
  725. "Value cannot be null or an empty string.");
  726. }
  727. [Fact]
  728. public void CanAddImageWatermarkWithFileName()
  729. {
  730. // Arrange
  731. var context = GetContext();
  732. WebImage image = new WebImage(_BmpImageBytes);
  733. WebImage watermark = new WebImage(_JpgImageBytes);
  734. // Act
  735. var watermarkedWithImageArgument = image.AddImageWatermark(watermark).GetBytes();
  736. var watermarkedWithFilePathArgument = image.AddImageWatermark(context, (name) => _JpgImageBytes, @"x:\jpegimage.jpg", width: 0, height: 0, horizontalAlign: "Right", verticalAlign: "Bottom", opacity: 100, padding: 5).GetBytes();
  737. Assert.Equal(watermarkedWithImageArgument, watermarkedWithFilePathArgument);
  738. }
  739. [Fact]
  740. public void SaveOverwritesExistingFile()
  741. {
  742. Action<string, byte[]> saveAction = (path, content) => { };
  743. WebImage image = new WebImage(_BmpImageBytes);
  744. string newFileName = @"x:\newImage.bmp";
  745. image.Save(GetContext(), saveAction, newFileName, imageFormat: null, forceWellKnownExtension: true);
  746. image.RotateLeft();
  747. // just verify this does not throw
  748. image.Save(GetContext(), saveAction, newFileName, imageFormat: null, forceWellKnownExtension: true);
  749. }
  750. [Fact]
  751. public void SaveThrowsWhenPathIsNull()
  752. {
  753. Action<string, byte[]> saveAction = (path, content) => { };
  754. // this constructor will not set path
  755. byte[] originalContent = _BmpImageBytes;
  756. WebImage image = new WebImage(originalContent);
  757. Assert.ThrowsArgumentNullOrEmptyString(
  758. () => image.Save(GetContext(), saveAction, filePath: null, imageFormat: null, forceWellKnownExtension: true),
  759. "filePath");
  760. }
  761. [Fact]
  762. public void SaveThrowsWhenPathIsEmpty()
  763. {
  764. Action<string, byte[]> saveAction = (path, content) => { };
  765. WebImage image = new WebImage(_BmpImageBytes);
  766. Assert.ThrowsArgumentNullOrEmptyString(
  767. () => image.Save(GetContext(), saveAction, filePath: String.Empty, imageFormat: null, forceWellKnownExtension: true),
  768. "filePath");
  769. }
  770. [Fact]
  771. public void SaveUsesOriginalFormatWhenNoFormatIsSpecified()
  772. {
  773. // Arrange
  774. // Use rooted path so we by pass using HttpContext
  775. var specifiedOutputFile = @"C:\some-dir\foo.jpg";
  776. string actualOutputFile = null;
  777. Action<string, byte[]> saveAction = (fileName, content) => { actualOutputFile = fileName; };
  778. // Act
  779. WebImage image = new WebImage(_PngImageBytes);
  780. image.Save(GetContext(), saveAction, filePath: specifiedOutputFile, imageFormat: null, forceWellKnownExtension: true);
  781. // Assert
  782. Assert.Equal(Path.GetExtension(actualOutputFile), ".png");
  783. }
  784. [Fact]
  785. public void SaveUsesOriginalFormatForStreamsWhenNoFormatIsSpecified()
  786. {
  787. // Arrange
  788. // Use rooted path so we by pass using HttpContext
  789. var specifiedOutputFile = @"x:\some-dir\foo.jpg";
  790. string actualOutputFile = null;
  791. Action<string, byte[]> saveAction = (fileName, content) => { actualOutputFile = fileName; };
  792. // Act
  793. WebImage image = new WebImage(_PngImageBytes);
  794. image.Save(GetContext(), saveAction, filePath: specifiedOutputFile, imageFormat: null, forceWellKnownExtension: true);
  795. // Assert
  796. Assert.Equal(Path.GetExtension(actualOutputFile), ".png");
  797. }
  798. [Fact]
  799. public void SaveSetsExtensionBasedOnFormatWhenForceExtensionIsSet()
  800. {
  801. // Arrange
  802. // Use rooted path so we by pass using HttpContext
  803. var specifiedOutputFile = @"x:\some-dir\foo.exe";
  804. string actualOutputFile = null;
  805. Action<string, byte[]> saveAction = (fileName, content) => { actualOutputFile = fileName; };
  806. // Act
  807. WebImage image = new WebImage(_BmpImageBytes);
  808. image.Save(GetContext(), saveAction, filePath: specifiedOutputFile, imageFormat: "jpg", forceWellKnownExtension: true);
  809. // Assert
  810. Assert.Equal(".jpeg", Path.GetExtension(actualOutputFile));
  811. Assert.Equal(specifiedOutputFile + ".jpeg", actualOutputFile);
  812. }
  813. [Fact]
  814. public void SaveAppendsExtensionBasedOnFormatWhenForceExtensionIsSet()
  815. {
  816. // Arrange
  817. // Use rooted path so we by pass using HttpContext
  818. var specifiedOutputFile = @"x:\some-dir\foo";
  819. string actualOutputFile = null;
  820. Action<string, byte[]> saveAction = (fileName, content) => { actualOutputFile = fileName; };
  821. // Act
  822. WebImage image = new WebImage(_BmpImageBytes);
  823. image.Save(GetContext(), saveAction, filePath: specifiedOutputFile, imageFormat: "jpg", forceWellKnownExtension: true);
  824. // Assert
  825. Assert.Equal(".jpeg", Path.GetExtension(actualOutputFile));
  826. }
  827. [Fact]
  828. public void SaveDoesNotModifyExtensionWhenExtensionIsCorrect()
  829. {
  830. // Arrange
  831. // Use rooted path so we by pass using HttpContext
  832. var specifiedOutputFile = @"x:\some-dir\foo.jpg";
  833. string actualOutputFile = null;
  834. Action<string, byte[]> saveAction = (fileName, content) => { actualOutputFile = fileName; };
  835. // Act
  836. WebImage image = new WebImage(_BmpImageBytes);
  837. image.Save(GetContext(), saveAction, filePath: specifiedOutputFile, imageFormat: "jpg", forceWellKnownExtension: true);
  838. // Assert
  839. Assert.Equal(specifiedOutputFile, actualOutputFile);
  840. }
  841. [Fact]
  842. public void SaveDoesNotModifyExtensionWhenForceCorrectExtensionRenameIsCleared()
  843. {
  844. // Arrange
  845. // Use rooted path so we by pass using HttpContext
  846. var specifiedOutputFile = @"x:\some-dir\foo.exe";
  847. string actualOutputFile = null;
  848. Action<string, byte[]> saveAction = (fileName, content) => { actualOutputFile = fileName; };
  849. // Act
  850. WebImage image = new WebImage(_BmpImageBytes);
  851. image.Save(GetContext(), saveAction, filePath: specifiedOutputFile, imageFormat: "jpg", forceWellKnownExtension: false);
  852. // Assert
  853. Assert.Equal(specifiedOutputFile, actualOutputFile);
  854. }
  855. [Fact]
  856. public void ImageFormatIsSavedCorrectly()
  857. {
  858. WebImage image = new WebImage(_BmpImageBytes);
  859. Assert.Equal("bmp", image.ImageFormat);
  860. }
  861. [Fact]
  862. public void SaveUsesInitialFormatWhenNoFormatIsSpecified()
  863. {
  864. // Arrange
  865. string savePath = @"x:\some-dir\image.png";
  866. MemoryStream stream = null;
  867. Action<string, byte[]> saveAction = (path, content) => { stream = new MemoryStream(content); };
  868. var image = new WebImage(_PngImageBytes);
  869. // Act
  870. image.FlipVertical().FlipHorizontal();
  871. // Assert
  872. image.Save(GetContext(), saveAction, savePath, imageFormat: null, forceWellKnownExtension: true);
  873. using (Image savedImage = Image.FromStream(stream))
  874. {
  875. Assert.Equal(savedImage.RawFormat, ImageFormat.Png);
  876. }
  877. }
  878. [Fact]
  879. public void ImageFormatIsParsedCorrectly()
  880. {
  881. WebImage image = new WebImage(_BmpImageBytes);
  882. Assert.Equal("bmp", image.ImageFormat);
  883. }
  884. private static HttpContextBase GetContext()
  885. {
  886. var httpContext = new Mock<HttpContextBase>();
  887. var httpRequest = new Mock<HttpRequestBase>();
  888. httpRequest.Setup(c => c.MapPath(It.IsAny<string>())).Returns((string path) => path);
  889. httpContext.Setup(c => c.Request).Returns(httpRequest.Object);
  890. return httpContext.Object;
  891. }
  892. // Test stream that pretends it can't seek.
  893. private class TestStream : Stream
  894. {
  895. private MemoryStream _memoryStream;
  896. public TestStream(MemoryStream memoryStream)
  897. {
  898. _memoryStream = memoryStream;
  899. }
  900. public override bool CanRead
  901. {
  902. get { return _memoryStream.CanRead; }
  903. }
  904. public override bool CanSeek
  905. {
  906. get { return false; }
  907. }
  908. public override bool CanWrite
  909. {
  910. get { return _memoryStream.CanWrite; }
  911. }
  912. public override void Flush()
  913. {
  914. _memoryStream.Flush();
  915. }
  916. public override long Length
  917. {
  918. get { throw new NotSupportedException(); }
  919. }
  920. public override long Position
  921. {
  922. get { return _memoryStream.Position; }
  923. set { _memoryStream.Position = value; }
  924. }
  925. public override int Read(byte[] buffer, int offset, int count)
  926. {
  927. return _memoryStream.Read(buffer, offset, count);
  928. }
  929. public override long Seek(long offset, SeekOrigin origin)
  930. {
  931. throw new NotSupportedException();
  932. }
  933. public override void SetLength(long value)
  934. {
  935. _memoryStream.SetLength(value);
  936. }
  937. public override void Write(byte[] buffer, int offset, int count)
  938. {
  939. _memoryStream.Write(buffer, offset, count);
  940. }
  941. }
  942. }
  943. }