이 글의 내용은 반응 구성 요소를 사용하여 사진을 찍고 업로드할 사진을 선택하는 내용입니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.
얼마 전 프로젝트가 재구성되어 SSR 프로젝트로 변경되었는데 이전에 사용했던 이미지 선택 업로드 컴포넌트가 SSR(Server-Side-Render)을 지원하지 않습니다. 그래서 연구를 진행하고 많은 도구를 찾았습니다. 그러나 일부는 너무 크고 일부는 사용하기 불편하며 일부는 사용 요구 사항을 충족하지 못합니다. h5 모바일 이미지 업로드 구성 요소를 직접 작성하기로 결정했습니다. 이미지 업로드는 비교적 일반적인 요구 사항입니다. PC 버전은 괜찮지만 모바일 버전은 특히 쉽지 않습니다. 아래에는 그 과정에서 발생한 몇 가지 주요 이슈를 간략히 기록합니다.
핵심사항
1. 입력에 대하여
선택 기능은 속성 accept='image/*', :capture는 카메라--카메라--카메라--녹음과 같은 시스템의 기본 장치를 캡처할 수 있음을 의미합니다. Capture="camera"로 설정하면 기본적으로 카메라가 사용됩니다. 일부 모델에서는 카메라를 호출할 수 없는 문제가 있으므로 여기서는 설정하지 않겠습니다. 다중 선택과 onchange 이벤트에 대한 콜백 기능을 허용합니다. 최종 입력은 아마도 다음과 같습니다:
<input type='file' className={classes.picker} accept='image/*' multiple capture="camera" onChange={this.onfileChange} />
물론 이 입력은 보기 흉합니다. '불투명도:0'을 설정하고 위치를 지정하여 필요한 선택 버튼 스타일로 덮어쓸 수 있습니다. 좀 더 화려하게 만들어 보세요.
사진을 선택한 후 미리보기가 가능한 것은 일반적인 기능입니다. 여기서는 스타일은 제쳐두고 코드 구현에 대해서만 이야기하겠습니다. onchange의 콜백 함수에서는 e.target.files를 통해 선택한 파일을 가져올 수 있지만 해당 파일을 페이지에 표시할 수는 없습니다. 일반적인 방법은 reader.readAsDataURL(file)을 사용하여 base64로 변환한 후 표시하는 것입니다. 페이지에 있습니다. 여기서는 9개의 정사각형 그리드 디스플레이를 사용하며 각 사진은 캔버스입니다. 다양한 사진 종횡비 문제를 고려하여 먼저 reader.readAsDataURL(file)을 통해 base64 파일을 가져옵니다. 그런 다음 이미지 내용이 왜곡 없이 캔버스 전체를 덮을 수 있도록 9개의 정사각형 격자의 캔버스 종횡비를 통해 그려진 이미지를 만듭니다.
fileToCanvas (file, index) {//文件 let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = (event) => { let image = new Image(); image.src = event.target.result; image.onload = () => { let imageCanvas = this['canvas' + index].getContext('2d'); let canvas = { width: imageCanvas.canvas.scrollWidth * 2, height: imageCanvas.canvas.scrollHeight * 2 }; let ratio = image.width / image.height; let canvasRatio = canvas.width / canvas.height; let xStart = 0; let yStart = 0; let renderableWidth; let renderableHeight; if (ratio > canvasRatio) { // 横向过大,以高为准,缩放宽度 let hRatio = image.height / canvas.height; renderableHeight = image.height; renderableWidth = canvas.width * hRatio; xStart = (image.width - renderableWidth) / 2; } if (ratio < canvasRatio) { // 横向过小,以宽为准,缩放高度 let wRatio = image.width / canvas.width; renderableWidth = image.width; renderableHeight = canvas.height * wRatio; yStart = (image.height - renderableHeight) / 2; } imageCanvas.drawImage(image, xStart, yStart, renderableWidth, renderableHeight, 0, 0, canvas.width * 2, canvas.height); }; }; }
일부 모델에서 사진 촬영 시 onchange 이벤트를 통해 얻은 파일은 blob
(小米6等)此时通过blob.type
수동으로 확장자를 판단합니다.
iOS에서 사진을 찍고 업로드하면 로컬 파일이 회전된 것으로 확인됩니다. 이 문제에 대한 이유는 설명하지 않겠습니다. 여기에 자세히 설명되어 있습니다. 관심 있으신 분은 검색해보시면 됩니다. 따라서 방향을 감지하고 이미지를 다시 일반 방향으로 회전해야 합니다. Exif.js와 같이 오리엔테이션을 얻기 위해 이미 만들어진 라이브러리가 많이 있습니다. 하지만 이 라이브러리는 용량이 좀 크고, 이 작은 요구사항 때문에 도입할 가치는 없어 보입니다. stackoverflow에서 이미지 방향을 얻기 위한 기성 코드가 많이 있습니다.
약간 변경됨:
getOrientation (file) { return new Promise((resolve, reject) => { let reader = new FileReader(); reader.onload = function (e) { //e.target.result为base64编码的文件 let view = new DataView(e.target.result); if (view.getUint16(0, false) !== 0xffd8) { return resolve(-2); } let length = view.byteLength; let offset = 2; while (offset < length) { let marker = view.getUint16(offset, false); offset += 2; if (marker === 0xffe1) { let tmp = view.getUint32(offset += 2, false); if (tmp !== 0x45786966) { return resolve(-1); } let little = view.getUint16(offset += 6, false) === 0x4949; offset += view.getUint32(offset + 4, little); let tags = view.getUint16(offset, little); offset += 2; for (let i = 0; i < tags; i++) { if (view.getUint16(offset + i * 12, little) === 0x0112) { return resolve(view.getUint16(offset + i * 12 + 8, little)); } } } else if ((marker & 0xff00) !== 0xff00) { break; } else { offset += view.getUint16(offset, false); } } return resolve(-1); }; reader.readAsArrayBuffer(file.slice(0, 64 * 1024)); }); }
//반환 값: 1--normal, -2--non-jpg, -1--undefine
일반적인 이미지 방향은 1이어야 하므로 우리는 파일을 캔버스로 변환하고 캔버스의 변환 메소드를 사용하여 캔버스를 변환하는 방법을 참고하시기 바랍니다. 마지막으로 canvas.toDataURL('')을 사용하여 base64로 인코딩된 일반 방향의 base64 이미지를 가져온 다음 업로드를 위해 base64를 blob으로 변환합니다.
//重置文件orientation resetOrientationToBlob (file, orientation) { return new Promise((resolve, reject) => { let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = (event) => { let image = new Image(); image.src = event.target.result; image.onload = () => { let width = image.width; let height = image.height; let canvas = document.createElement('canvas'); let ctx = canvas.getContext('2d'); if (orientation > 4 && orientation < 9) { canvas.width = height; canvas.height = width; } else { canvas.width = width; canvas.height = height; } switch (orientation) { case 2: ctx.transform(-1, 0, 0, 1, width, 0); break; case 3: ctx.transform(-1, 0, 0, -1, width, height); break; case 4: ctx.transform(1, 0, 0, -1, 0, height); break; case 5: ctx.transform(0, 1, 1, 0, 0, 0); break; case 6: ctx.transform(0, 1, -1, 0, height, 0); break; case 7: ctx.transform(0, -1, -1, 0, height, width); break; case 8: ctx.transform(0, -1, 1, 0, 0, width); break; default: ctx.transform(1, 0, 0, 1, 0, 0); } ctx.drawImage(image, 0, 0, width, height); let base64 = canvas.toDataURL('image/png'); let blob = this.dataURLtoBlob(base64); resolve(blob); }; }; }); }
마지막으로
이미지를 업로드하세요. 비교적 쉽습니다. FormData 형식으로 파일을 업로드하면 됩니다. 위 코드는 일부 기능의 의사 코드일 뿐이며 모든 기능의 최종 구현은 아닙니다.
할 수 있으면 시도해 보세요. 결국에는 많은 것을 배웠지만 다른 사람의 바퀴는 여전히 유용하다는 것을 알게 될 것입니다2333.
위 내용은 H5는 반응 구성 요소를 사용하여 사진을 찍고 업로드할 사진을 선택합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!