201 lines
5.5 KiB
TypeScript
201 lines
5.5 KiB
TypeScript
class Resizer {
|
|
static resizeAndRotateImage(
|
|
image: CanvasImageSource,
|
|
size: number,
|
|
compressFormat = "jpeg",
|
|
quality = 100,
|
|
rotation = 0,
|
|
) {
|
|
var qualityDecimal = quality / 100;
|
|
var canvas = document.createElement("canvas");
|
|
|
|
canvas.width = size;
|
|
canvas.height = size;
|
|
|
|
var ctx = canvas.getContext("2d");
|
|
if (ctx) {
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0)";
|
|
ctx.fillRect(0, 0, size, size);
|
|
|
|
if (ctx.imageSmoothingEnabled && ctx.imageSmoothingQuality) {
|
|
ctx.imageSmoothingQuality = "high";
|
|
}
|
|
|
|
if (rotation) {
|
|
ctx.rotate((rotation * Math.PI) / 180);
|
|
if (rotation === 90) {
|
|
ctx.translate(0, -canvas.width);
|
|
} else if (rotation === 180) {
|
|
ctx.translate(-canvas.width, -canvas.height);
|
|
} else if (rotation === 270) {
|
|
ctx.translate(-canvas.height, 0);
|
|
} else if (rotation === 0 || rotation === 360) {
|
|
ctx.translate(0, 0);
|
|
}
|
|
}
|
|
//Вставка картинки. Определяем k в который уменьшилась большая сторона и уменьшаем в него другую сторону
|
|
let width = Number(image.width);
|
|
let height = Number(image.height);
|
|
let Xoffset = 0;
|
|
let Yoffset = 0;
|
|
const larger = Math.max(width, height);
|
|
const k = Number((larger / size).toFixed(2));
|
|
if (height > width) {
|
|
height = size;
|
|
width = Math.round(width / k);
|
|
Xoffset = Math.round((size - width) / 2);
|
|
} else {
|
|
height = Math.round(width / k);
|
|
width = size;
|
|
Yoffset = Math.round((size - height) / 2);
|
|
}
|
|
|
|
ctx.drawImage(image, Xoffset, Yoffset, width, height);
|
|
|
|
return canvas.toDataURL(`image/${compressFormat}`, qualityDecimal);
|
|
} else {
|
|
throw new Error();
|
|
}
|
|
}
|
|
|
|
static b64toByteArrays(b64Data: any, contentType: string) {
|
|
contentType = contentType || "image/jpeg";
|
|
var sliceSize = 512;
|
|
|
|
var byteCharacters = atob(
|
|
b64Data
|
|
.toString()
|
|
.replace(/^data:image\/(png|jpeg|jpg|webp);base64,/, ""),
|
|
);
|
|
var byteArrays = [];
|
|
|
|
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
|
var slice = byteCharacters.slice(offset, offset + sliceSize);
|
|
|
|
var byteNumbers = new Array(slice.length);
|
|
for (var i = 0; i < slice.length; i++) {
|
|
byteNumbers[i] = slice.charCodeAt(i);
|
|
}
|
|
|
|
var byteArray = new Uint8Array(byteNumbers);
|
|
|
|
byteArrays.push(byteArray);
|
|
}
|
|
return byteArrays;
|
|
}
|
|
|
|
static b64toBlob(b64Data: any, contentType: string) {
|
|
const byteArrays = this.b64toByteArrays(b64Data, contentType);
|
|
var blob = new Blob(byteArrays, { type: contentType });
|
|
return blob;
|
|
}
|
|
|
|
static b64toFile(b64Data: string, fileName: string, contentType: string) {
|
|
const byteArrays = this.b64toByteArrays(b64Data, contentType);
|
|
const file = new File(byteArrays, fileName, { type: contentType });
|
|
return file;
|
|
}
|
|
|
|
static createResizedImage(
|
|
file: File,
|
|
size: number,
|
|
compressFormat: string,
|
|
quality: number,
|
|
rotation: number,
|
|
responseUriFunc: any,
|
|
outputType = "base64",
|
|
) {
|
|
const reader = new FileReader();
|
|
if (file) {
|
|
if (file.type && !file.type.includes("image")) {
|
|
throw Error("File Is NOT Image!");
|
|
} else {
|
|
reader.readAsDataURL(file);
|
|
reader.onload = () => {
|
|
var image = new Image();
|
|
//@ts-ignore
|
|
image.src = reader.result;
|
|
image.onload = function () {
|
|
var resizedDataUrl = Resizer.resizeAndRotateImage(
|
|
image,
|
|
size,
|
|
compressFormat,
|
|
quality,
|
|
rotation,
|
|
);
|
|
const contentType = `image/${compressFormat}`;
|
|
switch (outputType) {
|
|
case "blob":
|
|
const blob = Resizer.b64toBlob(resizedDataUrl, contentType);
|
|
responseUriFunc(blob);
|
|
break;
|
|
case "base64":
|
|
responseUriFunc(resizedDataUrl);
|
|
break;
|
|
case "file":
|
|
let fileName = file.name;
|
|
let fileNameWithoutFormat = fileName
|
|
.toString()
|
|
.replace(/(png|jpeg|jpg|webp)$/i, "");
|
|
let newFileName = fileNameWithoutFormat.concat(
|
|
compressFormat.toString(),
|
|
);
|
|
const newFile = Resizer.b64toFile(
|
|
resizedDataUrl,
|
|
newFileName,
|
|
contentType,
|
|
);
|
|
responseUriFunc(newFile);
|
|
break;
|
|
default:
|
|
responseUriFunc(resizedDataUrl);
|
|
}
|
|
};
|
|
};
|
|
reader.onerror = (error: any) => {
|
|
throw Error(error);
|
|
};
|
|
}
|
|
} else {
|
|
throw Error("File Not Found!");
|
|
}
|
|
}
|
|
}
|
|
export default {
|
|
imageFileResizer: (
|
|
file: File,
|
|
size: number,
|
|
compressFormat: string,
|
|
quality: number,
|
|
rotation: number,
|
|
responseUriFunc: any,
|
|
outputType: string,
|
|
) => {
|
|
return Resizer.createResizedImage(
|
|
file,
|
|
size,
|
|
compressFormat,
|
|
quality,
|
|
rotation,
|
|
responseUriFunc,
|
|
outputType,
|
|
);
|
|
},
|
|
};
|
|
|
|
export function resizeFavIcon(blob: Blob) {
|
|
return new Promise<Blob>((resolve) => {
|
|
Resizer.createResizedImage(
|
|
new File([blob], "image"),
|
|
48,
|
|
"PNG",
|
|
100,
|
|
0,
|
|
async (file: Blob) => {
|
|
resolve(file);
|
|
},
|
|
"blob",
|
|
);
|
|
});
|
|
}
|