-
-
Save roipeker/9315aa25301f5c0362caaebd15876c2f to your computer and use it in GitHub Desktop.
////////////////////////////// | |
// | |
// 2019, roipeker.com | |
// screencast - demo simple image: | |
// https://youtu.be/EJyRH4_pY8I | |
// | |
// screencast - demo snapshot: | |
// https://youtu.be/-LxPcL7T61E | |
// | |
////////////////////////////// | |
import 'dart:async'; | |
import 'dart:typed_data'; | |
import 'dart:ui' as ui; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart'; | |
import 'package:image/image.dart' as img; | |
import 'package:flutter/services.dart' show rootBundle; | |
class ColorPickerWidget extends StatefulWidget { | |
@override | |
_ColorPickerWidgetState createState() => _ColorPickerWidgetState(); | |
} | |
class _ColorPickerWidgetState extends State<ColorPickerWidget> { | |
String imagePath = 'assets/images/santorini.jpg'; | |
GlobalKey imageKey = GlobalKey(); | |
GlobalKey paintKey = GlobalKey(); | |
// CHANGE THIS FLAG TO TEST BASIC IMAGE, AND SNAPSHOT. | |
bool useSnapshot = true; | |
// based on useSnapshot=true ? paintKey : imageKey ; | |
// this key is used in this example to keep the code shorter. | |
GlobalKey currentKey; | |
final StreamController<Color> _stateController = StreamController<Color>(); | |
img.Image photo; | |
@override | |
void initState() { | |
currentKey = useSnapshot ? paintKey : imageKey; | |
super.initState(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final String title = useSnapshot ? "snapshot" : "basic"; | |
return Scaffold( | |
appBar: AppBar(title: Text("Color picker $title")), | |
body: StreamBuilder( | |
initialData: Colors.green[500], | |
stream: _stateController.stream, | |
builder: (buildContext, snapshot) { | |
Color selectedColor = snapshot.data ?? Colors.green; | |
return Stack( | |
children: <Widget>[ | |
RepaintBoundary( | |
key: paintKey, | |
child: GestureDetector( | |
onPanDown: (details) { | |
searchPixel(details.globalPosition); | |
}, | |
onPanUpdate: (details) { | |
searchPixel(details.globalPosition); | |
}, | |
child: Center( | |
child: Image.asset( | |
imagePath, | |
key: imageKey, | |
//color: Colors.red, | |
//colorBlendMode: BlendMode.hue, | |
//alignment: Alignment.bottomRight, | |
fit: BoxFit.none, | |
//scale: .8, | |
), | |
), | |
), | |
), | |
Container( | |
margin: EdgeInsets.all(70), | |
width: 50, | |
height: 50, | |
decoration: BoxDecoration( | |
shape: BoxShape.circle, | |
color: selectedColor, | |
border: Border.all(width: 2.0, color: Colors.white), | |
boxShadow: [ | |
BoxShadow( | |
color: Colors.black12, | |
blurRadius: 4, | |
offset: Offset(0, 2)) | |
]), | |
), | |
Positioned( | |
child: Text('${selectedColor}', | |
style: TextStyle( | |
color: Colors.white, | |
backgroundColor: Colors.black54)), | |
left: 114, | |
top: 95, | |
), | |
], | |
); | |
}), | |
); | |
} | |
void searchPixel(Offset globalPosition) async { | |
if (photo == null) { | |
await (useSnapshot ? loadSnapshotBytes() : loadImageBundleBytes()); | |
} | |
_calculatePixel(globalPosition); | |
} | |
void _calculatePixel(Offset globalPosition) { | |
RenderBox box = currentKey.currentContext.findRenderObject(); | |
Offset localPosition = box.globalToLocal(globalPosition); | |
double px = localPosition.dx; | |
double py = localPosition.dy; | |
if (!useSnapshot) { | |
double widgetScale = box.size.width / photo.width; | |
print(py); | |
px = (px / widgetScale); | |
py = (py / widgetScale); | |
} | |
int pixel32 = photo.getPixelSafe(px.toInt(), py.toInt()); | |
int hex = abgrToArgb(pixel32); | |
_stateController.add(Color(hex)); | |
} | |
Future<void> loadImageBundleBytes() async { | |
ByteData imageBytes = await rootBundle.load(imagePath); | |
setImageBytes(imageBytes); | |
} | |
Future<void> loadSnapshotBytes() async { | |
RenderRepaintBoundary boxPaint = paintKey.currentContext.findRenderObject(); | |
ui.Image capture = await boxPaint.toImage(); | |
ByteData imageBytes = | |
await capture.toByteData(format: ui.ImageByteFormat.png); | |
setImageBytes(imageBytes); | |
capture.dispose(); | |
} | |
void setImageBytes(ByteData imageBytes) { | |
List<int> values = imageBytes.buffer.asUint8List(); | |
photo = null; | |
photo = img.decodeImage(values); | |
} | |
} | |
// image lib uses uses KML color format, convert #AABBGGRR to regular #AARRGGBB | |
int abgrToArgb(int argbColor) { | |
int r = (argbColor >> 16) & 0xFF; | |
int b = argbColor & 0xFF; | |
return (argbColor & 0xFF00FF00) | (b << 16) | r; | |
} |
`///////////////////////////////////// 2019, roipeker.com // screencast - demo hình ảnh Đơn giản: // https://youtu.be/EJyRH4_pY8I // // ghi màn hình - ảnh chụp demo: // https://youtu.be/-LxPcL7T61E // ///////// / //////////////////
nhập 'phi tiêu: không đồng bộ'; nhập 'phi tiêu:typed_data'; nhập 'phi tiêu: ui' dưới dạng ui; nhập 'phi tiêu: toán học';
nhập 'gói: rung/liệu.dart'; nhập 'gói: rung/rendering.dart'; nhập 'gói: image/image.dart' dưới img; nhập 'gói: rung/services.dart' hiển thị rootBundle;
void main() => runApp(const MaterialApp(home: MyApp()));
Lớp MyApp mở rộng StatefulWidget { const MyApp({Key? key}): super(key: key);
@OverRide Trạng thái createState() => _MyAppState(); }
Lớp _MyAppState mở rộng Trạng thái { string imagePath = 'nội dung/12.jpg'; GlobalKey imageKey = GlobalKey(); GlobalKey paintKey = GlobalKey();
// THAY ĐỔI CỜ NÀY ĐỂ KIỂM TRA ẢNH CƠ BẢN VÀ ẢNH CHỤP. bool useSnapshot = true;
// dựa trên useSnapshot=true ? paintKey : imageKey ; // phím này đã được sử dụng trong ví dụ này để giữ mã ngắn hơn. GlobalKey currentKey lần lượt;
StreamController cuối cùng _stateController = StreamController(); //muộn img.Ảnh ; img.Hình ảnh? tấm hình;
@OverRide void initState() { currentKey = useSnapshot ? paintKey : imageKey; super.initState(); }
@OverRide Bản dựng tiện ích con (Bối cảnh BuildContext) { tiêu đề Chuỗi cuối cùng = useSnapshot? "ảnh chụp nhanh" : "cơ bản"; return SafeArea( con: Scaffold( appBar: AppBar(title: Text("Bộ chọn màu $title")), body: StreamBuilder( initData : Colors.green[500], stream: _stateController.stream, builder: (buildContext, snapshot ) { Color selectColor = snapshot.data as Color ?? Colors.green; return Stack( children: [ RepaintBoundary( key: paintKey, child: GestureDetector( onPanDown: (details) { searchPixel(details.globalPosition); }, onPanUpdate: ( chi tiết) ) { searchPixel(details.globalPosition); }, con: Center( con: Image.asset( imagePath, key: imageKey, //color: Colors.red, //colorBlendMode: BlendMode.hue, //alignment: Alignment.bottomRight, fit: BoxFit.contain, // scale: .8, ), ), ), ), Khu vực chứa( lề: const EdgeInsets.all(70), chiều rộng: 50, chiều cao: 50, trang trí: BoxDecoration( format: BoxShape.circle, color : đã chọnColor!, đường viền: Đường viền.tất cả(chiều rộng: 2.0, màu:Colors.white), boxShadow: [ const BoxShadow( color: Colors.black12, blurRadius: 4, offset: Offset(0, 2)) ]), ), Đã định vị( con: Văn bản('${selectedColor}', type: const TextStyle( color: Colors.white , backgroundColor: Colors.black54)), left: 114, top: 95, ), ], ); }), ), ); }
void searchPixel(Offset globalPosition) async { if (photo == null) { đang chờ (useSnapshot ? loadSnapshotBytes() : loadImageBundleBytes()); } _calculatePixel(globalPosition); }
void _calculatePixel(Offset globalPosition) { RenderBox box = currentKey.currentContext!.findRenderObject() làm RenderBox; Bù đắp localPosition = box.globalToLocal(globalPosition);
double px = localPosition.dx; double py = localPosition.dy; if (!useSnapshot) { double widgetScale = box.size.width / photo!.width; print(py); px = (px / widgetScale); py = (py / widgetScale); } int pixel32 = photo!.getPixelSafe(px.toInt(), py.toInt()); int hex = abgrToArgb(pixel32); _stateController.add(Color(hex));
}
Tương lai loadImageBundleBytes() async { ByteData imageBytes = đang chờ rootBundle.load(imagePath); setImageBytes(imageBytes); }
Tương lai loadSnapshotBytes() async { RenderRepaintBoundary boxPaint = paintKey.currentContext!.findRenderObject() doing RenderRepaintBoundary; //RenderObject? boxPaint = paintKey.currentContext.findRenderObject(); ui.Chụp ảnh = đang chờ hộpPaint.toImage();
ByteData? imageBytes = await capture.toByteData(format: ui.ImageByteFormat.png); setImageBytes(imageBytes!); capture.dispose();
}
void setImageBytes(ByteData imageBytes) { Danh sách giá trị = imageBytes.buffer.asUint8List(); tấm hình; ảnh = img.decodeImage(giá trị)!; } }
// lib lib image sieu used used format KML color, convert #AABBGGRR to #AARRGGBB normal int abgrToArgb(int argbColor) { int r = (argbColor >> 16) & 0xFF; int b = argbColor & 0xFF; trả về (argbColor & 0xFF00FF00) | (b<<16) | r; } `
can you send me the image.dart file code? thanks
import 'package:image/image.dart' as img;
@roipeker I tried using the code and placed an image inside an InteractiveViewer widget. However, when I zoom in, the color I obtain by tapping on the image is not accurate.
What can I do ?
`//////////////////////////////
//
// 2019, roipeker.com
// screencast - demo simple image:
// https://youtu.be/EJyRH4_pY8I
//
// screencast - demo snapshot:
// https://youtu.be/-LxPcL7T61E
//
//////////////////////////////
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:image/image.dart' as img;
import 'package:flutter/services.dart' show rootBundle;
void main() => runApp(const MaterialApp(home: MyApp()));
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@OverRide
State createState() => _MyAppState();
}
class _MyAppState extends State {
String imagePath = 'assets/12.jpg';
GlobalKey imageKey = GlobalKey();
GlobalKey paintKey = GlobalKey();
// CHANGE THIS FLAG TO TEST BASIC IMAGE, AND SNAPSHOT.
bool useSnapshot = true;
// based on useSnapshot=true ? paintKey : imageKey ;
// this key is used in this example to keep the code shorter.
late GlobalKey currentKey;
final StreamController _stateController = StreamController();
//late img.Image photo ;
img.Image? photo;
@OverRide
void initState() {
currentKey = useSnapshot ? paintKey : imageKey;
super.initState();
}
@OverRide
Widget build(BuildContext context) {
final String title = useSnapshot ? "snapshot" : "basic";
return SafeArea(
child: Scaffold(
appBar: AppBar(title: Text("Color picker $title")),
body: StreamBuilder(
initialData: Colors.green[500],
stream: _stateController.stream,
builder: (buildContext, snapshot) {
Color selectedColor = snapshot.data as Color ?? Colors.green;
return Stack(
children: [
RepaintBoundary(
key: paintKey,
child: GestureDetector(
onPanDown: (details) {
searchPixel(details.globalPosition);
},
onPanUpdate: (details) {
searchPixel(details.globalPosition);
},
child: Center(
child: Image.asset(
imagePath,
key: imageKey,
//color: Colors.red,
//colorBlendMode: BlendMode.hue,
//alignment: Alignment.bottomRight,
fit: BoxFit.contain,
//scale: .8,
),
),
),
),
Container(
margin: const EdgeInsets.all(70),
width: 50,
height: 50,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: selectedColor!,
border: Border.all(width: 2.0, color: Colors.white),
boxShadow: [
const BoxShadow(
color: Colors.black12,
blurRadius: 4,
offset: Offset(0, 2))
]),
),
Positioned(
child: Text('${selectedColor}',
style: const TextStyle(
color: Colors.white,
backgroundColor: Colors.black54)),
left: 114,
top: 95,
),
],
);
}),
),
);
}
void searchPixel(Offset globalPosition) async {
if (photo == null) {
await (useSnapshot ? loadSnapshotBytes() : loadImageBundleBytes());
}
_calculatePixel(globalPosition);
}
void _calculatePixel(Offset globalPosition) {
RenderBox box = currentKey.currentContext!.findRenderObject() as RenderBox;
Offset localPosition = box.globalToLocal(globalPosition);
}
Future loadImageBundleBytes() async {
ByteData imageBytes = await rootBundle.load(imagePath);
setImageBytes(imageBytes);
}
Future loadSnapshotBytes() async {
RenderRepaintBoundary boxPaint =
paintKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
//RenderObject? boxPaint = paintKey.currentContext.findRenderObject();
ui.Image capture = await boxPaint.toImage();
}
void setImageBytes(ByteData imageBytes) {
List values = imageBytes.buffer.asUint8List();
photo;
photo = img.decodeImage(values)!;
}
}
// image lib uses uses KML color format, convert #AABBGGRR to regular #AARRGGBB
int abgrToArgb(int argbColor) {
int r = (argbColor >> 16) & 0xFF;
int b = argbColor & 0xFF;
return (argbColor & 0xFF00FF00) | (b << 16) | r;
}
`