219 lines
7.7 KiB
Dart
219 lines
7.7 KiB
Dart
|
import 'dart:io';
|
||
|
import 'package:cpd_app/http_utils.dart';
|
||
|
import 'package:http/http.dart' as http;
|
||
|
import 'package:cpd_app/image_uploader.dart';
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter/services.dart';
|
||
|
import 'language_utils.dart';
|
||
|
import 'package:image_picker/image_picker.dart';
|
||
|
|
||
|
class ImageTranslation extends StatefulWidget {
|
||
|
const ImageTranslation({Key? key}) : super(key: key);
|
||
|
|
||
|
@override
|
||
|
State<ImageTranslation> createState() => _ImageTranslationState();
|
||
|
}
|
||
|
|
||
|
class _ImageTranslationState extends State<ImageTranslation> {
|
||
|
XFile? _selectedImage;
|
||
|
String _sourceLanguage = 'Auto';
|
||
|
String _targetLanguage = 'English';
|
||
|
String _translatedText = '';
|
||
|
final ImageUploader _imageUploader = ImageUploader();
|
||
|
final HttpUtils _httpUtils = HttpUtils();
|
||
|
/*1. Text extracten
|
||
|
2. Text übersetzen
|
||
|
3. Text aus dem alten bild mit farbe überdecken (koordinaten etwas weiter links oben + rechts unten als die erkannten koordinaten)
|
||
|
4. Übersetzen Text in neues bild einfügen
|
||
|
*/
|
||
|
Future<void> uploadImage(
|
||
|
Uint8List imageBytes,
|
||
|
String sourceLang,
|
||
|
String targetLang,
|
||
|
) async {
|
||
|
setState(() {
|
||
|
_translatedText = '';
|
||
|
});
|
||
|
|
||
|
//preprocessing
|
||
|
String text = '';
|
||
|
if (LanguageUtils.tessLanguages[sourceLang] == 'auto') {
|
||
|
String lang = await _httpUtils.checkLang(imageBytes, 'image.jpg');
|
||
|
text = await _imageUploader.performOcr(imageBytes, 'image.jpg', lang);
|
||
|
sourceLang = LanguageUtils.tessLanguages[sourceLang]!;
|
||
|
} else {
|
||
|
String langCode = LanguageUtils.tessLanguages[sourceLang]!;
|
||
|
text = await _imageUploader.performOcr(imageBytes, 'image.jpg', langCode);
|
||
|
}
|
||
|
if (text != '') {
|
||
|
Map<String, String> requestBody = {
|
||
|
'source_language': sourceLang,
|
||
|
'target_language': LanguageUtils.translatorLanguages[targetLang]!,
|
||
|
'text': text,
|
||
|
};
|
||
|
|
||
|
Map<String, String> headers = {
|
||
|
'content-type': 'application/x-www-form-urlencoded',
|
||
|
'X-RapidAPI-Key': 'd0fa3c2f3cmsh1805e7a2fed7cc2p1683ebjsna722e2bffafe',
|
||
|
'X-RapidAPI-Host': 'text-translator2.p.rapidapi.com',
|
||
|
};
|
||
|
|
||
|
final response = await http.post(
|
||
|
Uri.parse('https://text-translator2.p.rapidapi.com/translate'),
|
||
|
headers: headers,
|
||
|
body: requestBody,
|
||
|
);
|
||
|
|
||
|
if (response.statusCode == 200) {
|
||
|
_translatedText = response.body;
|
||
|
setState(() {
|
||
|
_translatedText = text;
|
||
|
_selectedImage = null;
|
||
|
});
|
||
|
} else {
|
||
|
print('Error: ${response.statusCode}');
|
||
|
}
|
||
|
print(_translatedText);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
List<String> sourceLanguages = LanguageUtils.tessLanguages.keys.toList();
|
||
|
List<String> targetLanguages =
|
||
|
LanguageUtils.translatorLanguages.keys.toList();
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return Scaffold(
|
||
|
appBar: AppBar(
|
||
|
title: const Text('Image Translation'),
|
||
|
),
|
||
|
body: Center(
|
||
|
child: Column(
|
||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
children: <Widget>[
|
||
|
const SizedBox(height: 20),
|
||
|
Row(
|
||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||
|
children: <Widget>[
|
||
|
// From - Subtle blue background
|
||
|
Container(
|
||
|
decoration: BoxDecoration(
|
||
|
color: Colors.blue.shade100,
|
||
|
borderRadius: BorderRadius.circular(8.0),
|
||
|
),
|
||
|
padding: const EdgeInsets.all(8.0),
|
||
|
child: Column(
|
||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
children: <Widget>[
|
||
|
const Text('From', style: TextStyle(color: Colors.blue)),
|
||
|
DropdownButton<String>(
|
||
|
value: _sourceLanguage,
|
||
|
onChanged: (newValue) {
|
||
|
setState(() {
|
||
|
_sourceLanguage = newValue!;
|
||
|
});
|
||
|
},
|
||
|
items: sourceLanguages
|
||
|
.map<DropdownMenuItem<String>>((String value) {
|
||
|
return DropdownMenuItem<String>(
|
||
|
value: value,
|
||
|
child: Text(value),
|
||
|
);
|
||
|
}).toList(),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
// Target - Subtle red background
|
||
|
Container(
|
||
|
decoration: BoxDecoration(
|
||
|
color: Colors.red.shade100,
|
||
|
borderRadius: BorderRadius.circular(8.0),
|
||
|
),
|
||
|
padding: const EdgeInsets.all(8.0),
|
||
|
child: Column(
|
||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
children: <Widget>[
|
||
|
const Text('Target', style: TextStyle(color: Colors.red)),
|
||
|
DropdownButton<String>(
|
||
|
value: _targetLanguage,
|
||
|
onChanged: (newValue) {
|
||
|
setState(() {
|
||
|
_targetLanguage = newValue!;
|
||
|
});
|
||
|
},
|
||
|
items: targetLanguages
|
||
|
.map<DropdownMenuItem<String>>((String value) {
|
||
|
return DropdownMenuItem<String>(
|
||
|
value: value,
|
||
|
child: Text(value),
|
||
|
);
|
||
|
}).toList(),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
const SizedBox(height: 20),
|
||
|
TextButton(
|
||
|
onPressed: () async {
|
||
|
final ImagePicker picker = ImagePicker();
|
||
|
final XFile? image =
|
||
|
await picker.pickImage(source: ImageSource.gallery);
|
||
|
if (image != null) {
|
||
|
setState(() {
|
||
|
_selectedImage = image;
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
style: ButtonStyle(
|
||
|
backgroundColor: MaterialStateProperty.all<Color>(Colors.blue),
|
||
|
),
|
||
|
child: const Text(
|
||
|
'Upload Image',
|
||
|
style: TextStyle(color: Colors.white),
|
||
|
),
|
||
|
),
|
||
|
ElevatedButton(
|
||
|
onPressed: _selectedImage != null
|
||
|
? () async {
|
||
|
if (_selectedImage != null) {
|
||
|
File imageFile = File(_selectedImage!.path);
|
||
|
List<int> imageBytes = imageFile.readAsBytesSync();
|
||
|
await uploadImage(Uint8List.fromList(imageBytes),
|
||
|
_sourceLanguage, _targetLanguage);
|
||
|
}
|
||
|
}
|
||
|
: null,
|
||
|
child: const Text('Extract Text'),
|
||
|
),
|
||
|
_translatedText.isNotEmpty
|
||
|
? Expanded(
|
||
|
child: Padding(
|
||
|
padding: const EdgeInsets.all(8.0),
|
||
|
child: TextFormField(
|
||
|
readOnly: true,
|
||
|
initialValue: _translatedText,
|
||
|
maxLines: null,
|
||
|
decoration: const InputDecoration(
|
||
|
labelText: 'Extracted Text',
|
||
|
border: OutlineInputBorder(),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
)
|
||
|
: Container(),
|
||
|
TextButton(
|
||
|
onPressed: () {
|
||
|
Clipboard.setData(ClipboardData(text: _translatedText));
|
||
|
},
|
||
|
child: const Text('Copy to Clipboard'),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|