adding packages
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
library image_resizer;
|
||||
|
||||
export 'src/folders.dart';
|
||||
export 'src/generator.dart';
|
||||
export 'src/template.dart';
|
||||
export 'src/generator/impl.dart';
|
||||
@@ -0,0 +1,108 @@
|
||||
import 'template.dart';
|
||||
|
||||
abstract class ImageFolder {
|
||||
final String path;
|
||||
final List<IconTemplate> templates;
|
||||
ImageFolder(this.path, this.templates);
|
||||
}
|
||||
|
||||
class WebIconsFolder extends ImageFolder {
|
||||
WebIconsFolder({
|
||||
String path = 'web/icons',
|
||||
this.favicion,
|
||||
List<WebIcon> icons = _defaultIcons,
|
||||
}) : super(path, icons);
|
||||
|
||||
static const _defaultIcons = [
|
||||
WebIcon(size: 192),
|
||||
WebIcon(size: 512),
|
||||
];
|
||||
|
||||
final WebFavicon favicion;
|
||||
}
|
||||
|
||||
class IosIconsFolder extends ImageFolder {
|
||||
IosIconsFolder({
|
||||
String path = 'ios/Runner/Assets.xcassets/AppIcon.appiconset',
|
||||
List<IosIcon> icons = _defaultIcons,
|
||||
}) : super(path, icons);
|
||||
|
||||
static const _defaultIcons = [
|
||||
IosIcon(size: 20, scale: 1),
|
||||
IosIcon(size: 20, scale: 2),
|
||||
IosIcon(size: 20, scale: 3),
|
||||
IosIcon(size: 29, scale: 1),
|
||||
IosIcon(size: 29, scale: 2),
|
||||
IosIcon(size: 29, scale: 3),
|
||||
IosIcon(size: 40, scale: 1),
|
||||
IosIcon(size: 40, scale: 2),
|
||||
IosIcon(size: 40, scale: 3),
|
||||
IosIcon(size: 60, scale: 2),
|
||||
IosIcon(size: 60, scale: 3),
|
||||
IosIcon(size: 76, scale: 1),
|
||||
IosIcon(size: 76, scale: 2),
|
||||
IosIcon(size: 83, scale: 2, point5: true),
|
||||
IosIcon(size: 1024, scale: 1),
|
||||
];
|
||||
|
||||
Map<String, dynamic> toJson({int version = 1, String author = 'xcode'}) {
|
||||
return {
|
||||
"images": [
|
||||
for (var icon in this.templates) ...{
|
||||
if (icon is IosIcon) ...{
|
||||
icon.toJson(),
|
||||
},
|
||||
}
|
||||
],
|
||||
"info": {"version": version, "author": author}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class MacOSIconsFolder extends ImageFolder {
|
||||
MacOSIconsFolder({
|
||||
String path = 'macos/Runner/Assets.xcassets/AppIcon.appiconset',
|
||||
List<MacOSIcon> icons = _defaultIcons,
|
||||
}) : super(path, icons);
|
||||
|
||||
static const _defaultIcons = [
|
||||
MacOSIcon(size: 16, scale: 1, name: '16'),
|
||||
MacOSIcon(size: 16, scale: 2, name: '32'),
|
||||
MacOSIcon(size: 32, scale: 1, name: '32'),
|
||||
MacOSIcon(size: 32, scale: 2, name: '64'),
|
||||
MacOSIcon(size: 128, scale: 1, name: '128'),
|
||||
MacOSIcon(size: 128, scale: 2, name: '256'),
|
||||
MacOSIcon(size: 256, scale: 1, name: '256'),
|
||||
MacOSIcon(size: 256, scale: 2, name: '512'),
|
||||
MacOSIcon(size: 512, scale: 1, name: '512'),
|
||||
MacOSIcon(size: 512, scale: 2, name: '1024'),
|
||||
];
|
||||
|
||||
Map<String, dynamic> toJson({int version = 1, String author = 'xcode'}) {
|
||||
return {
|
||||
"images": [
|
||||
for (var icon in this.templates) ...{
|
||||
if (icon is IosIcon) ...{
|
||||
icon.toJson(),
|
||||
},
|
||||
}
|
||||
],
|
||||
"info": {"version": version, "author": author}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidIconsFolder extends ImageFolder {
|
||||
AndroidIconsFolder({
|
||||
String path = 'android/app/src/main/res',
|
||||
List<AndroidIcon> icons = _defaultIcons,
|
||||
}) : super(path, icons);
|
||||
|
||||
static const _defaultIcons = [
|
||||
AndroidIcon(size: 72, folderSuffix: "hdpi"),
|
||||
AndroidIcon(size: 48, folderSuffix: "mdpi"),
|
||||
AndroidIcon(size: 96, folderSuffix: "xhdpi"),
|
||||
AndroidIcon(size: 144, folderSuffix: "xxhdpi"),
|
||||
AndroidIcon(size: 192, folderSuffix: "xxxhdpi"),
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export 'generator/unsupported.dart'
|
||||
if (dart.library.html) 'generator/web.dart'
|
||||
if (dart.library.io) 'generator/io.dart';
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:archive/archive.dart';
|
||||
import 'package:image/image.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:image_resizer/src/folders.dart';
|
||||
import 'package:image_resizer/src/template.dart';
|
||||
|
||||
export 'package:image_resizer/src/folders.dart';
|
||||
export 'package:image_resizer/src/template.dart';
|
||||
|
||||
abstract class IconGeneratorImpl {
|
||||
Future<FileData> generateIcon(Image image, IconTemplate icon,
|
||||
{String path = '', bool writeToDiskIO = true}) async {
|
||||
final Image resizedIcon = createResizedImage(icon, image);
|
||||
String filename = icon.filename;
|
||||
final data = encodeNamedImage(resizedIcon, filename);
|
||||
final _path = p.joinAll([
|
||||
path,
|
||||
if (icon is AndroidIcon) ...[
|
||||
icon.folder + '-' + icon.folderSuffix,
|
||||
],
|
||||
filename
|
||||
]);
|
||||
return FileData(data, data.length, filename, _path);
|
||||
}
|
||||
|
||||
Future<List<FileData>> generateIcons(Image image, ImageFolder folder,
|
||||
{String path = '', bool writeToDiskIO = true}) async {
|
||||
final List<FileData> _images = [];
|
||||
for (var template in folder.templates) {
|
||||
final _icon = await generateIcon(
|
||||
image,
|
||||
template,
|
||||
path: p.joinAll([if (path.isNotEmpty) path, folder.path]),
|
||||
writeToDiskIO: writeToDiskIO,
|
||||
);
|
||||
_images.add(_icon);
|
||||
}
|
||||
|
||||
return _images;
|
||||
}
|
||||
|
||||
List<int> generateArchive(List<FileData> images) {
|
||||
var encoder = ZipEncoder();
|
||||
final _output = OutputStream();
|
||||
encoder.startEncode(_output);
|
||||
// final archive = Archive();
|
||||
for (var f in images) {
|
||||
final archiveFile = ArchiveFile(f.path, f.size, f.data);
|
||||
encoder.addFile(archiveFile);
|
||||
}
|
||||
encoder.endEncode();
|
||||
|
||||
return _output.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
Image createResizedImage(IconTemplate template, Image image) {
|
||||
Interpolation _interpolation;
|
||||
if (image.width >= template.size) {
|
||||
_interpolation = Interpolation.average;
|
||||
} else {
|
||||
_interpolation = Interpolation.linear;
|
||||
}
|
||||
if (template is IosIcon) {
|
||||
return copyResize(
|
||||
image,
|
||||
width: (template.adjustedSize * template.scale.toDouble()).round(),
|
||||
height: (template.adjustedSize * template.scale.toDouble()).round(),
|
||||
interpolation: _interpolation,
|
||||
);
|
||||
}
|
||||
if (template is MacOSIcon) {
|
||||
return copyResize(
|
||||
image,
|
||||
width: template.size * template.scale,
|
||||
height: template.size * template.scale,
|
||||
interpolation: _interpolation,
|
||||
);
|
||||
}
|
||||
return copyResize(
|
||||
image,
|
||||
width: template.size,
|
||||
height: template.size,
|
||||
interpolation: _interpolation,
|
||||
);
|
||||
}
|
||||
|
||||
class FileData {
|
||||
final List<int> data;
|
||||
final int size;
|
||||
final String name;
|
||||
final String path;
|
||||
FileData(this.data, this.size, this.name, this.path);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:image/image.dart';
|
||||
|
||||
import 'impl.dart';
|
||||
import 'dart:io';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
class IconGenerator extends IconGeneratorImpl {
|
||||
@override
|
||||
Future<List<FileData>> generateIcons(Image image, ImageFolder folder,
|
||||
{String path = '', bool writeToDiskIO = true}) async {
|
||||
final List<FileData> _images = [];
|
||||
final _folderPath = p.joinAll([if (path.isNotEmpty) path, folder.path]);
|
||||
for (var template in folder.templates) {
|
||||
final _icon = await generateIcon(
|
||||
image,
|
||||
template,
|
||||
path: _folderPath,
|
||||
writeToDiskIO: writeToDiskIO,
|
||||
);
|
||||
_images.add(_icon);
|
||||
}
|
||||
if (writeToDiskIO) {
|
||||
if (folder is IosIconsFolder) {
|
||||
final _file = File(p.join(_folderPath, 'Contents.json'));
|
||||
if (!_file.existsSync()) {
|
||||
await _file.create(recursive: true);
|
||||
}
|
||||
await _file.writeAsString(json.encode(folder.toJson()));
|
||||
}
|
||||
if (folder is MacOSIconsFolder) {
|
||||
final _file = File(p.join(_folderPath, 'Contents.json'));
|
||||
if (!_file.existsSync()) {
|
||||
await _file.create(recursive: true);
|
||||
}
|
||||
await _file.writeAsString(json.encode(folder.toJson()));
|
||||
}
|
||||
}
|
||||
return _images;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<FileData> generateIcon(Image image, IconTemplate icon,
|
||||
{String path = '', bool writeToDiskIO = true}) async {
|
||||
if (path == '') {
|
||||
path = Directory.current.path;
|
||||
}
|
||||
File _file = File(p.joinAll([
|
||||
path,
|
||||
icon.filename,
|
||||
]));
|
||||
if (writeToDiskIO && !_file.existsSync()) {
|
||||
await _file.createSync(recursive: true);
|
||||
}
|
||||
final Image resizedIcon = createResizedImage(icon, image);
|
||||
final filename = icon.filename;
|
||||
final data = encodeNamedImage(resizedIcon, filename);
|
||||
if (writeToDiskIO) {
|
||||
_file = await _file.writeAsBytes(data);
|
||||
print('Updated: $filename');
|
||||
}
|
||||
return FileData(
|
||||
data,
|
||||
data.length,
|
||||
filename,
|
||||
p.joinAll([
|
||||
path,
|
||||
if (icon is AndroidIcon) ...[
|
||||
icon.folder + '-' + icon.folderSuffix,
|
||||
],
|
||||
filename
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import 'impl.dart';
|
||||
|
||||
class IconGenerator extends IconGeneratorImpl {}
|
||||
@@ -0,0 +1,3 @@
|
||||
import 'impl.dart';
|
||||
|
||||
class IconGenerator extends IconGeneratorImpl {}
|
||||
@@ -0,0 +1,191 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
/// Template for Icon
|
||||
abstract class IconTemplate {
|
||||
const IconTemplate(this.size);
|
||||
final int size;
|
||||
String get filename;
|
||||
}
|
||||
|
||||
/// web/icons/Icon-512.png
|
||||
class WebIcon extends IconTemplate {
|
||||
const WebIcon({
|
||||
@required int size,
|
||||
this.prefix = 'Icon-',
|
||||
this.ext = 'png',
|
||||
}) : super(size);
|
||||
final String prefix;
|
||||
final String ext;
|
||||
|
||||
WebIcon copyWith({
|
||||
int size,
|
||||
String prefix,
|
||||
String ext,
|
||||
}) {
|
||||
return WebIcon(
|
||||
prefix: prefix ?? this.prefix,
|
||||
size: size ?? this.size,
|
||||
ext: ext ?? this.ext,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson([String folder = "icons"]) {
|
||||
return {
|
||||
"src": "$folder/$filename",
|
||||
"sizes": "$size" + "x" + "$size",
|
||||
"type": "image/$ext"
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String get filename => '$prefix$size.$ext';
|
||||
}
|
||||
|
||||
/// web/icons/Icon-512.png
|
||||
class WebFavicon extends IconTemplate {
|
||||
const WebFavicon({
|
||||
int size = 16,
|
||||
this.name = 'favicon',
|
||||
this.ext = 'png',
|
||||
}) : super(size);
|
||||
final String name;
|
||||
final String ext;
|
||||
|
||||
WebFavicon copyWith({
|
||||
int size,
|
||||
String name,
|
||||
String ext,
|
||||
}) {
|
||||
return WebFavicon(
|
||||
size: size ?? this.size,
|
||||
ext: ext ?? this.ext,
|
||||
name: name ?? this.name,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String get filename => '$name.$ext';
|
||||
}
|
||||
|
||||
/// ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
|
||||
class IosIcon extends IconTemplate {
|
||||
const IosIcon({
|
||||
@required int size,
|
||||
this.ext = 'png',
|
||||
this.prefix = 'Icon-App-',
|
||||
this.scale = 1,
|
||||
this.point5 = false,
|
||||
}) : super(size);
|
||||
final String prefix;
|
||||
final int scale;
|
||||
final String ext;
|
||||
final bool point5;
|
||||
|
||||
IosIcon copyWith({
|
||||
int size,
|
||||
String prefix,
|
||||
int scale,
|
||||
String ext,
|
||||
bool point5,
|
||||
}) {
|
||||
return IosIcon(
|
||||
size: size ?? this.size,
|
||||
prefix: prefix ?? this.prefix,
|
||||
scale: scale ?? this.scale,
|
||||
ext: ext ?? this.ext,
|
||||
point5: point5 ?? this.point5,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
"size": "${size}x${size}",
|
||||
"idiom": "ios-marketing",
|
||||
"filename": filename,
|
||||
"scale": "${scale}x"
|
||||
};
|
||||
}
|
||||
|
||||
double get adjustedSize => point5 ? (size.toDouble() + 0.5) : size.toDouble();
|
||||
|
||||
@override
|
||||
String get filename =>
|
||||
"$prefix${adjustedSize}x${adjustedSize}@${scale}x.$ext";
|
||||
}
|
||||
|
||||
/// android/app/src/main/res/mipmap-hdpi/ic_launcher.png
|
||||
class AndroidIcon extends IconTemplate {
|
||||
const AndroidIcon({
|
||||
@required int size,
|
||||
this.name = 'ic_launcher',
|
||||
this.ext = 'png',
|
||||
this.folderSuffix = 'mipmap-',
|
||||
this.folder = 'hdpi',
|
||||
}) : super(size);
|
||||
final String name;
|
||||
final String folder;
|
||||
final String folderSuffix;
|
||||
final String ext;
|
||||
|
||||
AndroidIcon copyWith({
|
||||
String name,
|
||||
String folder,
|
||||
String folderSuffix,
|
||||
String ext,
|
||||
int size,
|
||||
}) {
|
||||
return AndroidIcon(
|
||||
name: name ?? this.name,
|
||||
size: size ?? this.size,
|
||||
folder: folder ?? this.folder,
|
||||
folderSuffix: folderSuffix ?? this.folderSuffix,
|
||||
ext: ext ?? this.ext,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String get filename => "$name.$ext";
|
||||
}
|
||||
|
||||
/// macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
|
||||
class MacOSIcon extends IconTemplate {
|
||||
const MacOSIcon({
|
||||
@required int size,
|
||||
this.prefix = 'app_icon_',
|
||||
this.ext = 'png',
|
||||
this.scale = 1,
|
||||
this.name = '16',
|
||||
}) : super(size);
|
||||
final String prefix;
|
||||
final int scale;
|
||||
final String ext;
|
||||
final String name;
|
||||
|
||||
MacOSIcon copyWith({
|
||||
int size,
|
||||
String prefix,
|
||||
int scale,
|
||||
String ext,
|
||||
}) {
|
||||
return MacOSIcon(
|
||||
size: size ?? this.size,
|
||||
prefix: prefix ?? this.prefix,
|
||||
scale: scale ?? this.scale,
|
||||
ext: ext ?? this.ext,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
"size": "$size" + "x" + "$size",
|
||||
"idiom": "mac",
|
||||
"filename": "$prefix$name.$ext",
|
||||
"scale": "${scale}x"
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String get filename => "$prefix$name.$ext";
|
||||
}
|
||||
Reference in New Issue
Block a user