Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2c842ba

Browse files
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
}

‎client/src/Shared/downscaleImage.js

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)

AltStyle によって変換されたページ (->オリジナル) /