main
parent
bfae90faca
commit
73a518733d
30
.metadata
30
.metadata
|
@ -4,7 +4,7 @@
|
||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: "ead455963c12b453cdb2358cad34969c76daf180"
|
revision: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9"
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
|
@ -13,26 +13,26 @@ project_type: app
|
||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: ead455963c12b453cdb2358cad34969c76daf180
|
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
base_revision: ead455963c12b453cdb2358cad34969c76daf180
|
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
- platform: android
|
- platform: android
|
||||||
create_revision: ead455963c12b453cdb2358cad34969c76daf180
|
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
base_revision: ead455963c12b453cdb2358cad34969c76daf180
|
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
- platform: ios
|
- platform: ios
|
||||||
create_revision: ead455963c12b453cdb2358cad34969c76daf180
|
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
base_revision: ead455963c12b453cdb2358cad34969c76daf180
|
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
- platform: linux
|
- platform: linux
|
||||||
create_revision: ead455963c12b453cdb2358cad34969c76daf180
|
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
base_revision: ead455963c12b453cdb2358cad34969c76daf180
|
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
- platform: macos
|
- platform: macos
|
||||||
create_revision: ead455963c12b453cdb2358cad34969c76daf180
|
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
base_revision: ead455963c12b453cdb2358cad34969c76daf180
|
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
- platform: web
|
- platform: web
|
||||||
create_revision: ead455963c12b453cdb2358cad34969c76daf180
|
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
base_revision: ead455963c12b453cdb2358cad34969c76daf180
|
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
- platform: windows
|
- platform: windows
|
||||||
create_revision: ead455963c12b453cdb2358cad34969c76daf180
|
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
base_revision: ead455963c12b453cdb2358cad34969c76daf180
|
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "optictext",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "optictext (profile mode)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "optictext (release mode)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Flutter Web (Chrome)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"program": "lib/main.dart",
|
||||||
|
"args": [
|
||||||
|
"--web-port", "8080"
|
||||||
|
],
|
||||||
|
"flutterMode": "debug",
|
||||||
|
"disableWebSecurity": true,
|
||||||
|
"webRenderer": "auto",
|
||||||
|
"deviceName": "Chrome",
|
||||||
|
"args2": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -5,8 +5,9 @@ import 'package:http_parser/http_parser.dart';
|
||||||
|
|
||||||
class HttpUtils {
|
class HttpUtils {
|
||||||
var client = http.Client();
|
var client = http.Client();
|
||||||
Future<String> performHttpRequest(
|
Future<String> checkLang(Uint8List imageBytes, String imageName) async {
|
||||||
Uint8List imageBytes, String imageName) async {
|
var client = http.Client();
|
||||||
|
|
||||||
var postUri = Uri.parse("http://130.61.88.150/upload");
|
var postUri = Uri.parse("http://130.61.88.150/upload");
|
||||||
http.MultipartRequest request = http.MultipartRequest("POST", postUri);
|
http.MultipartRequest request = http.MultipartRequest("POST", postUri);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
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'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,6 @@ import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
class ImageUploader {
|
class ImageUploader {
|
||||||
//final http.Client client;
|
|
||||||
|
|
||||||
ImageUploader();
|
ImageUploader();
|
||||||
|
|
||||||
Future<Uint8List> buildImageFile(String img) async {
|
Future<Uint8List> buildImageFile(String img) async {
|
||||||
|
@ -30,4 +28,21 @@ class ImageUploader {
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String> performAdvancedOCR(
|
||||||
|
Uint8List imageBytes, String imageName, String lang) async {
|
||||||
|
Directory tempDir = await getTemporaryDirectory();
|
||||||
|
String tempPath = tempDir.path;
|
||||||
|
File tempImageFile = File('$tempPath/$imageName');
|
||||||
|
await tempImageFile.writeAsBytes(imageBytes);
|
||||||
|
|
||||||
|
String text = await FlutterTesseractOcr.extractHocr(tempImageFile.path,
|
||||||
|
language: lang,
|
||||||
|
args: {
|
||||||
|
"psm": "4",
|
||||||
|
"preserve_interword_spaces": "1",
|
||||||
|
});
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
class LanguageUtils {
|
||||||
|
static Map<String, String> tessLanguages = {
|
||||||
|
'Auto': 'auto',
|
||||||
|
'English': 'eng',
|
||||||
|
'German': 'deu',
|
||||||
|
'French': 'fra',
|
||||||
|
'Spanish': 'spa',
|
||||||
|
'Italian': 'ita',
|
||||||
|
'Portuguese': 'por',
|
||||||
|
'Dutch': 'dut',
|
||||||
|
'Polish': 'pol',
|
||||||
|
'Russian': 'rus',
|
||||||
|
'Japanese': 'jpn',
|
||||||
|
'Chinese (Simplified)': 'chi_sim',
|
||||||
|
'Chinese (Traditional)': 'chi_tra',
|
||||||
|
'Korean': 'kor',
|
||||||
|
'Arabic': 'ara',
|
||||||
|
'Hindi': 'hin',
|
||||||
|
'Indonesian': 'ind',
|
||||||
|
'Malay': 'mal',
|
||||||
|
'Thai': 'tha',
|
||||||
|
'Vietnamese': 'vie',
|
||||||
|
'Turkish': 'tur',
|
||||||
|
'Ukrainian': 'ukr',
|
||||||
|
'Hungarian': 'hun',
|
||||||
|
'Czech': 'cze',
|
||||||
|
'Finnish': 'fin',
|
||||||
|
'Danish': 'dan',
|
||||||
|
'Norwegian': 'nor',
|
||||||
|
'Swedish': 'swe',
|
||||||
|
'Greek': 'gre',
|
||||||
|
'Slovak': 'slo',
|
||||||
|
'Croatian': 'hrv',
|
||||||
|
'Lithuanian': 'lit',
|
||||||
|
'Romanian': 'rum',
|
||||||
|
'Bulgarian': 'bul',
|
||||||
|
'Latvian': 'lav',
|
||||||
|
'Estonian': 'est',
|
||||||
|
'Persian': 'per',
|
||||||
|
'Hebrew': 'heb',
|
||||||
|
'Serbian': 'srp',
|
||||||
|
'Albanian': 'alb',
|
||||||
|
'Tagalog': 'tgl',
|
||||||
|
'Azerbaijani': 'aze',
|
||||||
|
'Basque': 'baq',
|
||||||
|
'Belarusian': 'bel',
|
||||||
|
'Bengali': 'ben',
|
||||||
|
'Bosnian': 'bos',
|
||||||
|
'Cebuano': 'ceb',
|
||||||
|
'Esperanto': 'epo',
|
||||||
|
'Galician': 'glg',
|
||||||
|
'Georgian': 'geo',
|
||||||
|
'Gujarati': 'guj',
|
||||||
|
};
|
||||||
|
|
||||||
|
static Map<String, String> translatorLanguages = {
|
||||||
|
'Auto': 'auto',
|
||||||
|
'English': 'en',
|
||||||
|
'German': 'de',
|
||||||
|
'French': 'fr',
|
||||||
|
'Spanish': 'spa',
|
||||||
|
'Italian': 'ita',
|
||||||
|
'Portuguese': 'por',
|
||||||
|
'Dutch': 'dut',
|
||||||
|
'Polish': 'pol',
|
||||||
|
'Russian': 'rus',
|
||||||
|
'Japanese': 'jpn',
|
||||||
|
'Chinese (Simplified)': 'chi_sim',
|
||||||
|
'Chinese (Traditional)': 'chi_tra',
|
||||||
|
'Korean': 'kor',
|
||||||
|
'Arabic': 'ara',
|
||||||
|
'Hindi': 'hin',
|
||||||
|
'Indonesian': 'ind',
|
||||||
|
'Malay': 'mal',
|
||||||
|
'Thai': 'tha',
|
||||||
|
'Vietnamese': 'vie',
|
||||||
|
'Turkish': 'tur',
|
||||||
|
'Ukrainian': 'ukr',
|
||||||
|
'Hungarian': 'hun',
|
||||||
|
'Czech': 'cze',
|
||||||
|
'Finnish': 'fin',
|
||||||
|
'Danish': 'dan',
|
||||||
|
'Norwegian': 'nor',
|
||||||
|
'Swedish': 'swe',
|
||||||
|
'Greek': 'gre',
|
||||||
|
'Slovak': 'slo',
|
||||||
|
'Croatian': 'hrv',
|
||||||
|
'Lithuanian': 'lit',
|
||||||
|
'Romanian': 'rum',
|
||||||
|
'Bulgarian': 'bul',
|
||||||
|
'Latvian': 'lav',
|
||||||
|
'Estonian': 'est',
|
||||||
|
'Persian': 'per',
|
||||||
|
'Hebrew': 'heb',
|
||||||
|
'Serbian': 'srp',
|
||||||
|
'Albanian': 'alb',
|
||||||
|
'Tagalog': 'tgl',
|
||||||
|
'Azerbaijani': 'aze',
|
||||||
|
'Basque': 'baq',
|
||||||
|
'Belarusian': 'bel',
|
||||||
|
'Bengali': 'ben',
|
||||||
|
'Bosnian': 'bos',
|
||||||
|
'Cebuano': 'ceb',
|
||||||
|
'Esperanto': 'epo',
|
||||||
|
'Galician': 'glg',
|
||||||
|
'Georgian': 'geo',
|
||||||
|
'Gujarati': 'guj',
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cpd_app/image_translator.dart';
|
||||||
import 'package:cpd_app/ocr_page.dart';
|
import 'package:cpd_app/ocr_page.dart';
|
||||||
import 'package:cpd_app/bottom_bar.dart';
|
import 'package:cpd_app/bottom_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -66,7 +67,13 @@ class ImageToolsPage extends StatelessWidget {
|
||||||
child: const Text('OCR'),
|
child: const Text('OCR'),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const ImageTranslation()),
|
||||||
|
);
|
||||||
|
},
|
||||||
child: const Text('Image Translation'),
|
child: const Text('Image Translation'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
import 'dart:io';
|
||||||
import 'package:cpd_app/http_utils.dart';
|
import 'package:cpd_app/http_utils.dart';
|
||||||
import 'package:cpd_app/image_uploader.dart';
|
import 'package:cpd_app/image_uploader.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'language_utils.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
|
||||||
class OCRPage extends StatefulWidget {
|
class OCRPage extends StatefulWidget {
|
||||||
const OCRPage({super.key});
|
const OCRPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<OCRPage> createState() => _OCRPageState();
|
State<OCRPage> createState() => _OCRPageState();
|
||||||
|
@ -14,25 +17,31 @@ class _OCRPageState extends State<OCRPage> {
|
||||||
String _extractedText = '';
|
String _extractedText = '';
|
||||||
final ImageUploader _imageUploader = ImageUploader();
|
final ImageUploader _imageUploader = ImageUploader();
|
||||||
final HttpUtils _httpUtils = HttpUtils();
|
final HttpUtils _httpUtils = HttpUtils();
|
||||||
@override
|
String _selectedLanguage = 'Auto';
|
||||||
void initState() {
|
XFile? _selectedImage;
|
||||||
super.initState();
|
|
||||||
uploadImage("lorem.png");
|
Future<void> uploadImage(
|
||||||
|
Uint8List imageBytes, String selectedLanguage) async {
|
||||||
|
setState(() {
|
||||||
|
_extractedText = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
//preprocessing, maybe
|
||||||
|
String text = '';
|
||||||
|
if (selectedLanguage == 'Auto') {
|
||||||
|
String lang = await _httpUtils.checkLang(imageBytes, 'image.jpg');
|
||||||
|
text = await _imageUploader.performOcr(imageBytes, 'image.jpg', lang);
|
||||||
|
} else {
|
||||||
|
String langCode = LanguageUtils.tessLanguages[selectedLanguage]!;
|
||||||
|
text = await _imageUploader.performOcr(imageBytes, 'image.jpg', langCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> uploadImage(String img) async {
|
|
||||||
//hier wird der user sein bild auswählen können
|
|
||||||
//aktuell hardcoded bild zum testen
|
|
||||||
String imageName = img;
|
|
||||||
Uint8List imageBytes = await _imageUploader.buildImageFile(imageName);
|
|
||||||
String lang = await _httpUtils.performHttpRequest(imageBytes, imageName);
|
|
||||||
String text = await _imageUploader.performOcr(imageBytes, imageName, lang);
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_extractedText = text;
|
_extractedText = text;
|
||||||
|
_selectedImage = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> languages = LanguageUtils.tessLanguages.keys.toList();
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
@ -43,11 +52,69 @@ class _OCRPageState extends State<OCRPage> {
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ElevatedButton(
|
DropdownButton<String>(
|
||||||
onPressed: () => uploadImage("lorem.png"),
|
value: _selectedLanguage,
|
||||||
child: const Text('Test Upload Image'),
|
onChanged: (newValue) {
|
||||||
|
setState(() {
|
||||||
|
_selectedLanguage = newValue!;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
items: languages.map<DropdownMenuItem<String>>((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
),
|
),
|
||||||
Text(_extractedText),
|
_selectedImage != null
|
||||||
|
? SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.8,
|
||||||
|
height: MediaQuery.of(context).size.height * 0.4,
|
||||||
|
child: Image.file(File(_selectedImage!.path)),
|
||||||
|
)
|
||||||
|
: Container(),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final ImagePicker picker = ImagePicker();
|
||||||
|
final XFile? image =
|
||||||
|
await picker.pickImage(source: ImageSource.gallery);
|
||||||
|
if (image != null) {
|
||||||
|
setState(() {
|
||||||
|
_selectedImage = image;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text('Select Image'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: _selectedImage != null
|
||||||
|
? () async {
|
||||||
|
if (_selectedImage != null) {
|
||||||
|
File imageFile = File(_selectedImage!.path);
|
||||||
|
List<int> imageBytes = imageFile.readAsBytesSync();
|
||||||
|
await uploadImage(
|
||||||
|
Uint8List.fromList(imageBytes), _selectedLanguage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: const Text('Extract Text'),
|
||||||
|
),
|
||||||
|
_extractedText.isNotEmpty
|
||||||
|
? Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: TextFormField(
|
||||||
|
readOnly: true,
|
||||||
|
initialValue: _extractedText,
|
||||||
|
maxLines: null,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Extracted Text',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Container(),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Clipboard.setData(ClipboardData(text: _extractedText));
|
Clipboard.setData(ClipboardData(text: _extractedText));
|
||||||
|
|
26
pubspec.lock
26
pubspec.lock
|
@ -93,10 +93,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.2"
|
version: "1.18.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -388,10 +388,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -521,18 +521,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -553,10 +553,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.6.1"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -585,10 +585,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.4-beta"
|
version: "0.3.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -614,5 +614,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.3 <4.0.0"
|
dart: ">=3.2.0-194.0.dev <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.7.0"
|
||||||
|
|
|
@ -17,6 +17,7 @@ dependencies:
|
||||||
http: ^1.1.0
|
http: ^1.1.0
|
||||||
flutter_tesseract_ocr:
|
flutter_tesseract_ocr:
|
||||||
http_parser: ^4.0.2
|
http_parser: ^4.0.2
|
||||||
|
#opencv_4: ^1.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in New Issue