Skip to content

Commit 2c842ba

Browse files
committed
compress img url
1 parent 7a93686 commit 2c842ba

File tree

2 files changed

+101
-26
lines changed

2 files changed

+101
-26
lines changed

client/src/NoteComponents/media/media.js

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,37 @@ import PropTypes from 'prop-types'
66
import "./media.css"
77
import NotesContext from "../../Context/NotesContext"
88
import Modal, { ModalProps } from "../../Shared/Components/Modal/Modal"
9+
import { downscaleImage } from "../../Shared/downscaleImage"
910

1011
const MAX_PAYLOAD_SIZE = 100 * 1024
1112

13+
/**
14+
* Сжатие url изображения c проверкой размера
15+
* @param {String} uncompressed
16+
* @param {String} type
17+
*/
18+
async function getCompressed(uncompressed, type) {
19+
if (uncompressed.length < MAX_PAYLOAD_SIZE) return uncompressed
20+
const smallcompressedRes = await downscaleImage(uncompressed, type, 480)
21+
if (smallcompressedRes.length < MAX_PAYLOAD_SIZE) return smallcompressedRes
22+
const mediumcompressedRes = await downscaleImage(uncompressed, type, 360)
23+
if (mediumcompressedRes.length < MAX_PAYLOAD_SIZE) return mediumcompressedRes
24+
const extracompressedRes = await downscaleImage(uncompressed, type, 240)
25+
if (extracompressedRes.length < MAX_PAYLOAD_SIZE) return extracompressedRes
26+
console.error("compressed unsuc, too long url")
27+
return null
28+
}
29+
1230
/**
1331
* компонент палитры
14-
* @param {*} param0
15-
*
32+
* @param {object} props
33+
* @param {void} props.setNoteMedia
34+
* @param {Array<String>} props.mediaList
35+
* @param {{}} props.style
36+
* @param {String} props.className
37+
* @param {Boolean} props.disabled
38+
* @param {String} props.noteId
39+
* @param {{}} props.sizeData
1640
*/
1741
function Media({ setNoteMedia, mediaList = [], style, className, disabled, noteId, sizeData }) {
1842
const { addMedia, removeMedia, getMediaById, getNoteById } = useContext(NotesContext)
@@ -42,16 +66,16 @@ function Media({ setNoteMedia, mediaList = [], style, className, disabled, noteI
4266
var file = e.target.files[0]
4367
var reader = new FileReader()
4468

45-
reader.onloadend = function () {
46-
const res = reader.result
47-
if (res.length < MAX_PAYLOAD_SIZE) {
48-
console.log("readed suc", res.length)
49-
const mediaId = addMedia(res, noteId)
69+
reader.onloadend = async function () {
70+
const uncompressedReaderRes = reader.result
71+
const compressedRes = await getCompressed(uncompressedReaderRes, file.type)
72+
73+
if (compressedRes) {
74+
const mediaId = addMedia(compressedRes, noteId)
5075
Array.isArray(mediaList) ? mediaList.push(mediaId) : (mediaList = [mediaId])
5176
setNoteMedia(mediaList)
52-
} else {
53-
console.error("readed unsuc", res.length)
5477
}
78+
5579
e.target.value = null
5680
}
5781

@@ -67,13 +91,7 @@ function Media({ setNoteMedia, mediaList = [], style, className, disabled, noteI
6791
return (
6892
<React.Fragment>
6993
{/**Кнопка вызова media */}
70-
<button
71-
disabled={disabled}
72-
className={`btn ${className}`}
73-
style={style}
74-
type="button"
75-
onClick={open}
76-
>
94+
<button disabled={disabled} className={`btn ${className}`} style={style} type="button" onClick={open} >
7795
<i className="bi bi-image" ></i>
7896
</button>
7997

@@ -102,21 +120,18 @@ function Media({ setNoteMedia, mediaList = [], style, className, disabled, noteI
102120
)}
103121
</div>
104122

105-
<div className="form-group container d-flex flex-wrap justify-content-between mb-0">
106-
<div className="custom-file mb-0 m-1" style={{ maxWidth: "14em" }}>
107-
<input disabled={limited} onChange={encodeImageFileAsURLAndPost} type="file" className="custom-file-input" id="noteImgFile" accept=".jpg, .jpeg, .png" />
108-
<label className="custom-file-label" htmlFor="noteImgFile">{"Img - 100Kb max"}</label>
123+
<div className="form-group container row mb-0">
124+
<div className="custom-file p-0 col m-1" style={{ minWidth: "7.6em" }}>
125+
<input style={{ cursor: "pointer" }} disabled={limited} onChange={encodeImageFileAsURLAndPost} type="file" className="custom-file-input" id="noteImgFile" accept=".jpg, .jpeg, .png" />
126+
<label style={{ boxShadow: "none", border: "lightgray 1px solid" }} className="custom-file-label" htmlFor="noteImgFile">{"Img"}</label>
109127
</div>
110-
<button
111-
className="btn btn-light m-1"
112-
style={{ boxShadow: "none" }}
113-
onClick={close}
114-
>Close</button>
128+
<button className="btn btn-light col-3 col-sm-2 m-1 ml-auto" style={{ boxShadow: "none", minWidth: "4em" }} onClick={close} >
129+
Close
130+
</button>
115131
</div>
116132

117133
</div>
118134
</Modal>
119-
120135
</React.Fragment>
121136
);
122137
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**@file downscaleImage.js */
2+
3+
/**
4+
* Получение Image из dataUrl
5+
* @param {string} dataUrl
6+
* @returns {Promise<HTMLImageElement>}
7+
*/
8+
function getImage(dataUrl) {
9+
return new Promise((resolve, reject) => {
10+
const image = new Image()
11+
image.src = dataUrl
12+
image.onload = () => {
13+
resolve(image)
14+
}
15+
image.onerror = (el, err) => {
16+
reject(err.error)
17+
}
18+
})
19+
}
20+
21+
/**
22+
* Сжатие url изображения
23+
* @param {string} dataUrl
24+
* @param {string} imageType e.g. 'image/jpeg'
25+
* @param {number} resolution max width/height in pixels
26+
* @param {number} quality e.g. 0.9 = 90% quality
27+
* @returns {Promise<string>}
28+
*/
29+
export async function downscaleImage(dataUrl, imageType, resolution, quality = 1) {
30+
// Create a temporary image so that we can compute the height of the image.
31+
const image = await getImage(dataUrl)
32+
const oldWidth = image.naturalWidth
33+
const oldHeight = image.naturalHeight
34+
35+
const longestDimension = oldWidth > oldHeight ? 'width' : 'height'
36+
const currentRes = longestDimension === 'width' ? oldWidth : oldHeight
37+
38+
if (currentRes > resolution) {
39+
// Calculate new dimensions
40+
const newSize = longestDimension === 'width'
41+
? Math.floor(oldHeight / oldWidth * resolution)
42+
: Math.floor(oldWidth / oldHeight * resolution)
43+
const newWidth = longestDimension === 'width' ? resolution : newSize
44+
const newHeight = longestDimension === 'height' ? resolution : newSize
45+
46+
// Create a temporary canvas to draw the downscaled image on.
47+
const canvas = document.createElement('canvas')
48+
canvas.width = newWidth
49+
canvas.height = newHeight
50+
51+
// Draw the downscaled image on the canvas and return the new data URL.
52+
const ctx = canvas.getContext('2d')
53+
ctx.drawImage(image, 0, 0, newWidth, newHeight)
54+
const newDataUrl = canvas.toDataURL(imageType, quality)
55+
return newDataUrl
56+
}
57+
else {
58+
return dataUrl
59+
}
60+
}

0 commit comments

Comments
 (0)