+21
| MIT License | ||
| Copyright (c) 2022-present ZG | ||
| 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. |
+113
-35
| /*! | ||
| * CuteImage v1.0.0 | ||
| * CuteImage v1.0.1 | ||
| * Copyright (C) 2022-present, ZG | ||
@@ -14,2 +14,3 @@ * Released under the MIT license. | ||
| // 工具 | ||
| const util = { | ||
@@ -20,2 +21,3 @@ type: obj => Object.prototype.toString.call( obj ).slice( 8, -1 ).toLowerCase(), | ||
| isDataUrl: obj => typeof obj === "string" && /^data:image\/(jpg|jpeg|png|gif|bmp|webp|tiff|tif);base64,/i.test( obj ), | ||
| randomString: ( prefix = "" ) => prefix + Math.random().toString( 36 ).slice( 2 ), | ||
| getHexadecimal: ( file, len = 50 ) => { | ||
@@ -26,5 +28,5 @@ return new Promise(( resolve, reject ) => { | ||
| } | ||
| function hex ( butter, start, end ) { | ||
| function hex ( buffer, start, end ) { | ||
| const hexArray = []; | ||
| const obj = [ ...new Uint8Array( butter.slice( start, end ) ) ]; | ||
| const obj = [ ...new Uint8Array( buffer.slice( start, end ) ) ]; | ||
| for ( let i = 0, j = obj.length; i < j; i++ ) { | ||
@@ -38,12 +40,11 @@ hexArray.push( obj[ i ].toString( 16 ).padStart( 2, "0" ) ); | ||
| reader.onload = function () { | ||
| const butter = this.result; | ||
| resolve( hex( butter, 0, len ) ); | ||
| resolve( hex( this.result, 0, len ) ); | ||
| } | ||
| reader.onerror = event => reject( event ) | ||
| reader.onerror = () => reject() | ||
| reader.readAsArrayBuffer( file ); | ||
| }) | ||
| }, | ||
| randomString: ( prefix = "" ) => prefix + Math.random().toString( 36 ).slice( 2 ) | ||
| } | ||
| }; | ||
| // 方法 | ||
| const func = { | ||
@@ -143,3 +144,3 @@ isImage: file => { | ||
| } | ||
| return type === "file" ? new File([ u8arr ], filename, { | ||
| return type === "file" ? new File([ u8arr ], `${ filename }.${ mime.slice( 6 ) }`, { | ||
| type: mime | ||
@@ -150,14 +151,50 @@ }) : new Blob([ u8arr ], { | ||
| } | ||
| }, | ||
| calcSize: size => { | ||
| const sizeMap = { | ||
| kb: size / Math.pow( 1024, 1 ), | ||
| mb: size / Math.pow( 1024, 2 ), | ||
| gb: size / Math.pow( 1024, 3 ), | ||
| tb: size / Math.pow( 1024, 4 ) | ||
| }; | ||
| const calc = [ "", "" ]; | ||
| if ( sizeMap.kb < 1 ) { | ||
| calc[ 0 ] = size; | ||
| calc[ 1 ] = "B"; | ||
| } else if ( sizeMap.mb < 1 ) { | ||
| calc[ 0 ] = sizeMap.kb.toFixed( 2 ); | ||
| calc[ 1 ] = "KB"; | ||
| } else if ( sizeMap.gb < 1 ) { | ||
| calc[ 0 ] = sizeMap.mb.toFixed( 2 ); | ||
| calc[ 1 ] = "MB"; | ||
| } else if ( sizeMap.tb < 1 ) { | ||
| calc[ 0 ] = sizeMap.gb.toFixed( 2 ); | ||
| calc[ 1 ] = "GB"; | ||
| } else { | ||
| calc[ 0 ] = sizeMap.tb.toFixed( 2 ); | ||
| calc[ 1 ] = "TB"; | ||
| } | ||
| calc[ 0 ] = calc[ 0 ].endsWith( "00" ) ? calc[ 0 ].replace( ".00", "" ) : calc[ 0 ]; | ||
| calc[ 0 ] = calc[ 0 ].endsWith( "0" ) ? calc[ 0 ].slice( 0, calc[ 0 ].length - 1 ) : calc[ 0 ]; | ||
| return calc; | ||
| } | ||
| }; | ||
| // CuteImage 类 | ||
| class CuteImageClass { | ||
| constructor ( file ) { | ||
| this.file = util.isFile( file ) ? file : null; | ||
| this.file = file; | ||
| } | ||
| size () { | ||
| size ( bool ) { | ||
| return new Promise(resolve => { | ||
| func.isImage( this.file ) | ||
| .then( () => resolve( this.file.size ) ) | ||
| .catch( () => resolve( 0 ) ) | ||
| .then(() => { | ||
| const size = this.file.size; | ||
| if ( !bool ) { | ||
| return resolve( size ); | ||
| } | ||
| const calcSize = func.calcSize( size ); | ||
| resolve( [ size, calcSize[ 0 ] + calcSize[ 1 ] ] ); | ||
| }) | ||
| .catch( () => resolve( bool ? 0 : [] ) ) | ||
| }) | ||
@@ -252,2 +289,32 @@ } | ||
| } | ||
| toFile ( filename ) { | ||
| return new Promise(resolve => { | ||
| if ( util.isFile( this.file ) ) { | ||
| func.isImage( this.file ).then(() => { | ||
| resolve( this.file ); | ||
| }).catch( () => resolve( null ) ) | ||
| } else if ( util.isBlob( this.file ) ) { | ||
| const type = this.file.type; | ||
| if ( !type.startsWith( "image/" ) ) { | ||
| return resolve( null ); | ||
| } | ||
| const format = type.slice( 6 ).match( /(jpg|jpeg|png|gif|bmp|webp|tiff|tif)/i ) | ||
| if ( !format ) { | ||
| return resolve( null ); | ||
| } | ||
| const blobToFile = func.toFile( this.file, `${ filename ?? util.randomString() }.${ format[ 1 ] }` ); | ||
| func.isImage( blobToFile ).then(() => { | ||
| resolve( blobToFile ); | ||
| }).catch( () => resolve( null ) ) | ||
| } else if ( util.isDataUrl( this.file ) ) { | ||
| const dataUrlToFile = func.dataUrlToBlobOrFile( this.file, "file", filename ); | ||
| func.isImage( dataUrlToFile ).then(() => { | ||
| resolve( dataUrlToFile ); | ||
| }).catch( () => resolve( null ) ) | ||
| } else { | ||
| resolve( null ); | ||
| } | ||
| }) | ||
| } | ||
| dimension () { | ||
@@ -257,24 +324,29 @@ return new Promise(resolve => { | ||
| if ( !type || type.startsWith( "tif" ) ) { | ||
| resolve( [] ); | ||
| } else { | ||
| const reader = new FileReader(); | ||
| reader.onload = event => { | ||
| const blob = new Blob( [ event.target.result ], { type: this.file.type } ); | ||
| const blobUrl = func.toUrl( blob ); | ||
| let img = new Image(); | ||
| img.src = blobUrl; | ||
| let timer = null; | ||
| function checkWidthOrHeight () { | ||
| if ( img.width && img.height ) { | ||
| clearInterval( timer ); | ||
| resolve( [ img.width, img.height, img.width / img.height ] ); | ||
| img = null; | ||
| timer = null; | ||
| } | ||
| return resolve( [] ); | ||
| } | ||
| const reader = new FileReader(); | ||
| reader.onload = event => { | ||
| const blob = new Blob([ event.target.result ], { | ||
| type: this.file.type | ||
| }); | ||
| const blobUrl = func.toUrl( blob ); | ||
| let img = new Image(); | ||
| img.src = blobUrl; | ||
| let timer = null; | ||
| function checkWidthOrHeight () { | ||
| if ( img.width && img.height ) { | ||
| resolve([ | ||
| img.width, | ||
| img.height, | ||
| img.width / img.height | ||
| ]); | ||
| clearInterval( timer ); | ||
| timer = null; | ||
| img = null; | ||
| } | ||
| timer = setInterval( checkWidthOrHeight, 10 ); | ||
| } | ||
| reader.onerror = () => resolve( [] ) | ||
| reader.readAsArrayBuffer( this.file ); | ||
| timer = setInterval( checkWidthOrHeight, 10 ); | ||
| } | ||
| reader.onerror = () => resolve( [] ) | ||
| reader.readAsArrayBuffer( this.file ); | ||
| }) | ||
@@ -292,3 +364,3 @@ }) | ||
| a.href = func.toUrl( blob ); | ||
| a.download = filename || `${ util.randomString() }.${ type }`; | ||
| a.download = `${ filename ?? util.randomString() }.${ type }`; | ||
| a.target = "_blank"; | ||
@@ -307,3 +379,3 @@ document.body.appendChild( a ); | ||
| dimension: [ 1920 ], | ||
| fastMode: true | ||
| fastMode: false | ||
| }; | ||
@@ -320,2 +392,4 @@ if ( util.type( options ) === "object" ) { | ||
| return new Promise(resolve => { | ||
| // 检测图片 | ||
| const isImage = () => new Promise(( done, fail ) => { | ||
@@ -331,2 +405,3 @@ if ( fastMode ) { | ||
| // 解析 dimension | ||
| const getDimension = () => new Promise(done => { | ||
@@ -348,2 +423,3 @@ if ( Array.isArray( dimension ) ) { | ||
| // 压缩函数 | ||
| const compressFunc = async () => { | ||
@@ -372,2 +448,4 @@ const imageUrl = await this.toURL( this.file ); | ||
| const file = func.toFile( dataUrl, fileName ); | ||
| const calcSize = func.calcSize( file.size ); | ||
| file.calcSize = calcSize[ 0 ] + calcSize[ 1 ]; | ||
| const result = { | ||
@@ -395,2 +473,2 @@ dataUrl: dataUrl, | ||
| }); | ||
| }); |
+2
-2
| { | ||
| "name": "cuteimage", | ||
| "version": "1.0.0", | ||
| "version": "1.0.1", | ||
| "author": "ZG", | ||
| "description": "使用原生 JavaScript 开发的轻量级前端图片工具助手", | ||
| "description": "完全使用原生 JavaScript 开发的轻量级前端图片工具助手", | ||
| "homepage": "https://gitee.com/dreamer365/cute-image", | ||
@@ -7,0 +7,0 @@ "keywords": [ |
+39
-16
| <br> | ||
| <h1 align="center">CuteImage</h1> | ||
| <p align="center">使用原生 JavaScript 开发的轻量级前端图片工具助手</p> | ||
| <p align="center">完全使用原生 JavaScript 开发的轻量级前端图片工具助手</p> | ||
| <p align="center"> | ||
| <img src="https://img.shields.io/badge/version-v1.0.0-blue.svg"> | ||
| <img src="https://img.shields.io/badge/license-MIT-green.svg"> | ||
| <img src="https://img.shields.io/badge/language-JavaScript-orange.svg"> | ||
| <img src="https://img.shields.io/badge/Version-v1.0.1-blue.svg"> | ||
| <img src="https://img.shields.io/badge/License-MIT-green.svg"> | ||
| <img src="https://img.shields.io/badge/Language-JavaScript-orange.svg"> | ||
| </p> | ||
| <p align="center"> | ||
| <a href="http://dreamer365.gitee.io/cuteimage/check" target="_blank">检测示例</a> | | ||
| <a href="http://dreamer365.gitee.io/cuteimage/compress" target="_blank">压缩示例</a> | | ||
| <a href="http://dreamer365.gitee.io/cuteimage/transform" target="_blank">转换示例</a> | ||
| <a href="http://dreamer365.gitee.io/cute-image/check" target="_blank">检测示例</a> ◆ | ||
| <a href="http://dreamer365.gitee.io/cute-image/compress" target="_blank">压缩示例</a> ◆ | ||
| <a href="http://dreamer365.gitee.io/cute-image/transform" target="_blank">转换示例</a> | ||
| </p> | ||
@@ -19,4 +19,4 @@ | ||
| ## 工具特点 | ||
| - 使用原生 JavaScript 开发,无任何第三方依赖,可自由嵌入到任何前端程序中; | ||
| - 提供了 16 个常用的工具方法,满足常规的开发需要; | ||
| - 完全使用原生 JavaScript 开发,无任何第三方依赖,可自由随意的嵌入到任何前端程序中; | ||
| - 提供了 17 个常用的图片工具方法,满足常规的开发需要; | ||
| - 所有方法均以异步形式构建,不阻碍其它程序的执行,保证运行效率。 | ||
@@ -66,2 +66,3 @@ | ||
| - [toURL](#toURL) | ||
| - [toFile](#toFile) | ||
| - [dimension](#dimension) | ||
@@ -192,4 +193,8 @@ - [download](#download) | ||
| - **功能**:获取传入的图片(文件流)的体积(字节),返回 `Promise`。 <br> | ||
| - **说明**:此方法内部会先调用 `isImage` 方法,如果检测出不是图片则直接返回 `0`,否则会正常返回 `size` 的获取结果。 | ||
| - **说明**:此方法内部会先调用 `isImage` 方法,如果检测出不是图片则直接返回 `0` 或空数组(在传入 `true` 参数的情况下),否则会正常返回 `size` 的获取结果。 | ||
| - **参数**:此方法可根据需要传入一个 `true` 做为参数,此时返回结果将变为数组形式,包含两个值: | ||
| - 文件体积的字节数 | ||
| - 格式化后的文件体积(如:159.35KB、52MB、1.8GB 等形式) | ||
| ```html | ||
@@ -200,4 +205,6 @@ <input id="file" type="file" accept="image/*" /> | ||
| document.getElementById( "file" ).onchange = async function () { | ||
| const size = await CuteImage( this.files[ 0 ] ).size(); | ||
| console.log( `体积:${ size }` ); | ||
| const size1 = await CuteImage( this.files[ 0 ] ).size(); | ||
| const size2 = await CuteImage( this.files[ 0 ] ).size( true ); | ||
| console.log( `体积:${ size1 }` ); | ||
| console.log( `体积:${ size2 }` ); | ||
| } | ||
@@ -289,6 +296,24 @@ </script> | ||
| <h3 id="toFile">toFile</h3> | ||
| - **功能**:将传入的图片( `File` 或 `Blob` 或 `DataUrl`)转换为 `File` 文件流形式 ,返回 `Promise`。 <br> | ||
| - **说明**:此方法会先判断传入的参数是否符合类型要求,然后判断是否为 `isImage` 方法中所列出的所支持的图片格式,如果不符合上述两点,则直接返回 `null`,否则会正常返回 `toFile` 的转换结果。<br> | ||
| - **注意**: | ||
| - 此方法可传入一个参数,用来设置转换后的图片名称,如果忽略此参数,将会自动以一个随机字符串命名。另外,如果传入的参数本身就是符合要求的图片文件流,则直接取原始文件流中的 `name`,即此参数在这种情况下无效。 | ||
| ```html | ||
| <input id="file" type="file" accept="image/*" /> | ||
| <script> | ||
| document.getElementById( "file" ).onchange = async function () { | ||
| const file = await CuteImage( this.files[ 0 ] ).toFile( "自定义的图片名称" ); | ||
| console.log( file ); | ||
| } | ||
| </script> | ||
| ``` | ||
| <h3 id="dimension">dimension</h3> | ||
| - **功能**:获取传入的图片(文件流)的宽高尺寸,返回 `Promise`。 <br> | ||
| - **说明**:此方法内部会先调用 `isImage` 方法,如果检测出不是图片则直接返回空数组,否则会正常返回 `dimension` 的获取结果。 | ||
| - **说明**:此方法内部会先调用 `isImage` 方法,如果检测出不是图片则直接返回空数组,否则会正常返回 `dimension` 的获取结果,数组形式,包含三个值:宽度、高度、宽高比。 | ||
| - **注意**:不支持获取 `tiff` 和 `tif` 图片的宽高尺寸,这两种格式将直接返回空数组。 | ||
@@ -302,4 +327,2 @@ | ||
| const dimension = await CuteImage( this.files[ 0 ] ).dimension(); | ||
| // 正确情况下会返回:[ 宽度, 高度, 宽高比 ] | ||
| console.log( dimension ); | ||
@@ -345,3 +368,3 @@ } | ||
| - `dataUrl`:压缩后的图片 `dataUrl` 编码 | ||
| - `file`:压缩后的图片文件流 | ||
| - `file`:压缩后的图片文件流(其中包含了一个自定义属性 `calcSize`,表示格式化后的体积) | ||
| - `dimension`:压缩后的图片宽高尺寸 | ||
@@ -348,0 +371,0 @@ - `originalFile`:原始图片文件流 |
38316
18.81%4
33.33%447
20.81%416
5.85%