Skip to content

Commit 76fbcd1

Browse files
committed
Fix Bug where on Linux resizing Images in Low, and Medium Quality caused messed up textures, Added update Check
1 parent d38a89c commit 76fbcd1

7 files changed

Lines changed: 203 additions & 5 deletions

File tree

lib/main.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ String decimationArgs = "-t 1";
1818
String meshingExtraFlags =
1919
"--target-face-num 0 --crop-to-roi 1 --roi-border 10";
2020
String meshing_type = "poissonrecon";
21+
String currentVersionTag = "V1.1.5";
2122

2223
void main() async {
2324
WidgetsFlutterBinding.ensureInitialized();

lib/scanningScreen/scanningScreenModel.dart

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:isolate_current_directory/isolate_current_directory.dart';
88
import 'package:shared_preferences/shared_preferences.dart';
99
import 'package:simple_photogrammetry_gui/main.dart';
1010
import 'package:simple_photogrammetry_gui/runCommand.dart';
11+
import 'package:simple_photogrammetry_gui/utils/downscaleImages.dart';
1112
import 'package:simple_photogrammetry_gui/utils/getMemoryUsage.dart';
1213
// import 'package:system_info2/system_info2.dart';
1314
import 'package:path/path.dart' as p;
@@ -104,6 +105,28 @@ class ScanningScreenModel {
104105
return;
105106
}
106107

108+
List maximagesizes = [-1, 3000, 2000];
109+
110+
if(maximagesizes[qualityLevel] != -1) {
111+
112+
view.status = "0/$totalStepNumber Copy & Resize Images";
113+
view.setState(() {});
114+
115+
final resizedImagePath = "$outputPath${slash}temp${slash}images_scaled";
116+
117+
await Directory(
118+
resizedImagePath,
119+
).create(recursive: true);
120+
121+
// Wait for the background downscaling to finish
122+
await downscaleImages(imagesPath, resizedImagePath, maximagesizes[qualityLevel]);
123+
124+
125+
imagesPath = resizedImagePath;
126+
127+
}
128+
129+
107130
final model_colmap_file = File("$outputPath${slash}temp${slash}model_colmap.mvs");
108131

109132
if (!(await model_colmap_file.exists())) {
@@ -223,7 +246,7 @@ class ScanningScreenModel {
223246
view.status = "4/$totalStepNumber Undistorting Images";
224247
view.setState(() {});
225248

226-
List maximagesizes = [-1, 3000, 2000];
249+
227250

228251
await runCommand(colmapPath, [
229252
"image_undistorter",
@@ -236,7 +259,7 @@ class ScanningScreenModel {
236259

237260
"--output_type", "COLMAP",
238261

239-
"--max_image_size", maximagesizes[qualityLevel].toString()
262+
// "--max_image_size", maximagesizes[qualityLevel].toString()
240263

241264
]);
242265

lib/scanningScreen/scanningScreenView.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:roundcheckbox/roundcheckbox.dart';
1313
import 'package:simple_photogrammetry_gui/TitleBar/TitleBar.dart';
1414
import 'package:simple_photogrammetry_gui/main.dart';
1515
import 'package:simple_photogrammetry_gui/runCommand.dart';
16+
import 'package:simple_photogrammetry_gui/utils/checkForUpdate.dart';
1617
import 'package:simple_photogrammetry_gui/utils/getMemoryUsage.dart';
1718
import 'package:url_launcher/url_launcher.dart';
1819
import 'package:hexcolor/hexcolor.dart';
@@ -58,6 +59,47 @@ class _ScanningScreenViewState extends State<ScanningScreenView> {
5859
// });
5960
// });
6061

62+
checkForUpdates(currentVersionTag).then((newVersion) {
63+
if (newVersion != null) {
64+
65+
var alert = AlertDialog(
66+
backgroundColor: HexColor("#282828"),
67+
title: Text(
68+
"A New Version is Available",
69+
style: TextStyle(color: HexColor("#ebdbb2")),
70+
),
71+
content: Column(
72+
mainAxisSize: MainAxisSize.min,
73+
children: [
74+
linkWidget("Download Here: https://github.com/edin45/simple_photogrammetry_gui/releases/latest", "https://github.com/edin45/simple_photogrammetry_gui/releases/latest"),
75+
// linkWidget("2. OpenMVS", "https://github.com/cdcseacave/openMVS"),
76+
// linkWidget("3. mvs-texturing", "https://github.com/nmoehrle/mvs-texturing"),
77+
// linkWidget("4. pymeshlab", "https://github.com/cnr-isti-vclab/PyMeshLab"),
78+
// linkWidget("5. brush", "https://github.com/ArthurBrussee/brush"),
79+
// linkWidget("6. PoissonRecon", "https://github.com/mkazhdan/PoissonRecon"),
80+
Padding(padding: EdgeInsets.all(8)),
81+
TextButton(
82+
onPressed: () async {
83+
84+
Navigator.pop(context);
85+
86+
// photogrammetry_or_splat = true;
87+
88+
// setState(() {});
89+
90+
},
91+
child: Text(
92+
"Later",
93+
style: TextStyle(color: HexColor("#ebdbb2"), fontSize: 18),
94+
))
95+
],
96+
),
97+
);
98+
showDialog(context: context, builder: (_) => alert);
99+
100+
}
101+
});
102+
61103
asyncTasks() async {
62104
hasAllDependencies = await widget.model.checkDependencies(this);
63105
setState(() {});

lib/utils/checkForUpdate.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import 'dart:convert';
2+
import 'package:http/http.dart' as http;
3+
4+
5+
Future<String?> checkForUpdates(String currentTag) async {
6+
7+
final url = Uri.parse('https://api.github.com/repos/edin45/simple_photogrammetry_gui/releases/latest');
8+
9+
try {
10+
final response = await http.get(url, headers: {
11+
'User-Agent': 'simple_photogrammetry_gui',
12+
});
13+
14+
if (response.statusCode == 200) {
15+
final data = jsonDecode(response.body);
16+
final fetchedTag = data['tag_name'] as String?;
17+
18+
19+
if (fetchedTag != null && fetchedTag != currentTag) {
20+
return fetchedTag;
21+
}
22+
} else {
23+
print('GitHub API returned status code: ${response.statusCode}');
24+
}
25+
} catch (e) {
26+
27+
print('Failed to check for updates: $e');
28+
}
29+
30+
return null;
31+
}

lib/utils/downscaleImages.dart

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import 'dart:io';
2+
import 'dart:isolate';
3+
import 'package:image/image.dart' as img;
4+
import 'package:path/path.dart' as p;
5+
6+
/// Scales images in [sourceDir] to [maxSize] using a fixed pool of [maxConcurrency] threads.
7+
Future<void> downscaleImages(
8+
String sourceDir,
9+
String destDir,
10+
int maxSize, {
11+
int maxConcurrency = 4,
12+
}) async {
13+
final dir = Directory(sourceDir);
14+
final dest = Directory(destDir);
15+
if (!dest.existsSync()) {
16+
dest.createSync(recursive: true);
17+
}
18+
19+
final files = dir.listSync().whereType<File>().where((f) {
20+
final ext = p.extension(f.path).toLowerCase();
21+
return ext == '.jpg' || ext == '.jpeg' || ext == '.png';
22+
}).toList();
23+
24+
if (files.isEmpty) return;
25+
26+
// Work-stealing queue to keep exactly [maxConcurrency] isolates busy
27+
int fileIndex = 0;
28+
final workers = List.generate(maxConcurrency, (_) async {
29+
while (fileIndex < files.length) {
30+
final currentFile = files[fileIndex++];
31+
await Isolate.run(
32+
() => _resizeWorker(currentFile.path, destDir, maxSize),
33+
);
34+
}
35+
});
36+
37+
await Future.wait(workers);
38+
}
39+
40+
/// Standalone top-level worker executed inside an Isolate
41+
void _resizeWorker(String filePath, String destDir, int maxSize) {
42+
final bytes = File(filePath).readAsBytesSync();
43+
final image = img.decodeImage(bytes);
44+
45+
if (image == null) return;
46+
47+
final fileName = p.basename(filePath);
48+
final outPath = p.join(destDir, fileName);
49+
50+
// Skip downscaling if already within target dimensions
51+
if (image.width <= maxSize && image.height <= maxSize) {
52+
File(filePath).copySync(outPath);
53+
return;
54+
}
55+
56+
int targetWidth = image.width;
57+
int targetHeight = image.height;
58+
59+
if (image.width > image.height) {
60+
targetWidth = maxSize;
61+
targetHeight = (image.height * (maxSize / image.width)).round();
62+
} else {
63+
targetHeight = maxSize;
64+
targetWidth = (image.width * (maxSize / image.height)).round();
65+
}
66+
67+
// Fast bilinear resizing suitable for photogrammetry inputs
68+
final resized = img.copyResize(
69+
image,
70+
width: targetWidth,
71+
height: targetHeight,
72+
interpolation: img.Interpolation.linear,
73+
);
74+
75+
File(outPath).writeAsBytesSync(img.encodeJpg(resized, quality: 95));
76+
}

pubspec.lock

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# Generated by pub
22
# See https://dart.dev/tools/pub/glossary#lockfile
33
packages:
4+
archive:
5+
dependency: transitive
6+
description:
7+
name: archive
8+
sha256: be169cf6ac481e052c4538715d88841d567150dfe1df38aaec76461a4e7b39f2
9+
url: "https://pub.dev"
10+
source: hosted
11+
version: "4.1.0"
412
args:
513
dependency: transitive
614
description:
@@ -236,10 +244,10 @@ packages:
236244
dependency: "direct main"
237245
description:
238246
name: http
239-
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
247+
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
240248
url: "https://pub.dev"
241249
source: hosted
242-
version: "0.13.6"
250+
version: "1.6.0"
243251
http_parser:
244252
dependency: transitive
245253
description:
@@ -248,6 +256,14 @@ packages:
248256
url: "https://pub.dev"
249257
source: hosted
250258
version: "4.1.2"
259+
image:
260+
dependency: "direct main"
261+
description:
262+
name: image
263+
sha256: "1976370a4df3091bb0f72409c187ad1f9132a818bc6b95ca59c0bae1c75c688e"
264+
url: "https://pub.dev"
265+
source: hosted
266+
version: "4.9.2"
251267
isolate_current_directory:
252268
dependency: "direct main"
253269
description:
@@ -440,6 +456,14 @@ packages:
440456
url: "https://pub.dev"
441457
source: hosted
442458
version: "2.1.8"
459+
posix:
460+
dependency: transitive
461+
description:
462+
name: posix
463+
sha256: bc1bad54ad2b735816e31f8d4600cfde6c7839975085ddfbca48b6c9f7c4044e
464+
url: "https://pub.dev"
465+
source: hosted
466+
version: "6.5.2"
443467
provider:
444468
dependency: "direct main"
445469
description:

pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ dependencies:
3838
cupertino_icons: ^1.0.2
3939
system_theme: ^2.1.0
4040
path_provider: ^2.1.2
41-
http: ^0.13.5
41+
http: ^1.6.0
4242
provider: ^6.0.5
4343
roundcheckbox: ^2.0.5
4444
# system_info2: ^4.1.0
@@ -49,6 +49,7 @@ dependencies:
4949
hexcolor: ^3.1.3
5050
file_selector: ^1.1.0
5151
shared_preferences: ^2.5.5
52+
image: ^4.9.2
5253
# win32: ^5.15.0
5354
# ffi: ^2.2.0
5455

0 commit comments

Comments
 (0)