@@ -15,8 +15,8 @@ const CacheAsset = require("@11ty/eleventy-cache-assets");
1515const globalOptions = {
1616 src : null ,
1717 widths : [ null ] ,
18- heights : [ null ] ,
19- formats : [ "webp" , "jpeg" ] , //"png"
18+ crops : null ,
19+ formats : [ "webp" , "jpeg" ] , // "png"
2020 concurrency : 10 ,
2121 urlPath : "/img/" ,
2222 outputDir : "img/" ,
@@ -25,7 +25,6 @@ const globalOptions = {
2525} ;
2626
2727const MIME_TYPES = {
28- "jpg" : "image/jpeg" ,
2928 "jpeg" : "image/jpeg" ,
3029 "webp" : "image/webp" ,
3130 "png" : "image/png"
@@ -109,62 +108,113 @@ async function resizeImage(src, options = {}) {
109108 let formats = getFormatsArray ( options . formats ) ;
110109 for ( let format of formats ) {
111110 let hasAtLeastOneValidMaxWidth = false ;
112- for ( let widthKey in options . widths ) {
113- let width = options . widths [ widthKey ] ;
114- let hasWidth = ! ! width ;
115- // heights length should be same length with widths
116- if ( options . heights && options . heights [ 0 ] != null && options . heights . length != options . widths . length ) {
117- throw new Error ( "if `heights` is set. it should has same with length of width." ) ;
118- }
119- let height = options . heights [ widthKey ] ;
120- // Set format
121- let imageFormat = sharpImage . clone ( ) ;
122- if ( metadata . format !== format ) {
123- imageFormat . toFormat ( format ) ;
111+ if ( options . crops ) {
112+ let crops = _normalizeCrop ( options . crops ) ;
113+ if ( crops . length == 0 ) {
114+ throw new Error ( `Expected options.crops should be ["1600x900", "160x90"] or ${ JSON . stringify ( [ { width : 1600 , height : 900 } , { width : 160 , height : 90 } ] , null , 2 ) } ` ) ;
124115 }
116+ for ( let [ width , height ] of crops ) {
117+ let hasWidth = ! ! width ;
118+ // Set format
119+ let imageFormat = sharpImage . clone ( ) ;
120+ if ( metadata . format !== format ) {
121+ imageFormat . toFormat ( format ) ;
122+ }
123+
124+ if ( width > metadata . width || height > metadata . height ) {
125+ continue ;
126+ }
127+
128+ imageFormat . resize ( {
129+ width : width ,
130+ height : height ,
131+ withoutEnlargement : true
132+ } ) ;
133+
134+ let outputFilename = getFilename ( src , width + 'x' + height , format ) ;
135+ let outputPath = path . join ( options . outputDir , outputFilename ) ;
136+ outputFilePromises . push ( imageFormat . toFile ( outputPath ) . then ( data => {
137+ let stats = getStats ( src , format , options . urlPath , data . width , data . height , hasWidth ) ;
138+ stats . outputPath = outputPath ;
139+ stats . size = data . size ;
140+
141+ return stats ;
142+ } ) ) ;
125143
126- // skip this width because it’s larger than the original and we already
127- // have at least one output image size that works
128- if ( hasAtLeastOneValidMaxWidth && ( ! width || width > metadata . width ) ) {
129- continue ;
144+ debug ( "Writing %o" , outputPath ) ;
130145 }
146+ } else {
147+ for ( let width of options . widths ) {
148+ let hasWidth = ! ! width ;
149+ // Set format
150+ let imageFormat = sharpImage . clone ( ) ;
151+ if ( metadata . format !== format ) {
152+ imageFormat . toFormat ( format ) ;
153+ }
154+
155+ // skip this width because it’s larger than the original and we already
156+ // have at least one output image size that works
157+ if ( hasAtLeastOneValidMaxWidth && ( ! width || width > metadata . width ) ) {
158+ continue ;
159+ }
131160
132- // Resize the image
133- if ( ! width ) {
134- hasAtLeastOneValidMaxWidth = true ;
135- } else {
136- if ( width >= metadata . width ) {
137- // don’t reassign width if it’s falsy
138- width = null ;
139- hasWidth = false ;
161+ // Resize the image
162+ if ( ! width ) {
140163 hasAtLeastOneValidMaxWidth = true ;
141164 } else {
142- imageFormat . resize ( {
143- width : width ,
144- height : height ,
145- withoutEnlargement : true
146- } ) ;
165+ if ( width >= metadata . width ) {
166+ // don’t reassign width if it’s falsy
167+ width = null ;
168+ hasWidth = false ;
169+ hasAtLeastOneValidMaxWidth = true ;
170+ } else {
171+ imageFormat . resize ( {
172+ width : width ,
173+ withoutEnlargement : true
174+ } ) ;
175+ }
147176 }
148- }
149177
150178
151- let outputFilename = getFilename ( src , width , format ) ;
152- let outputPath = path . join ( options . outputDir , outputFilename ) ;
153- outputFilePromises . push ( imageFormat . toFile ( outputPath ) . then ( data => {
154- let stats = getStats ( src , format , options . urlPath , data . width , data . height , hasWidth ) ;
155- stats . outputPath = outputPath ;
156- stats . size = data . size ;
179+ let outputFilename = getFilename ( src , width , format ) ;
180+ let outputPath = path . join ( options . outputDir , outputFilename ) ;
181+ outputFilePromises . push ( imageFormat . toFile ( outputPath ) . then ( data => {
182+ let stats = getStats ( src , format , options . urlPath , data . width , data . height , hasWidth ) ;
183+ stats . outputPath = outputPath ;
184+ stats . size = data . size ;
157185
158- return stats ;
159- } ) ) ;
186+ return stats ;
187+ } ) ) ;
160188
161- debug ( "Writing %o" , outputPath ) ;
189+ debug ( "Writing %o" , outputPath ) ;
190+ }
162191 }
163192 }
164193
165194 return Promise . all ( outputFilePromises ) . then ( files => transformRawFiles ( files ) ) ;
166195}
167196
197+ function _normalizeCrop ( options ) {
198+ if ( options == null ) return null ;
199+ let filteredOptions = options . map ( function ( config ) {
200+ if ( typeof ( config ) == 'string' ) {
201+ let val = config . split ( 'x' )
202+ if ( config . split ( 'x' ) . length != 2 ) {
203+ return false ;
204+ }
205+ return [ parseInt ( val [ 0 ] ) , parseInt ( val [ 1 ] ) ]
206+ } else if ( typeof ( config ) == 'object' ) {
207+ let width = config . hasOwnProperty ( 'width' ) ;
208+ let height = config . hasOwnProperty ( 'height' ) ;
209+ if ( width && height ) {
210+ return [ parseInt ( config . width ) , parseInt ( config . height ) ] ;
211+ }
212+ return false ;
213+ }
214+ } )
215+ return filteredOptions . filter ( Boolean ) ;
216+ }
217+
168218function isFullUrl ( url ) {
169219 try {
170220 new URL ( url ) ;
@@ -240,34 +290,39 @@ function _statsSync(src, originalWidth, originalHeight, opts) {
240290
241291 for ( let format of formats ) {
242292 let hasAtLeastOneValidMaxWidth = false ;
243- for ( let widthKey in options . widths ) {
244- let width = options . widths [ widthKey ] ;
245- let hasWidth = ! ! width ;
246- // heights length should be same length with widths
247- if ( options . heights && options . heights [ 0 ] != null && options . heights . length != options . widths . length ) {
248- throw new Error ( "if `heights` is set. it should has same with length of width." ) ;
249- }
250- let height ;
251-
252- if ( hasAtLeastOneValidMaxWidth && ( ! width || width > originalWidth ) ) {
253- continue ;
293+ if ( options . crops ) {
294+ let crops = _normalizeCrop ( options . crops ) ;
295+ for ( let [ width , height ] of crops ) {
296+ let hasWidth = ! ! width
297+ if ( width > originalWidth || height > originalWidth ) {
298+ continue ;
299+ }
300+ results . push ( getStats ( src , format , options . urlPath , width , height , hasWidth ) ) ;
254301 }
255-
256- if ( ! width ) {
257- width = originalWidth ;
258- height = originalHeight ;
259- hasAtLeastOneValidMaxWidth = true ;
260- } else {
261- if ( width >= originalWidth ) {
302+ } else {
303+ for ( let width of options . widths ) {
304+ let hasWidth = ! ! width ;
305+ let height ;
306+
307+ if ( hasAtLeastOneValidMaxWidth && ( ! width || width > originalWidth ) ) {
308+ continue ;
309+ }
310+
311+ if ( ! width ) {
262312 width = originalWidth ;
263- hasWidth = false ;
313+ height = originalHeight ;
264314 hasAtLeastOneValidMaxWidth = true ;
315+ } else {
316+ if ( width >= originalWidth ) {
317+ width = originalWidth ;
318+ hasWidth = false ;
319+ hasAtLeastOneValidMaxWidth = true ;
320+ }
321+ height = Math . floor ( width * originalHeight / originalWidth ) ;
265322 }
266- height = options . heights [ widthKey ] || Math . floor ( width * originalHeight / originalWidth ) ;
323+
324+ results . push ( getStats ( src , format , options . urlPath , width , height , hasWidth ) ) ;
267325 }
268-
269-
270- results . push ( getStats ( src , format , options . urlPath , width , height , hasWidth ) ) ;
271326 }
272327 }
273328
@@ -284,4 +339,4 @@ function statsByDimensionsSync(src, width, height, opts) {
284339}
285340
286341module . exports . statsSync = statsSync ;
287- module . exports . statsByDimensionsSync = statsByDimensionsSync ;
342+ module . exports . statsByDimensionsSync = statsByDimensionsSync ;
0 commit comments