Коммит 9f5dff7a создал по автору aleksandr.morozov's avatar aleksandr.morozov Зафиксировано автором ovc-serega
Просмотр файлов

[feature] image_cropper_aurora implementation

владелец 56c76cf5
......@@ -21,7 +21,7 @@ migrate_working_dir/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
......@@ -31,3 +31,5 @@ migrate_working_dir/
.flutter-plugins
.flutter-plugins-dependencies
build/
/aurora/flutter
include:
- project: 'oss/flutter/gitlab-ci-configuration'
file: '/plugins/.plugin-ci-mono-repo.yml'
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "f2d5856ef69f4b908411a43ba78a91e40b334580"
channel: "[user-branch]"
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: f2d5856ef69f4b908411a43ba78a91e40b334580
base_revision: f2d5856ef69f4b908411a43ba78a91e40b334580
- platform: aurora
create_revision: f2d5856ef69f4b908411a43ba78a91e40b334580
base_revision: f2d5856ef69f4b908411a43ba78a91e40b334580
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
# Authors
* Kirill Chuvilin, <k.chuvilin@omp.ru>
* Product owner, 2025
* Maintainer, 2025
* Sergey Ovchinnikov, <s.ovchinnikov@omp.ru>
* Reviewer, 2025
* Andrey Vasilyev
* Developer, 2025
* Aleksandr Morozov
* Developer, 2025
* Vladislav Larionov
* Developer, 2025
## 0.0.1
## Updated: 21/05/2025 16:05:02
* TODO: Describe initial release.
## Info
- First release
- Released: 1
## Versions
- Version: 0.1.0 (21/05/2025)
# Contributor License Agreements
Thank you for your interest in contributing
to software projects managed by Open Mobile Platform («We» or «Us»).
This contributor agreement («Agreement»)
documents the rights granted by contributors to Us.
To make this document effective,
please sign it and send it to Us by email or electronic submission.
This is a legally binding document,
so please read it carefully before agreeing to it.
The Agreement may cover more than one software project managed by Us.
## 1. Definitions
**«We» or «Us»** means Open Mobile Platform Limited Liability Company
(Open Mobile Platform LLC),
420500, Republic of Tatarstan, Verkhneuslonsky District,
Innopolis, Universitetskaya Street, h. 7, office 59,
OGRN (Primary State Registration Number) 1161690087020.
**«You»** means the individual who Submits a Contribution to Us.
**«Contribution»** means any work of authorship
that is Submitted by You to Us
in which You own or assert ownership of the Copyright.
**«Copyright»** means all rights protecting works of authorship
owned or controlled by You,
including copyright, moral and neighboring rights, as appropriate,
for the full term of their existence including any extensions by You.
**«Material»** means the work of authorship
which is made available by Us to third parties.
When this Agreement covers more than one software project,
the Material means the work of authorship
to which the Contribution was Submitted.
After You Submit the Contribution,
it may be included in the Material.
**«Submit»** means any form of electronic, verbal, or written communication
sent to Us or our representatives,
including but not limited to electronic mailing lists,
source code control systems, and issue tracking systems
that are managed by, or on behalf of, Us
for the purpose of discussing and improving the Material,
but excluding communication that is conspicuously marked
or otherwise designated in writing by You as «Not a Contribution».
**«Submission Date»** means the date
on which You Submit a Contribution to Us.
**«Effective Date»** means the date You execute this Agreement
or the date You first Submit a Contribution to Us,
whichever is earlier.
**«Media»** means any portion of a Contribution which is not software.
## 2. Grant of Rights
### 2.1. Copyright License
(a) You retain ownership of the Copyright in Your Contribution
and have the same rights to use or license the Contribution
which You would have had without entering into the Agreement.
(b) To the maximum extent permitted by the relevant law,
You grant to Us a perpetual, worldwide, non-exclusive,
transferable, royalty-free, irrevocable license
under the Copyright covering the Contribution,
with the right to sublicense
such rights through multiple tiers of sublicenses,
to reproduce, modify, display, perform and distribute
the Contribution as part of the Material;
provided that this license is conditioned upon compliance with Section 2.3.
### 2.2. Patent License
For patent claims including, without limitation,
method, process, and apparatus claims
which You own, control or have the right to grant, now or in the future,
You grant to Us a perpetual, worldwide, non-exclusive,
transferable, royalty-free, irrevocable patent license,
with the right to sublicense these rights to multiple tiers of sublicensees,
to make, have made, use, sell, offer for sale, import
and otherwise transfer the Contribution
and the Contribution in combination with the Material
(and portions of such combination).
This license is granted only to the extent
that the exercise of the licensed rights infringes such patent claims;
and provided that this license is conditioned upon compliance with Section 2.3.
### 2.3. Outbound License
Based on the grant of rights in Sections 2.1 and 2.2,
if We include Your Contribution in a Material,
We may license the Contribution under any license,
including copyleft, permissive, commercial, or proprietary licenses.
As a condition on the exercise of this right,
We agree to also license the Contribution
under the terms of the license or licenses
which We are using for the Material on the Submission Date.
### 2.4. Our Rights
You acknowledge that We are not obligated
to use Your Contribution as part of the Material
and may decide to include any Contribution We consider appropriate.
## 3. Agreement
You confirm that:
(a) You have the legal authority to enter into this Agreement.
(b) You own the Copyright and patent claims
covering the Contribution which are required
to grant the rights under Section 2.
(c) The grant of rights under Section 2
does not violate any grant of rights
which You have made to third parties, including Your employer.
If You are an employee,
You have had Your employer approve this Agreement
or sign the Entity version of this document.
If You are less than eighteen years old,
please have Your parents or guardian sign the Agreement.
## 4. Disclaimer
EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3,
THE CONTRIBUTION IS PROVIDED «AS IS».
MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES
INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE
AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO US.
TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED,
SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW.
## 5. Miscellaneous
5.1. This Agreement will be governed by and construed
in accordance with the laws of Russian Federation.
5.2. This Agreement sets out the entire agreement between You
and Us for Your Contributions to Us
and overrides all other agreements or understandings.
5.3. If You or We assign the rights or obligations
received through this Agreement to a third party,
as a condition of the assignment,
that third party must agree in writing
to abide by all the rights and obligations in the Agreement.
5.4. The failure of either party to require performance
by the other party of any provision of this Agreement in one situation
shall not affect the right of a party
to require such performance at any time in the future.
A waiver of performance under a provision in one situation
shall not be considered a waiver of the performance
of the provision in the future or a waiver of the provision in its entirety.
5.5. If any provision of this Agreement is found void and unenforceable,
such provision will be replaced to the extent possible with a provision
that comes closest to the meaning of the original provision
and which is enforceable.
The terms and conditions set forth in this Agreement
shall apply notwithstanding any failure of essential purpose
of this Agreement or any limited remedy
to the maximum extent possible under law.
## 6. How to contribute
First of all, thank you for deciding to participate in the development of the project!
Please at the [contribution guidelines](https://gitlab.com/omprussia/wiki/-/wikis/CONTRIBUTING.ru).
This will make the work easier for project maintainers and provide the most enjoyable experience for all participants.
If you like the project but don't have the opportunity to contribute, that's OK.
There are easy ways to support the project, which we will be happy to do as well:
* give the project a star;
* write about the project on social networks;
* mention the project in your projects;
* talk about the project at events;
* tell your friends or colleagues about the project.
TODO: Add your license here.
# The 3-Clause BSD License
_Copyright (c) 2025 Open Mobile Platform LLC._
Redistribution and use in source and binary forms,
with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain
the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce
the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# flutter_image_cropper
**EN** | [RU](README.ru.md)
A new Flutter plugin project.
# flutter_image_cropper_aurora
## Getting Started
The original ReadMe of the image_cropper plugin: [README](https://github.com/hnvn/flutter_image_cropper/blob/master/README.md)
This project is a starting point for a Flutter
[plug-in package](https://flutter.dev/to/develop-plugins),
a specialized package that includes platform-specific implementation code for
Android and/or iOS.
### Description
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
This plugin is an implementation of the [image_cropper package](https://pub.dev/packages/image_cropper) for the Aurora operating system. This plugin is used for cropping images.
The plugin project was generated without specifying the `--platforms` flag, no platforms are currently supported.
To add platforms, run `flutter create -t plugin --platforms <platforms> .` in this directory.
You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/to/pubspec-plugin-platforms.
The plugin uses [Dart code](#dart-component) to provide a customizable visual interface for cropping images. However, the actual image cropping process is handled by the [platform-specific component](#cpp-component).
ReadMe of the usage example: [README](example/README.md)
#### Quick launch
```dart
CroppedFile? resultImage =
await ImageCropper()
.cropImage(
sourcePath: filePath,
uiSettings: AuroraUiSettings(context: context),
);
```
### Contents
- [Description](#description)
- [Build and Install](#build-and-install)
- [Detailed description](#detailed-description)
- [Dart Component](#dart-component)
- [cropImage](#cropimage)
- [recoverImage](#recoverimage)
- [AuroraUiSettings](#aurorauisettings)
- [C++ Component](#cpp-component)
- [Result Saving](#result-saving)
- [Branches](#branches)
- [Usage Example](#usage-example)
- [Compatibility](#compatibility)
- [Usage Rules](#usage-rules)
### Build and Install
**pubspec.yaml**
```yaml
dependencies:
image_cropper: ^9.1.0
image_cropper_aurora:
path: https://gitlab.com/omprussia/flutter/flutter-community-plugins/image_cropper_aurora.git
```
**desktop**
```desktop
Permissions=UserDirs;
```
**spec**
```spec
BuildRequires: pkgconfig(Qt5Core)
```
**main.cpp**
```cpp
#include <flutter/flutter_aurora.h>
#include <flutter/flutter_compatibility_qt.h> // <- Enable Qt
#include "generated_plugin_registrant.h"
int main(int argc, char *argv[]) {
aurora::EnableQtCompatibility(); // <- Enable Qt
aurora::Initialize(argc, argv);
aurora::RegisterPlugins();
aurora::Launch();
return 0;
}
```
### Detailed description
#### Dart component
#### cropImage
The `cropImage` method is designed for cropping images. It takes the path to the original image as input and returns the cropped image as a result. When this method is invoked, a new screen opens, allowing the user to interactively adjust the cropping area. The crop screen is implemented using the [crop_image cross-platform plugin](https://pub.dev/packages/crop_image), which provides a flexible interface for cropping operations.
When the `cropImage` method is called, it performs the following steps:
1. **Path storage**: The method accepts a `sourcePath` parameter, which specifies the path to the original image file. This path is stored in the `_sourcePath` variable internally. This storage mechanism allows the method to retain the reference to the source image for recovering the original image.
2. **Dialog initialization**: A crop screen is displayed, enabling the user to select and adjust the cropping area. This screen can be customized using the [AuroraUiSettings](#aurorauisettings) configuration.
3. **Delegation to Platform Plugin**: Once the user confirms the cropping area, the method delegates the image processing and saving tasks to the [platform component](#c++-component). The platform plugin is responsible for handling the actual cropping operation and saving the cropped image to a new file.
4. **Result handling**: The method gets the path to cropped image from platform component and returns a `Future<CroppedFile?>`, which resolves to a [CroppedFile](https://github.com/hnvn/flutter_image_cropper/blob/99d967d04e174f62dee298ca61b1dae900c6eda8/image_cropper_platform_interface/lib/src/models/cropped_file/io.dart#L14) object representing the cropped image if the operation is successful. If the user cancels the operation or an error occurs, the method returns `null`.
#### recoverImage
The recoverImage method is designed to recover the source image that was previously set for cropping. This method is particularly useful when you need to retrieve the original image used during the last cropping operation without requiring the user to reselect it.
When invoked, the method checks whether a source image path (`sourcePath`) was provided during the last call to the [cropImage](#cropimage) method. If such a path is saved in `_sourcePath`, the method returns a [CroppedFile](https://github.com/hnvn/flutter_image_cropper/blob/99d967d04e174f62dee298ca61b1dae900c6eda8/image_cropper_platform_interface/lib/src/models/cropped_file/io.dart#L14) object representing the source image. However, if no source image path is available, the method returns null.
It is important to note that ***this method does not perform any additional processing*** or recovery of previously cropped images. Its purpose is to provide access to the original source image that was set for cropping. The implementation of the method is straightforward. It checks whether the `_sourcePath` variable, which stores the path to the source image, is null. If `_sourcePath` is null, the method returns `Future.value(null)`. Otherwise, it wraps the `_sourcePath` in a `CroppedFile` object and returns it as a future.
#### AuroraUiSettings
The `AuroraUiSettings` class provides a set of customization options for the image cropping dialog. This class extends the [PlatformUiSettings](https://github.com/hnvn/flutter_image_cropper/blob/99d967d04e174f62dee298ca61b1dae900c6eda8/image_cropper_platform_interface/lib/src/models/settings.dart#L128) class and allows developers to customize the cropping interface to match their application's design. You can read more about the possible settings [here](/lib/src/aurora_ui_settings.dart).
***Passing the "context" argument for the Aurora OS is necessary so that the plugin can show the user a crop screen with image editing***
#### Cpp Component
The C++-component is designed to handle calls to only one method: `cropImage`. This method is invoked when the user clicks the "crop" button in the crop screen of the Dart component. The `cropImage` method accepts a set of arguments that define the parameters for the cropping operation.
The mandatory arguments include:
- `source_path`: The path to the original image file.
- `crop_top`: The top boundary of the cropping area.
- `crop_bottom`: The bottom boundary of the cropping area.
- `crop_left`: The left boundary of the cropping area.
- `crop_right`: The right boundary of the cropping area.
These parameters are essential for defining the cropping region and ensuring that the platform component can process the image. Without these arguments, the cropping operation cannot be performed.
In addition to the mandatory arguments, the `cropImage` method also accepts several optional parameters. These include:
- `max_width`: The maximum width of the cropped image.
- `max_height`: The maximum height of the cropped image.
- `ratio_x`: The x-component of the aspect ratio for the cropping area.
- `ratio_y`: The y-component of the aspect ratio for the cropping area.
- `compress_format`: The format in which the cropped image will be compressed (jpg, png).
- `compress_quality`: The quality level for image compression, ranging from 0 to 100.
- `rotation`: The rotation angle applied to the image during cropping.
If these optional parameters are not provided, they will either be replaced with default values or will not influence the result of the cropping operation. For example, if `max_width` and `max_height` are not specified, the cropped image will retain its original dimensions, constrained by the cropping boundaries. Similarly, if `compress_format` or `compress_quality` is omitted, the platform component will use default compression settings.
These parameters are passed to the platform component via MethodChannel to perform the actual image processing and saving tasks.
It should be noted that ***the visual interface allows the user to select an area larger than the maxWidth and maxHeight passed to the cropImage method***. In this case, after cropping by coordinates, the image will be cropped to the maximum length and width relative to its center and then cropped to the specified aspect ratio.
#### Result saving
The `cropImage` method saves the cropped image as a new image, following a specific naming and storage convention. The output file path is generated using a predefined template that ensures uniqueness and consistency. Each cropped image is saved in the user's Pictures directory, with the file name prefixed by `ImageCropper-` followed by a timestamp in the format `yyyy-MM-dd-HH-mm-ss`. The timestamp is dynamically generated based on the current date and time to avoid filename conflicts. The complete output path is constructed by appending the generated filename and the specified compression format (jpg or png) to the base directory path, which is defined as the home directory's Pictures folder. Example: `ImageCropper-2025-04-17-15-05-08.jpg`.
#### Usage example
You can find an example [here](example/lib/main.dart).
### Branches
The versions of the application comply with the branch naming convention, which can be found [here](https://developer.auroraos.ru/doc/software_development/examples#branches)
### Compatibility
* Aurora OS: 5.1.3+
### Usage Rules
* The source code of the project is provided under [the license](LICENSE.BSD-3-Clause.md), that allows it to be used in third-party applications.
* To participate in the development of the project, please read the [contributor agreement](CONTRIBUTING.md). If you plan to contribute your own source code to the project, you will need to accept the [CLA agreement](https://gitlab.com/omprussia/wiki/-/wikis/CLA).
* For information about contributors see [AUTHORS](AUTHORS.md).
* [Code of conduct](CODE_OF_CONDUCT.md) is a current set of rules of the Open Mobile Platform which informs you how we expect the members of the community will interact while contributing and communicating.
[EN](README.md) | **RU**
# flutter_image_cropper_aurora
Исходный ReadMe плагина image_cropper: [README](https://github.com/hnvn/flutter_image_cropper/blob/master/README.md)
### Описание
Этот плагин является реализацией [image_cropper](https://pub.dev/packages/image_cropper) для операционной системы Аврора. Этот плагин используется для обрезки изображений.
Плагин использует [Dart-код](#dart-component) для предоставления настраиваемого визуального интерфейса для обрезки изображений. Однако сам процесс обрезки выполняется [платформенным компонентом](#cpp-component).
ReadMe примера использования: [README](example/README.ru.md)
#### Быстрый запуск
```dart
CroppedFile? resultImage =
await ImageCropper()
.cropImage(
sourcePath: filePath,
uiSettings: AuroraUiSettings(context: context),
);
```
### Содержание
- [Описание](#описание)
- [Ветки](#ветки)
- [Подробное описание](#подробное-описание)
- [Dart компонент](#dart-компонент)
- [cropImage](#cropimage)
- [recoverImage](#recoverimage)
- [AuroraUiSettings](#aurorauisettings)
- [C++ компонент](#cpp-компонент)
- [Сохранение результата](#сохранение-результата)
- [Сборка и установка](#сборка-и-установка)
- [Пример использования](#пример-использования)
- [Совместимость](#совместимость)
- [Правила использования](#правила-использования)
### Сборка и установка
**pubspec.yaml**
```yaml
dependencies:
image_cropper: ^9.1.0
image_cropper_aurora:
path: https://gitlab.com/omprussia/flutter/flutter-community-plugins/image_cropper_aurora.git
```
**desktop**
```desktop
Permissions=UserDirs;
```
**spec**
```spec
BuildRequires: pkgconfig(Qt5Core)
```
**main.cpp**
```cpp
#include <flutter/flutter_aurora.h>
#include <flutter/flutter_compatibility_qt.h> // <- Enable Qt
#include "generated_plugin_registrant.h"
int main(int argc, char *argv[]) {
aurora::EnableQtCompatibility(); // <- Enable Qt
aurora::Initialize(argc, argv);
aurora::RegisterPlugins();
aurora::Launch();
return 0;
}
```
### Подробное описание
#### Dart Компонент
#### cropImage
Метод `cropImage` предназначен для обрезки изображений. Он принимает путь к исходному изображению в качестве входных данных и возвращает обрезанное изображение в качестве результата. При вызове этого метода открывается экран обрезки изображения, позволяющий пользователю в интерактивном режиме настроить область обрезки. Экран реализован с помощью кроссплатформенного плагина [crop_image](https://pub.dev/packages/crop_image), который предоставляет гибкий интерфейс для операций обрезки.
Когда вызывается метод `cropImage`, он выполняет следующие действия:
1. **Сохранение пути**: Метод принимает параметр `sourcePath`, который указывает путь к исходному файлу изображения. Этот путь хранится во внутренней переменной `_sourcePath`. Это позволяет сохранять ссылку на исходное изображение для операции восстановления.
2. **Инициализация диалогового окна**: Отображается экран обрезки, позволяющий пользователю выбрать область обрезки. Этот экран можно настроить с помощью конфигурации [AuroraUiSettings](#aurorauisettings).
3. **Делегирование обрезки**: Как только пользователь подтверждает область обрезки, метод делегирует задачу обработки и сохранения изображения [платформенному компоненту](#cpp-компонент). Платформенный компонент отвечает за фактическую обрезку и сохранение обработанного изображения его в новом файле.
4. **Обработка результатов**: Метод получает путь к обрезанному изображению из платформенного компонента и возвращает `Future<CroppedFile?>`, который преобразуется в объект [CroppedFile](https://github.com/hnvn/flutter_image_cropper/blob/99d967d04e174f62dee298ca61b1dae900c6eda8/image_cropper_platform_interface/lib/src/models/cropped_file/io.dart#L14), представляющий обрезанное изображение в случае, если операция выполнена успешно. Если пользователь отменяет операцию или возникает ошибка, метод возвращает значение `null`.
#### recoverImage
Метод recoverImage предназначен для восстановления исходного изображения, которое ранее было настроено на обрезку. Этот метод необходим, когда вам нужно восстановить исходное изображение, использованное во время последней операции обрезки, не требуя от пользователя повторного выбора.
При вызове метод проверяет, был ли указан путь к исходному изображению (`sourcePath`) во время последнего вызова метода [cropImage](#cropimage). Если такой путь сохранен в `_sourcePath`, метод возвращает объект [CroppedFile](https://github.com/hnvn/flutter_image_cropper/blob/99d967d04e174f62dee298ca61b1dae900c6eda8/image_cropper_platform_interface/lib/src/models/cropped_file/io.dart#L14) - исходное изображение. Если путь к исходному изображению не был установлен, метод возвращает значение null.
Важно отметить, что ***этот метод не выполняет никакой дополнительной обработки или восстановления ранее обрезанных изображений***. Его цель - предоставить доступ к исходному изображению, путь к которому был указан в методе обрезки. Метод проверяет, имеет ли значение `null` переменная `_sourcePath`, в которой хранится путь к исходному изображению. Если значение `_sourcePath` равно `null`, метод возвращает значение `Future.value(null)`. В противном случае он оборачивает `_sourcePath` в объект `CroppedFile` и возвращает его.
#### AuroraUiSettings
Класс `AuroraUiSettings` предоставляет набор параметров настройки для диалогового окна обрезки изображений. Этот класс расширяет класс [PlatformUiSettings](https://github.com/hnvn/flutter_image_cropper/blob/99d967d04e174f62dee298ca61b1dae900c6eda8/image_cropper_platform_interface/lib/src/models/settings.dart#L128) и позволяет разработчикам настраивать интерфейс обрезки в соответствии с дизайном своего приложения. Вы можете прочитать больше о возможных настройках [здесь](/lib/src/aurora_ui_settings.dart).
***Передача аргумента "context" в AuroraUiSettings для Aurora OS необходима для того, чтобы плагин мог показывать пользователю экран редактирования изображения.***
#### Cpp-компонент
C++-компонент предназначен для обработки вызовов только одного метода: `cropImage`. Этот метод вызывается, когда пользователь нажимает кнопку "Crop" на экране обрезки Dart-компонента. Метод `cropImage` принимает набор аргументов, которые определяют параметры для операции обрезки.
К обязательным аргументам относятся:
- `source_path`: путь к исходному файлу изображения.
- `crop_top`: верхняя граница области обрезки.
- `crop_bottom`: Нижняя граница области обрезки.
- `crop_left`: левая граница области обрезки.
- `crop_right`: правая граница области обрезки.
Эти параметры необходимы для определения области обрезки и обеспечения возможности обработки изображения компонентом платформы. Без этих аргументов операция обрезки не может быть выполнена.
В дополнение к обязательным аргументам, метод `cropImage` может принимать несколько необязательных параметров. К ним относятся:
- `max_width`: Максимальная ширина обрезанного изображения.
- `max_height`: максимальная высота обрезанного изображения.
- `ratio_x`: x-составляющая соотношения сторон для области кадрирования.
- `ratio_y`: y-составляющая соотношения сторон для области кадрирования.
- `compress_format`: формат, в котором будет сохранено обрезанное изображение (jpg, png).
- `compress_quality`: уровень качества сжатия изображения в диапазоне от 0 до 100.
- `rotation`: угол поворота, применяемый к изображению во время обрезки.
Если эти необязательные параметры не указаны, они либо будут заменены значениями по умолчанию, либо не повлияют на результат операции обрезки. Например, если не указаны значения `max_width` и `max_height`, обрезанное изображение сохранит свои первоначальные размеры, ограниченные границами сетки обрезки. Аналогично, если не указано значение `compress_format` или `compress_quality`, компонент платформы будет использовать настройки сжатия по умолчанию.
Эти параметры передаются компоненту платформы через `MethodChannel`.
Следует отметить, что ***визуальный интерфейс позволяет пользователю выбрать область, размер которой превышает значения maxWidth и maxHeight, переданные методу cropImage***. В этом случае после обрезки по координатам изображение будет обрезано до максимальной длины и ширины относительно его центра, а затем обрезано до заданного соотношения сторон.
#### Сохранение результата
Метод `cropImage` сохраняет обрезанное изображение как новое, следуя определенным правилам именования и хранения. Путь к выходному файлу генерируется с использованием предопределенного шаблона, который обеспечивает уникальность и согласованность. Каждое обрезанное изображение сохраняется в каталоге изображений пользователя с префиксом имени файла `ImageCropper-`, за которым следует временная метка в формате `гггг-ММ-дд-ЧЧ-мм-сс`. Временная метка генерируется динамически на основе текущей даты и времени, чтобы избежать конфликтов имён файлов. Полный выходной путь создается путем добавления сгенерированного имени файла и указанного формата сжатия (jpg или png) к базовому пути к каталогу, который определяется как папка изображений в домашнем каталоге. Пример: `ImageCropper-2025-04-17-15-05-08.jpg`.
#### Пример использования
Вы можете найти пример [здесь](example/lib/main.dart).
### Ветки
Версии приложения соответствуют соглашению о наименовании веток, которое можно найти [здесь](https://developer.auroraos.ru/doc/software_development/examples#branches).
### Совместимость
* Aurora OS: 5.1.3+
### Правила использования
* Исходный код проекта предоставляется по [лицении](LICENSE.BSD-3-Clause.md), которая позволяет использовать его в сторонних приложениях.
* Для участия в развитии проекта, пожалуйста, ознакомьтесь с [cоглашением](https://gitlab.com/omprussia/flutter/demos/call_api/-/blob/master/CONTRIBUTING.md) участника.
Если Вы планируете присылать свой исходный код для включения в состав проекта, Вам понадобится принять [условия CLA](https://gitlab.com/omprussia/wiki/-/wikis/CLA.ru).
* Информация об участниках указана в файле [AUTHORS](AUTHORS)
* [Кодекс поведения](https://gitlab.com/omprussia/wiki/-/wikis/Code_of_Conduct.ru) — это действующий набор правил компании «Открытая Мобильная Платформа», который информирует об ожиданиях по взаимодействию между членами сообщества при общении и работе над проектами.
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
The MIT License (MIT)
Copyright (c) 2016 Gabi Melman.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-- NOTE: Third party dependency used by this software --
This software depends on the fmt lib (MIT License),
and users must comply to its license: https://raw.githubusercontent.com/fmtlib/fmt/master/LICENSE
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
//
// Async logging using global thread pool
// All loggers created here share same global thread pool.
// Each log message is pushed to a queue along with a shared pointer to the
// logger.
// If a logger deleted while having pending messages in the queue, it's actual
// destruction will defer
// until all its messages are processed by the thread pool.
// This is because each message in the queue holds a shared_ptr to the
// originating logger.
#include <spdlog/async_logger.h>
#include <spdlog/details/registry.h>
#include <spdlog/details/thread_pool.h>
#include <functional>
#include <memory>
#include <mutex>
namespace spdlog {
namespace details {
static const size_t default_async_q_size = 8192;
}
// async logger factory - creates async loggers backed with thread pool.
// if a global thread pool doesn't already exist, create it with default queue
// size of 8192 items and single thread.
template <async_overflow_policy OverflowPolicy = async_overflow_policy::block>
struct async_factory_impl {
template <typename Sink, typename... SinkArgs>
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args) {
auto &registry_inst = details::registry::instance();
// create global thread pool if not already exists..
auto &mutex = registry_inst.tp_mutex();
std::lock_guard<std::recursive_mutex> tp_lock(mutex);
auto tp = registry_inst.get_tp();
if (tp == nullptr) {
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U);
registry_inst.set_tp(tp);
}
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink),
std::move(tp), OverflowPolicy);
registry_inst.initialize_logger(new_logger);
return new_logger;
}
};
using async_factory = async_factory_impl<async_overflow_policy::block>;
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
template <typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name,
SinkArgs &&...sink_args) {
return async_factory::create<Sink>(std::move(logger_name),
std::forward<SinkArgs>(sink_args)...);
}
template <typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name,
SinkArgs &&...sink_args) {
return async_factory_nonblock::create<Sink>(std::move(logger_name),
std::forward<SinkArgs>(sink_args)...);
}
// set global thread pool.
inline void init_thread_pool(size_t q_size,
size_t thread_count,
std::function<void()> on_thread_start,
std::function<void()> on_thread_stop) {
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start,
on_thread_stop);
details::registry::instance().set_tp(std::move(tp));
}
inline void init_thread_pool(size_t q_size,
size_t thread_count,
std::function<void()> on_thread_start) {
init_thread_pool(q_size, thread_count, on_thread_start, [] {});
}
inline void init_thread_pool(size_t q_size, size_t thread_count) {
init_thread_pool(
q_size, thread_count, [] {}, [] {});
}
// get the global thread pool.
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() {
return details::registry::instance().get_tp();
}
} // namespace spdlog
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/async_logger.h>
#endif
#include <spdlog/details/thread_pool.h>
#include <spdlog/sinks/sink.h>
#include <memory>
#include <string>
SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
sinks_init_list sinks_list,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy)
: async_logger(std::move(logger_name),
sinks_list.begin(),
sinks_list.end(),
std::move(tp),
overflow_policy) {}
SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
sink_ptr single_sink,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy)
: async_logger(
std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) {}
// send the log message to the thread pool
SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){
SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
}
else {
throw_spdlog_ex("async log: thread pool doesn't exist anymore");
}
}
SPDLOG_LOGGER_CATCH(msg.source)
}
// send flush request to the thread pool
SPDLOG_INLINE void spdlog::async_logger::flush_(){
SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
}
else {
throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
}
}
SPDLOG_LOGGER_CATCH(source_loc())
}
//
// backend functions - called from the thread pool to do the actual job
//
SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) {
for (auto &sink : sinks_) {
if (sink->should_log(msg.level)) {
SPDLOG_TRY { sink->log(msg); }
SPDLOG_LOGGER_CATCH(msg.source)
}
}
if (should_flush_(msg)) {
backend_flush_();
}
}
SPDLOG_INLINE void spdlog::async_logger::backend_flush_() {
for (auto &sink : sinks_) {
SPDLOG_TRY { sink->flush(); }
SPDLOG_LOGGER_CATCH(source_loc())
}
}
SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) {
auto cloned = std::make_shared<spdlog::async_logger>(*this);
cloned->name_ = std::move(new_name);
return cloned;
}
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// Fast asynchronous logger.
// Uses pre allocated queue.
// Creates a single back thread to pop messages from the queue and log them.
//
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until
// space is available in the queue)
// Upon destruction, logs all remaining messages in the queue before
// destructing..
#include <spdlog/logger.h>
namespace spdlog {
// Async overflow policy - block by default.
enum class async_overflow_policy {
block, // Block until message can be enqueued
overrun_oldest, // Discard oldest message in the queue if full when trying to
// add new item.
discard_new // Discard new message if the queue is full when trying to add new item.
};
namespace details {
class thread_pool;
}
class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>,
public logger {
friend class details::thread_pool;
public:
template <typename It>
async_logger(std::string logger_name,
It begin,
It end,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block)
: logger(std::move(logger_name), begin, end),
thread_pool_(std::move(tp)),
overflow_policy_(overflow_policy) {}
async_logger(std::string logger_name,
sinks_init_list sinks_list,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
async_logger(std::string logger_name,
sink_ptr single_sink,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
std::shared_ptr<logger> clone(std::string new_name) override;
protected:
void sink_it_(const details::log_msg &msg) override;
void flush_() override;
void backend_sink_it_(const details::log_msg &incoming_log_msg);
void backend_flush_();
private:
std::weak_ptr<details::thread_pool> thread_pool_;
async_overflow_policy overflow_policy_;
};
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "async_logger-inl.h"
#endif
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/cfg/helpers.h>
#include <spdlog/details/registry.h>
//
// Init log levels using each argv entry that starts with "SPDLOG_LEVEL="
//
// set all loggers to debug level:
// example.exe "SPDLOG_LEVEL=debug"
// set logger1 to trace level
// example.exe "SPDLOG_LEVEL=logger1=trace"
// turn off all logging except for logger1 and logger2:
// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info"
namespace spdlog {
namespace cfg {
// search for SPDLOG_LEVEL= in the args and use it to init the levels
inline void load_argv_levels(int argc, const char **argv) {
const std::string spdlog_level_prefix = "SPDLOG_LEVEL=";
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
if (arg.find(spdlog_level_prefix) == 0) {
auto levels_string = arg.substr(spdlog_level_prefix.size());
helpers::load_levels(levels_string);
}
}
}
inline void load_argv_levels(int argc, char **argv) {
load_argv_levels(argc, const_cast<const char **>(argv));
}
} // namespace cfg
} // namespace spdlog
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/cfg/helpers.h>
#include <spdlog/details/os.h>
#include <spdlog/details/registry.h>
//
// Init levels and patterns from env variables SPDLOG_LEVEL
// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger).
// Note - fallback to "info" level on unrecognized levels
//
// Examples:
//
// set global level to debug:
// export SPDLOG_LEVEL=debug
//
// turn off all logging except for logger1:
// export SPDLOG_LEVEL="*=off,logger1=debug"
//
// turn off all logging except for logger1 and logger2:
// export SPDLOG_LEVEL="off,logger1=debug,logger2=info"
namespace spdlog {
namespace cfg {
inline void load_env_levels(const char* var = "SPDLOG_LEVEL") {
auto env_val = details::os::getenv(var);
if (!env_val.empty()) {
helpers::load_levels(env_val);
}
}
} // namespace cfg
} // namespace spdlog
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/cfg/helpers.h>
#endif
#include <spdlog/details/os.h>
#include <spdlog/details/registry.h>
#include <spdlog/spdlog.h>
#include <algorithm>
#include <sstream>
#include <string>
#include <utility>
namespace spdlog {
namespace cfg {
namespace helpers {
// inplace convert to lowercase
inline std::string &to_lower_(std::string &str) {
std::transform(str.begin(), str.end(), str.begin(), [](char ch) {
return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch);
});
return str;
}
// inplace trim spaces
inline std::string &trim_(std::string &str) {
const char *spaces = " \n\r\t";
str.erase(str.find_last_not_of(spaces) + 1);
str.erase(0, str.find_first_not_of(spaces));
return str;
}
// return (name,value) trimmed pair from given "name=value" string.
// return empty string on missing parts
// "key=val" => ("key", "val")
// " key = val " => ("key", "val")
// "key=" => ("key", "")
// "val" => ("", "val")
inline std::pair<std::string, std::string> extract_kv_(char sep, const std::string &str) {
auto n = str.find(sep);
std::string k, v;
if (n == std::string::npos) {
v = str;
} else {
k = str.substr(0, n);
v = str.substr(n + 1);
}
return std::make_pair(trim_(k), trim_(v));
}
// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.."
// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...}
inline std::unordered_map<std::string, std::string> extract_key_vals_(const std::string &str) {
std::string token;
std::istringstream token_stream(str);
std::unordered_map<std::string, std::string> rv{};
while (std::getline(token_stream, token, ',')) {
if (token.empty()) {
continue;
}
auto kv = extract_kv_('=', token);
rv[kv.first] = kv.second;
}
return rv;
}
SPDLOG_INLINE void load_levels(const std::string &input) {
if (input.empty() || input.size() > 512) {
return;
}
auto key_vals = extract_key_vals_(input);
std::unordered_map<std::string, level::level_enum> levels;
level::level_enum global_level = level::info;
bool global_level_found = false;
for (auto &name_level : key_vals) {
auto &logger_name = name_level.first;
auto level_name = to_lower_(name_level.second);
auto level = level::from_str(level_name);
// ignore unrecognized level names
if (level == level::off && level_name != "off") {
continue;
}
if (logger_name.empty()) // no logger name indicate global level
{
global_level_found = true;
global_level = level;
} else {
levels[logger_name] = level;
}
}
details::registry::instance().set_levels(std::move(levels),
global_level_found ? &global_level : nullptr);
}
} // namespace helpers
} // namespace cfg
} // namespace spdlog
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <unordered_map>
namespace spdlog {
namespace cfg {
namespace helpers {
//
// Init levels from given string
//
// Examples:
//
// set global level to debug: "debug"
// turn off all logging except for logger1: "off,logger1=debug"
// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info"
//
SPDLOG_API void load_levels(const std::string &txt);
} // namespace helpers
} // namespace cfg
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "helpers-inl.h"
#endif // SPDLOG_HEADER_ONLY
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/common.h>
#endif
#include <algorithm>
#include <iterator>
namespace spdlog {
namespace level {
#if __cplusplus >= 201703L
constexpr
#endif
static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;
SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT {
return level_string_views[l];
}
SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT {
return short_level_names[l];
}
SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT {
auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name);
if (it != std::end(level_string_views))
return static_cast<level::level_enum>(std::distance(std::begin(level_string_views), it));
// check also for "warn" and "err" before giving up..
if (name == "warn") {
return level::warn;
}
if (name == "err") {
return level::err;
}
return level::off;
}
} // namespace level
SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
: msg_(std::move(msg)) {}
SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) {
#ifdef SPDLOG_USE_STD_FORMAT
msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what();
#else
memory_buf_t outbuf;
fmt::format_system_error(outbuf, last_errno, msg.c_str());
msg_ = fmt::to_string(outbuf);
#endif
}
SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT { return msg_.c_str(); }
SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) {
SPDLOG_THROW(spdlog_ex(msg, last_errno));
}
SPDLOG_INLINE void throw_spdlog_ex(std::string msg) { SPDLOG_THROW(spdlog_ex(std::move(msg))); }
} // namespace spdlog
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать