diff --git a/machine_learning/Dockerfile b/machine_learning/Dockerfile index acca831d6d..f575b479ef 100644 --- a/machine_learning/Dockerfile +++ b/machine_learning/Dockerfile @@ -13,6 +13,9 @@ ## CPU BUILD FROM python:3.8 as cpu +RUN apt-get update +RUN apt-get install ffmpeg libsm6 libxext6 -y + WORKDIR /code COPY ./requirements.txt /code/requirements.txt diff --git a/machine_learning/app/image_classifier/image_classifier.py b/machine_learning/app/image_classifier/image_classifier.py index c3c130124b..73fb692c02 100644 --- a/machine_learning/app/image_classifier/image_classifier.py +++ b/machine_learning/app/image_classifier/image_classifier.py @@ -2,15 +2,20 @@ from tensorflow.keras.applications import InceptionV3 from tensorflow.keras.applications.inception_v3 import preprocess_input, decode_predictions from tensorflow.keras.preprocessing import image import numpy as np - +from PIL import Image +import cv2 IMG_SIZE = 299 PREDICTION_MODEL = InceptionV3(weights='imagenet') def classify_image(image_path: str): img_path = f'./app/{image_path}' - img = image.load_img(img_path, target_size=(IMG_SIZE, IMG_SIZE)) - x = image.img_to_array(img) + # img = image.load_img(img_path, target_size=(IMG_SIZE, IMG_SIZE)) + + target_image = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) + resized_target_image = cv2.resize(target_image, (IMG_SIZE, IMG_SIZE)) + + x = image.img_to_array(resized_target_image) x = np.expand_dims(x, axis=0) x = preprocess_input(x) diff --git a/machine_learning/requirements.txt b/machine_learning/requirements.txt index dc6cea1468..c1d9129272 100644 --- a/machine_learning/requirements.txt +++ b/machine_learning/requirements.txt @@ -1,3 +1,4 @@ +opencv-python==4.5.5.64 fastapi>=0.68.0,<0.69.0 pydantic>=1.8.0,<2.0.0 uvicorn>=0.15.0,<0.16.0 diff --git a/mobile/lib/modules/home/ui/profile_drawer.dart b/mobile/lib/modules/home/ui/profile_drawer.dart index e57e2372db..6e6e406280 100644 --- a/mobile/lib/modules/home/ui/profile_drawer.dart +++ b/mobile/lib/modules/home/ui/profile_drawer.dart @@ -1,18 +1,36 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/modules/home/providers/asset.provider.dart'; import 'package:immich_mobile/modules/login/models/authentication_state.model.dart'; import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; import 'package:immich_mobile/shared/providers/backup.provider.dart'; import 'package:immich_mobile/shared/providers/websocket.provider.dart'; +import 'package:package_info_plus/package_info_plus.dart'; -class ProfileDrawer extends ConsumerWidget { +class ProfileDrawer extends HookConsumerWidget { const ProfileDrawer({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { AuthenticationState _authState = ref.watch(authenticationProvider); + final appInfo = useState({}); + + _getPackageInfo() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + + appInfo.value = { + "version": packageInfo.version, + "buildNumber": packageInfo.buildNumber, + }; + } + + useEffect(() { + _getPackageInfo(); + + return null; + }, []); return Drawer( shape: const RoundedRectangleBorder( @@ -21,50 +39,68 @@ class ProfileDrawer extends ConsumerWidget { bottomRight: Radius.circular(5), ), ), - child: ListView( - padding: EdgeInsets.zero, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - DrawerHeader( - decoration: BoxDecoration( - color: Colors.grey[200], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Image( - image: AssetImage('assets/immich-logo-no-outline.png'), - width: 50, - filterQuality: FilterQuality.high, + ListView( + shrinkWrap: true, + padding: EdgeInsets.zero, + children: [ + DrawerHeader( + decoration: BoxDecoration( + color: Colors.grey[200], ), - const Padding(padding: EdgeInsets.all(8)), - Text( - _authState.userEmail, - style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold), - ) - ], - ), - ), - ListTile( - tileColor: Colors.grey[100], - leading: const Icon( - Icons.logout_rounded, - color: Colors.black54, - ), - title: const Text( - "Sign Out", - style: TextStyle(color: Colors.black54, fontSize: 14), - ), - onTap: () async { - bool res = await ref.read(authenticationProvider.notifier).logout(); + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Image( + image: AssetImage('assets/immich-logo-no-outline.png'), + width: 50, + filterQuality: FilterQuality.high, + ), + const Padding(padding: EdgeInsets.all(8)), + Text( + _authState.userEmail, + style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold), + ) + ], + ), + ), + ListTile( + tileColor: Colors.grey[100], + leading: const Icon( + Icons.logout_rounded, + color: Colors.black54, + ), + title: const Text( + "Sign Out", + style: TextStyle(color: Colors.black54, fontSize: 14), + ), + onTap: () async { + bool res = await ref.read(authenticationProvider.notifier).logout(); - if (res) { - ref.watch(backupProvider.notifier).cancelBackup(); - ref.watch(assetProvider.notifier).clearAllAsset(); - ref.watch(websocketProvider.notifier).disconnect(); - AutoRouter.of(context).popUntilRoot(); - } - }, + if (res) { + ref.watch(backupProvider.notifier).cancelBackup(); + ref.watch(assetProvider.notifier).clearAllAsset(); + ref.watch(websocketProvider.notifier).disconnect(); + AutoRouter.of(context).popUntilRoot(); + } + }, + ) + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "Version V${appInfo.value["version"]}+${appInfo.value["buildNumber"]}", + style: TextStyle( + fontSize: 12, + color: Colors.grey[400], + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + ), + ), ) ], ), diff --git a/mobile/lib/utils/files_helper.dart b/mobile/lib/utils/files_helper.dart index b2e1b5e7ee..1c9d64cc52 100644 --- a/mobile/lib/utils/files_helper.dart +++ b/mobile/lib/utils/files_helper.dart @@ -32,6 +32,9 @@ class FileHelper { case 'heif': return {"type": "image", "subType": "heif"}; + case 'dng': + return {"type": "image", "subType": "dng"}; + default: return {"type": "unsupport", "subType": "unsupport"}; } diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 5b40d36995..0e4b2479e8 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -555,6 +555,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.2" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.0" + package_info_plus_linux: + dependency: transitive + description: + name: package_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + package_info_plus_macos: + dependency: transitive + description: + name: package_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + package_info_plus_web: + dependency: transitive + description: + name: package_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + package_info_plus_windows: + dependency: transitive + description: + name: package_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" path: dependency: transitive description: diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 58b28ffba9..173065add7 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: # mapbox_gl: ^0.15.0 flutter_map: ^0.14.0 flutter_udid: ^2.0.0 + package_info_plus: ^1.4.0 dev_dependencies: flutter_test: diff --git a/server/src/config/multer-option.config.ts b/server/src/config/multer-option.config.ts index 2cdba58337..791de71575 100644 --- a/server/src/config/multer-option.config.ts +++ b/server/src/config/multer-option.config.ts @@ -12,7 +12,7 @@ export const multerConfig = { export const multerOption: MulterOptions = { fileFilter: (req: Request, file: any, cb: any) => { - if (file.mimetype.match(/\/(jpg|jpeg|png|gif|mp4|x-msvideo|quicktime|heic|heif)$/)) { + if (file.mimetype.match(/\/(jpg|jpeg|png|gif|mp4|x-msvideo|quicktime|heic|heif|dng)$/)) { cb(null, true); } else { cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false); diff --git a/server/src/modules/image-optimize/image-optimize.processor.ts b/server/src/modules/image-optimize/image-optimize.processor.ts index 50f826c829..d646c7b5a2 100644 --- a/server/src/modules/image-optimize/image-optimize.processor.ts +++ b/server/src/modules/image-optimize/image-optimize.processor.ts @@ -43,12 +43,19 @@ export class ImageOptimizeProcessor { console.error('Error Reading File'); } - if (savedAsset.mimeType == 'image/heic' || savedAsset.mimeType == 'image/heif') { + // Special Assets Type - ios + if ( + savedAsset.mimeType == 'image/heic' || + savedAsset.mimeType == 'image/heif' || + savedAsset.mimeType == 'image/dng' + ) { let desitnation = ''; if (savedAsset.mimeType == 'image/heic') { desitnation = resizePath.replace('.HEIC', '.jpeg'); - } else { + } else if (savedAsset.mimeType == 'image/heif') { desitnation = resizePath.replace('.HEIF', '.jpeg'); + } else if (savedAsset.mimeType == 'image/dng') { + desitnation = resizePath.replace('.DNG', '.jpeg'); } sharp(data)