2020-07-29 13:42:51 +00:00
import * as sharp from "sharp" ;
import * as tinify from "tinify" ;
import * as image_size from "image-size" ;
import {
writeFileSync ,
getFileSizeInKilobyte
} from "./filesystem" ;
import * as chalk from 'chalk' ;
2020-08-19 20:59:05 +00:00
import * as config from "../config" ;
2020-07-29 13:42:51 +00:00
2020-08-19 20:59:05 +00:00
export const minLogoWidth = config . imageMinLogoWidth ;
export const minLogoHeight = config . imageMinLogoHeight ;
export const maxLogoWidth = config . imageMaxLogoWidth ;
export const maxLogoHeight = config . imageMaxLogoHeight ;
export const maxLogoSizeInKilobyte = config . imageMaxLogoSizeKb ;
2020-07-29 13:42:51 +00:00
export function isDimensionTooLarge ( width : number , height : number ) : boolean {
return ( width > maxLogoWidth ) || ( height > maxLogoHeight ) ;
}
2020-08-06 19:17:38 +00:00
export function isDimensionOK ( width : number , height : number ) : boolean {
return ( width <= maxLogoWidth ) && ( height <= maxLogoHeight ) &&
( width >= minLogoWidth ) && ( height >= minLogoHeight ) ;
}
2020-07-29 13:42:51 +00:00
export function calculateTargetSize ( srcWidth : number , srcHeight : number , targetWidth : number , targetHeight : number ) : { width : number , height : number } {
if ( srcWidth == 0 || srcHeight == 0 ) {
return { width : targetWidth , height : targetHeight } ;
}
const ratio = Math . min ( targetWidth / srcWidth , targetHeight / srcHeight ) ;
return {
width : Math.round ( srcWidth * ratio ) ,
height : Math.round ( srcHeight * ratio )
} ;
}
2020-08-06 19:17:38 +00:00
// check logo dimensions (pixel) and size (kilobytes)
export async function isLogoOK ( path : string ) : Promise < [ boolean , string ] > {
2020-09-18 14:39:31 +00:00
let [ isOK , msg ] = await isLogoDimensionOK ( path ) ;
2020-08-06 19:17:38 +00:00
if ( ! isOK ) {
return [ false , msg ] ;
}
[ isOK , msg ] = await isLogoSizeOK ( path ) ;
if ( ! isOK ) {
return [ false , msg ] ;
}
return [ true , "" ] ;
}
2020-07-29 13:42:51 +00:00
const getImageDimensions = ( path : string ) = > image_size . imageSize ( path ) ;
2020-08-06 19:17:38 +00:00
async function isLogoDimensionOK ( path : string ) : Promise < [ boolean , string ] > {
const { width , height } = getImageDimensions ( path )
if ( isDimensionOK ( width , height ) ) {
return [ true , "" ] ;
}
return [ false , ` Image at path ${ path } must have dimensions: min: ${ minLogoWidth } x ${ minLogoHeight } and max: ${ maxLogoWidth } x ${ maxLogoHeight } instead ${ width } x ${ height } ` ] ;
}
2020-07-29 13:42:51 +00:00
async function compressTinyPNG ( path : string ) {
console . log ( ` Compressing image via tinypng at path ${ path } ` ) ;
const source = await tinify . fromFile ( path ) ;
await source . toFile ( path ) ;
}
2020-08-06 19:17:38 +00:00
async function isLogoSizeOK ( path : string ) : Promise < [ boolean , string ] > {
const sizeKilobyte = getFileSizeInKilobyte ( path ) ;
if ( sizeKilobyte > maxLogoSizeInKilobyte ) {
return [ false , ` Logo ${ path } is too large, ${ sizeKilobyte } kB instead of ${ maxLogoSizeInKilobyte } ` ] ;
}
return [ true , '' ] ;
}
2020-08-07 14:39:46 +00:00
// return if image if too large, and if image has been updated
export async function checkResizeIfTooLarge ( path : string , checkOnly : boolean ) : Promise < [ boolean , boolean ] > {
let tooLarge = false ;
2020-09-18 14:39:31 +00:00
let updated = false ;
2020-08-07 14:39:46 +00:00
2020-07-29 13:42:51 +00:00
const { width : srcWidth , height : srcHeight } = getImageDimensions ( path ) ;
2020-08-07 14:39:46 +00:00
if ( ! isDimensionOK ( srcWidth , srcHeight ) ) {
tooLarge = true ; // may be too small as well
2021-02-26 11:39:39 +00:00
console . log ( ` Wrong image dimensions, ${ srcWidth } x ${ srcHeight } , ${ path } ` ) ;
2020-08-07 14:39:46 +00:00
}
2020-07-29 13:42:51 +00:00
if ( isDimensionTooLarge ( srcWidth , srcHeight ) ) {
2020-08-07 14:39:46 +00:00
tooLarge = true ;
2021-02-26 11:39:39 +00:00
console . log ( ` Image too large, ${ srcWidth } x ${ srcHeight } , ${ path } ` ) ;
2020-08-07 14:39:46 +00:00
if ( ! checkOnly ) {
// resize
const { width , height } = calculateTargetSize ( srcWidth , srcHeight , maxLogoWidth , maxLogoHeight ) ;
console . log ( ` Resizing image at ${ path } from ${ srcWidth } x ${ srcHeight } => ${ width } x ${ height } ` )
await sharp ( path ) . resize ( width , height ) . toBuffer ( )
. then ( data = > {
writeFileSync ( path , data ) ;
updated = true ;
} )
. catch ( e = > {
console . log ( chalk . red ( e . message ) ) ;
} ) ;
}
2020-07-29 13:42:51 +00:00
}
// If file size > max limit, compress with tinypng
const sizeKilobyte = getFileSizeInKilobyte ( path ) ;
if ( sizeKilobyte > maxLogoSizeInKilobyte ) {
2020-08-07 14:39:46 +00:00
tooLarge = true ;
2021-02-26 11:39:39 +00:00
console . log ( ` Image too big, ${ sizeKilobyte } kb, ${ path } ` ) ;
2020-08-07 14:39:46 +00:00
if ( ! checkOnly ) {
console . log ( ` Resizing image at path ${ path } from ${ sizeKilobyte } kB ` ) ;
await compressTinyPNG ( path )
. then ( ( ) = > {
updated = true ;
console . log ( ` Resized image at path ${ path } from ${ sizeKilobyte } kB => ${ getFileSizeInKilobyte ( path ) } kB ` ) ;
} )
. catch ( e = > {
console . log ( chalk . red ( e . message ) ) ;
} ) ;
}
2020-07-29 13:42:51 +00:00
}
2020-08-07 14:39:46 +00:00
return [ tooLarge , updated ] ;
2020-07-29 13:42:51 +00:00
}