GOOGLE ADS

среда, 27 апреля 2022 г.

Как обрезать кадр предварительного просмотра камеры Flutter

Я пытаюсь делать квадратные снимки в своем приложении. Я использую пакет камеры и пытаюсь отобразить обрезанную по центру версию CameraPreviewвиджета.

Моя цель — показать центральный квадрат предварительного просмотра (во всю ширину) с равномерным обрезанием сверху и снизу.

Я изо всех сил пытался заставить это работать, поэтому я создал минимальный пример, используя фиксированное изображение. (извиняюсь за скучное фото меня в кресле):

import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Example',
theme: ThemeData(),
home: Scaffold(
body: Example(),
),
);
}
}
class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
CroppedCameraPreview(),
// Something to occupy the rest of the space
Expanded(
child: Container(),
)
],
);
}
}
class CroppedCameraPreview extends StatelessWidget {
@override
Widget build(BuildContext context) {
// We will pretend this is a camera preview (to make demo easier)
var cameraImage = Image.network("https://i.imgur.com/gZfg4jm.jpg");
var aspectRatio = 1280 / 720;
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.width,
child: ClipRect(
child: new OverflowBox(
alignment: Alignment.center,
child: FittedBox(
fit: BoxFit.fitWidth,
child: cameraImage,
),
),
),
);
}
}

Это отлично работает - я получаю изображение во всю ширину экрана, обрезанное по центру и помещаемое в верхнюю часть моего приложения.

Однако, если я добавлю этот код в свое существующее приложение и заменю cameraImageна CameraPreview, я получу много ошибок макета:

flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during performResize():
flutter: TextureBox object was given an infinite size during layout.
flutter: This probably means that it is a render object that tries to be as big as possible, but it was put
flutter: inside another render object that allows its children to pick their own size.
flutter: The nearest ancestor providing an unbounded width constraint is:
flutter: RenderFittedBox#0bd54 NEEDS-LAYOUT NEEDS-PAINT
flutter: creator: FittedBox ← OverflowBox ← ClipRect ← ConstrainedBox ← Container ← Stack ← ConstrainedBox
flutter: ← Container ← CameraWidget ← Column ← CameraPage ← MediaQuery ← ⋯
flutter: parentData: offset=Offset(0.0, 0.0) (can use size)
flutter: constraints: BoxConstraints(w=320.0, h=320.0)
flutter: size: MISSING
flutter: fit: fitWidth
flutter: alignment: center
flutter: textDirection: ltr
flutter: The nearest ancestor providing an unbounded height constraint is:
flutter: RenderFittedBox#0bd54 NEEDS-LAYOUT NEEDS-PAINT
flutter: creator: FittedBox ← OverflowBox ← ClipRect ← ConstrainedBox ← Container ← Stack ← ConstrainedBox
flutter: ← Container ← CameraWidget ← Column ← CameraPage ← MediaQuery ← ⋯
flutter: parentData: offset=Offset(0.0, 0.0) (can use size)
flutter: constraints: BoxConstraints(w=320.0, h=320.0)
flutter: size: MISSING
flutter: fit: fitWidth
flutter: alignment: center
flutter: textDirection: ltr
flutter: The constraints that applied to the TextureBox were:
flutter: BoxConstraints(unconstrained)
flutter: The exact size it was given was:
flutter: Size(Infinity, Infinity)
flutter: See https://flutter.io/layout/ for more information.

Кто-нибудь может подсказать, почему я получаю ошибки при предварительном просмотре и как их избежать?


Решение проблемы

У меня есть фрагмент кода, похожий на тот, что используется в ответе.

Как и ответ, он поддерживает случаи, когда соотношение сторон камеры отличается от соотношения сторон экрана.

Хотя моя версия имеет некоторое отличие: она не требует MediaQuery для получения размера устройства, поэтому она будет соответствовать ширине любого родителя (а не только полноэкранной ширины)

....
return AspectRatio(
aspectRatio: 1,
child: ClipRect(
child: Transform.scale(
scale: 1 / _cameraController.value.aspectRatio,
child: Center(
child: AspectRatio(
aspectRatio: _cameraController.value.aspectRatio,
child: CameraPreview(_cameraController),
),
),
),
),
);

Чтобы обрезать изображение по центру квадрата, см. фрагмент ниже.

Он одинаково хорошо работает с изображениями в портретной и альбомной ориентации. Это также позволяет опционально зеркально отразить изображение (это может быть полезно, если вы хотите сохранить оригинальный зеркальный вид с селфи-камеры)

import 'dart:io';
import 'dart:math';
import 'package:flutter/rendering.dart';
import 'package:image/image.dart' as IMG;
class ImageProcessor {
static Future cropSquare(String srcFilePath, String destFilePath, bool flip) async {
var bytes = await File(srcFilePath).readAsBytes();
IMG.Image src = IMG.decodeImage(bytes);
var cropSize = min(src.width, src.height);
int offsetX = (src.width - min(src.width, src.height)) ~/ 2;
int offsetY = (src.height - min(src.width, src.height)) ~/ 2;
IMG.Image destImage =
IMG.copyCrop(src, offsetX, offsetY, cropSize, cropSize);
if (flip) {
destImage = IMG.flipVertical(destImage);
}
var jpg = IMG.encodeJpg(destImage);
await File(destFilePath).writeAsBytes(jpg);
}
}

Для этого кода требуется пакет изображения. Добавьте его в pubspec.yaml:

 dependencies:
image: ^2.1.4

Комментариев нет:

Отправить комментарий

Laravel Datatable addColumn returns ID of one record only

Я пытаюсь использовать Yajra Datatable для интеграции DataTable на свой веб-сайт. Я смог отобразить таблицу, но столкнулся с проблемой. В по...