ImageTools.Android.cs 7.8 KB

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