ImageToolsDroid.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using System;
  2. using System.Drawing;
  3. using System.IO;
  4. using System.Threading.Tasks;
  5. using Android.Graphics;
  6. using Android.Media;
  7. using Java.IO;
  8. using Xamarin.Essentials;
  9. using Bitmap = Android.Graphics.Bitmap;
  10. using File = System.IO.File;
  11. using Path = System.IO.Path;
  12. using Stream = System.IO.Stream;
  13. [assembly: Xamarin.Forms.Dependency(typeof(InABox.Mobile.Android.ImageToolsDroid))]
  14. namespace InABox.Mobile.Android
  15. {
  16. public class ImageToolsDroid: IImageTools
  17. {
  18. public byte[] CreateVideoThumbnail(byte[] video, int maxwidth, int maxheight)
  19. {
  20. byte[] result = null;
  21. var filename = Path.Combine(
  22. Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
  23. $"{Guid.NewGuid().ToString()}.tmp"
  24. );
  25. File.WriteAllBytes(filename,video);
  26. using (FileInputStream fs = new FileInputStream(filename))
  27. {
  28. FileDescriptor fd = fs.FD;
  29. MediaMetadataRetriever retriever = new MediaMetadataRetriever();
  30. retriever.SetDataSource(fd);
  31. Bitmap bitmap = retriever.GetFrameAtTime(0);
  32. if (bitmap != null)
  33. {
  34. bitmap = ScaleImage(bitmap, new Size(maxwidth, maxheight));
  35. MemoryStream stream = new MemoryStream();
  36. bitmap.Compress(Bitmap.CompressFormat.Png, 60, stream);
  37. result = stream.ToArray();
  38. }
  39. }
  40. File.Delete(filename);
  41. return result;
  42. }
  43. public byte[] CreateThumbnail(byte[] source, int maxwidth, int maxheight)
  44. {
  45. return ScaleImage(source, new Size(maxwidth, maxheight), 60);
  46. }
  47. public enum ImageOrientation
  48. {
  49. Undefined = 0,
  50. Normal = 1,
  51. FlipHorizontal = 2,
  52. Rotate180 = 3,
  53. FlipVertical = 4,
  54. Transpose = 5,
  55. Rotate90 = 6,
  56. Transverse = 7,
  57. Rotate270 = 8
  58. }
  59. public async Task<FileResult> PickPhotoAsync(int? compression, Size? constraints)
  60. {
  61. var fileResult = await MediaPicker.PickPhotoAsync();
  62. if (fileResult == null)
  63. return null;
  64. return await ProcessFile(fileResult, compression, constraints);
  65. }
  66. public async Task<FileResult> CapturePhotoAsync(int? compression, Size? constraints)
  67. {
  68. var fileResult = await MediaPicker.CapturePhotoAsync();
  69. if (fileResult == null)
  70. return null;
  71. return await ProcessFile(fileResult, compression, constraints);
  72. }
  73. private async Task<FileResult> ProcessFile(FileResult fileResult, int? compression, Size? constraints)
  74. {
  75. await using var stream = await fileResult.OpenReadAsync();
  76. var orientation = GetImageOrientation(stream);
  77. var source = await BitmapFactory.DecodeStreamAsync(stream);
  78. var rotated = RotateImage(source, orientation);
  79. var scaled = ScaleImage(rotated, constraints);
  80. var jpegFilename = Path.Combine(FileSystem.CacheDirectory, $"{Guid.NewGuid()}.jpg");
  81. using (var outStream = new MemoryStream())
  82. {
  83. await scaled.CompressAsync(Bitmap.CompressFormat.Jpeg, compression ?? 100, outStream);
  84. outStream.Position = 0;
  85. await File.WriteAllBytesAsync(jpegFilename, outStream.ToArray());
  86. }
  87. return new FileResult(jpegFilename);
  88. }
  89. private static Bitmap RotateImage(Bitmap source, ImageOrientation orientation)
  90. {
  91. var matrix = new Matrix();
  92. switch (orientation)
  93. {
  94. case ImageOrientation.Normal:
  95. break;
  96. case ImageOrientation.FlipHorizontal:
  97. break;
  98. case ImageOrientation.Rotate180:
  99. break;
  100. case ImageOrientation.FlipVertical:
  101. matrix.PreRotate(180);
  102. break;
  103. case ImageOrientation.Transpose:
  104. matrix.PreRotate(90);
  105. break;
  106. case ImageOrientation.Rotate90:
  107. matrix.PreRotate(90);
  108. break;
  109. case ImageOrientation.Transverse:
  110. matrix.PreRotate(-90);
  111. break;
  112. case ImageOrientation.Rotate270:
  113. matrix.PreRotate(-90);
  114. break;
  115. }
  116. return Bitmap.CreateBitmap(
  117. source,
  118. 0,
  119. 0,
  120. source.Width,
  121. source.Height,
  122. matrix,
  123. true);
  124. }
  125. private ImageOrientation GetImageOrientation(Stream stream)
  126. {
  127. var exif = new ExifInterface(stream);
  128. var tag = exif.GetAttribute(ExifInterface.TagOrientation);
  129. var orientation = string.IsNullOrEmpty(tag) ?
  130. ImageOrientation.Undefined :
  131. (ImageOrientation)Enum.Parse(typeof(ImageOrientation), tag);
  132. exif.Dispose();
  133. stream.Position = 0;
  134. return orientation;
  135. }
  136. private static Bitmap ScaleImage(Bitmap source, Size? constraints)
  137. {
  138. var maxwidth = constraints?.Width ?? source.Width;
  139. var maxheight = constraints?.Height ?? source.Height;
  140. var wRatio = maxwidth < source.Width
  141. ? maxwidth / (double)source.Width
  142. : 1.0F;
  143. var hRatio = maxheight < source.Height
  144. ? maxheight / (double)source.Height
  145. : 1.0F;
  146. var ratio = Math.Min(hRatio, wRatio);
  147. var result = (ratio < 1.0F)
  148. ? Bitmap.CreateScaledBitmap(
  149. source,
  150. (int)(source.Width * ratio),
  151. (int)(source.Height * ratio),
  152. true)
  153. : source;
  154. return result;
  155. }
  156. public byte[] RotateImage(byte[] source, float angle, int compression = 100)
  157. {
  158. if (angle % 360 == 0)
  159. return source;
  160. byte[] result = { };
  161. using (var image = BitmapFactory.DecodeByteArray(source, 0, source.Length))
  162. {
  163. if (image != null)
  164. {
  165. var matrix = new Matrix();
  166. matrix.PreRotate(angle);
  167. var rotated = Bitmap.CreateBitmap(
  168. image,
  169. 0,
  170. 0,
  171. image.Width,
  172. image.Height,
  173. matrix,
  174. true);
  175. if (rotated != null)
  176. {
  177. using (var ms = new MemoryStream())
  178. {
  179. rotated.Compress(Bitmap.CompressFormat.Jpeg, compression, ms);
  180. result = ms.ToArray();
  181. }
  182. }
  183. }
  184. }
  185. return result;
  186. }
  187. public byte[] ScaleImage(byte[] source, Size? constraints, int compression = 100)
  188. {
  189. byte[] result = { };
  190. using (var image = BitmapFactory.DecodeByteArray(source, 0, source.Length))
  191. {
  192. if (image != null)
  193. {
  194. var scaled = ScaleImage(image, constraints);
  195. using (var ms = new MemoryStream())
  196. {
  197. scaled.Compress(Bitmap.CompressFormat.Jpeg, compression, ms);
  198. result = ms.ToArray();
  199. }
  200. }
  201. }
  202. return result;
  203. }
  204. }
  205. }