135 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
| import 'dart:typed_data';
 | |
| import 'package:image/image.dart';
 | |
| 
 | |
| class ExifCleaner {
 | |
|   static List<int> removeExifData(List<int> imageBytes) {
 | |
|       // Decode the image (this strips EXIF data)
 | |
|       final Image? image = decodeImage(Uint8List.fromList(imageBytes));
 | |
| 
 | |
|       if (image == null) {
 | |
|         throw Exception('Failed to decode image');
 | |
|       }
 | |
| 
 | |
|       // Encode back to bytes without EXIF based on detected format
 | |
|       List<int> cleanedBytes;
 | |
| 
 | |
|       image.exif.clear();
 | |
| 
 | |
|       if (_isJpeg(imageBytes)) {
 | |
|         cleanedBytes = encodeJpg(image);
 | |
|       } else if (_isPng(imageBytes)) {
 | |
|         cleanedBytes = encodePng(image);
 | |
|       } else if (_isGif(imageBytes)) {
 | |
|         cleanedBytes = encodeGif(image);
 | |
|       } else if (_isBmp(imageBytes)) {
 | |
|         cleanedBytes = encodeBmp(image);
 | |
|       } else if (_isTiff(imageBytes)) {
 | |
|         // TIFF doesn't have a direct encoder in image package, convert to PNG
 | |
|         cleanedBytes = encodeTiff(image);
 | |
|       } else if (_isHeic(imageBytes)) {
 | |
|         // HEIC format - convert to JPEG since image package doesn't have HEIC encoder
 | |
|         cleanedBytes = encodeJpg(image);
 | |
|       } else {
 | |
|         // Default fallback - try to encode as PNG, then JPEG
 | |
|         try {
 | |
|           cleanedBytes = encodePng(image);
 | |
|         } catch (e) {
 | |
|           cleanedBytes = encodeJpg(image);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       return cleanedBytes;
 | |
|   }
 | |
| 
 | |
|   static bool _isJpeg(List<int> bytes) {
 | |
|     return bytes.length >= 2 && bytes[0] == 0xFF && bytes[1] == 0xD8;
 | |
|   }
 | |
| 
 | |
|   static bool _isPng(List<int> bytes) {
 | |
|     return bytes.length >= 8 &&
 | |
|         bytes[0] == 0x89 &&
 | |
|         bytes[1] == 0x50 &&
 | |
|         bytes[2] == 0x4E &&
 | |
|         bytes[3] == 0x47;
 | |
|   }
 | |
| 
 | |
|   static bool _isGif(List<int> bytes) {
 | |
|     return bytes.length >= 6 &&
 | |
|         bytes[0] == 0x47 && // G
 | |
|         bytes[1] == 0x49 && // I
 | |
|         bytes[2] == 0x46 && // F
 | |
|         bytes[3] == 0x38 && // 8
 | |
|         (bytes[4] == 0x37 || bytes[4] == 0x39) && // 7 or 9
 | |
|         bytes[5] == 0x61; // a
 | |
|   }
 | |
| 
 | |
|   static bool _isBmp(List<int> bytes) {
 | |
|     return bytes.length >= 2 &&
 | |
|         bytes[0] == 0x42 && // B
 | |
|         bytes[1] == 0x4D;   // M
 | |
|   }
 | |
| 
 | |
|   static bool _isTiff(List<int> bytes) {
 | |
|     return bytes.length >= 4 &&
 | |
|         ((bytes[0] == 0x49 && bytes[1] == 0x49 && bytes[2] == 0x2A && bytes[3] == 0x00) || // Little Endian
 | |
|          (bytes[0] == 0x4D && bytes[1] == 0x4D && bytes[2] == 0x00 && bytes[3] == 0x2A)); // Big Endian
 | |
|   }
 | |
| 
 | |
|   static bool _isWebP(List<int> bytes) {
 | |
|     return bytes.length >= 12 &&
 | |
|         bytes[0] == 0x52 && // R
 | |
|         bytes[1] == 0x49 && // I
 | |
|         bytes[2] == 0x46 && // F
 | |
|         bytes[3] == 0x46 && // F
 | |
|         bytes[8] == 0x57 && // W
 | |
|         bytes[9] == 0x45 && // E
 | |
|         bytes[10] == 0x42 && // B
 | |
|         bytes[11] == 0x50;   // P
 | |
|   }
 | |
| 
 | |
|   static bool _isHeic(List<int> bytes) {
 | |
|     // HEIC files start with 'ftyp' at position 4
 | |
|     if (bytes.length < 12) return false;
 | |
|     
 | |
|     // Check for 'ftyp' at position 4
 | |
|     bool hasFtyp = bytes[4] == 0x66 && // f
 | |
|                    bytes[5] == 0x74 && // t
 | |
|                    bytes[6] == 0x79 && // y
 | |
|                    bytes[7] == 0x70;   // p
 | |
|     
 | |
|     if (!hasFtyp) return false;
 | |
|     
 | |
|     // Check for HEIC brand variants
 | |
|     List<List<int>> heicBrands = [
 | |
|       [0x68, 0x65, 0x69, 0x63], // heic
 | |
|       [0x68, 0x65, 0x69, 0x78], // heix
 | |
|       [0x68, 0x65, 0x76, 0x63], // hevc
 | |
|       [0x68, 0x65, 0x76, 0x78], // hevx
 | |
|       [0x6D, 0x69, 0x66, 0x31], // mif1
 | |
|       [0x6D, 0x73, 0x66, 0x31], // msf1
 | |
|     ];
 | |
|     
 | |
|     for (var brand in heicBrands) {
 | |
|       if (bytes[8] == brand[0] &&
 | |
|           bytes[9] == brand[1] &&
 | |
|           bytes[10] == brand[2] &&
 | |
|           bytes[11] == brand[3]) {
 | |
|         return true;
 | |
|       }
 | |
|     }
 | |
|     
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Utility method to get image format name
 | |
|   static String getImageFormat(List<int> bytes) {
 | |
|     if (_isJpeg(bytes)) return 'JPEG';
 | |
|     if (_isPng(bytes)) return 'PNG';
 | |
|     if (_isGif(bytes)) return 'GIF';
 | |
|     if (_isBmp(bytes)) return 'BMP';
 | |
|     if (_isTiff(bytes)) return 'TIFF';
 | |
|     if (_isWebP(bytes)) return 'WebP';
 | |
|     if (_isHeic(bytes)) return 'HEIC';
 | |
|     return 'Unknown';
 | |
|   }
 | |
| } |