JS 클라이언트 측 Exif 방향 : JPEG 이미지 회전 및 미러링
디지털 카메라 사진은 종종 EXIF "방향"태그를 사용하여 JPEG로 저장됩니다. 올바르게 표시하려면 설정된 방향에 따라 이미지를 회전 / 미러링해야하지만 브라우저는 이미지를 렌더링하는이 정보를 무시합니다. 대규모 상용 웹 앱에서도 EXIF 방향 지원은 드문 일 이 될 수 있습니다 1 . 동일한 소스는 JPEG가 가질 수있는 8 가지 방향에 대한 요약을 제공합니다 .
샘플 이미지는 4 에서 사용할 수 있습니다 .
문제는 이미지가 올바르게 표시되고 필요한 경우 추가 처리가 가능하도록 클라이언트 쪽에서 이미지를 회전 / 미러링하는 방법입니다.
방향 속성 2를 포함하여 EXIF 데이터를 구문 분석 할 수있는 JS 라이브러리가 있습니다 . webworkers의 사용을 필요로하는, 큰 이미지를 구문 분석 할 때 플리커 가능한 성능 문제를 언급 한 3 .
콘솔 도구는 이미지 방향을 올바르게 조정할 수 있습니다 5 . 문제를 해결하는 PHP 스크립트는 6에 있습니다.
github 프로젝트 JavaScript-Load-Image 는 EXIF 오리엔테이션 문제에 대한 완벽한 솔루션을 제공하여 8 개의 exif 오리엔테이션 모두에 대해 이미지를 올바르게 회전 / 반사합니다. 자바 스크립트 EXIF 오리엔테이션 온라인 데모보기
이미지는 HTML5 캔버스에 그려집니다. 올바른 렌더링은 캔버스 작업을 통해 js / load-image-orientation.js에 구현됩니다 .
이것이 누군가의 시간을 절약하고 검색 엔진 에이 오픈 소스 보석에 대해 가르치기를 바랍니다 :)
Mederr의 컨텍스트 변환 은 완벽하게 작동합니다. 방향을 추출 해야하는 경우이 기능 만 사용 하십시오-EXIF를 읽는 라이브러리가 필요하지 않습니다. 다음은 base64 이미지에서 방향을 재설정하는 기능입니다. 여기에 바이올린이 있습니다 . 또한 방향 추출 데모 로 바이올린을 준비했습니다 .
function resetOrientation(srcBase64, srcOrientation, callback) {
var img = new Image();
img.onload = function() {
var width = img.width,
height = img.height,
canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d");
// set proper canvas dimensions before transform & export
if (4 < srcOrientation && srcOrientation < 9) {
canvas.width = height;
canvas.height = width;
} else {
canvas.width = width;
canvas.height = height;
}
// transform context before drawing image
switch (srcOrientation) {
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: break;
}
// draw image
ctx.drawImage(img, 0, 0);
// export base64
callback(canvas.toDataURL());
};
img.src = srcBase64;
};
만약
width = img.width;
height = img.height;
var ctx = canvas.getContext('2d');
그런 다음 이러한 변환을 사용하여 이미지를 방향으로 설정할 수 있습니다. 1
오리엔테이션에서 :
ctx.transform(1, 0, 0, 1, 0, 0);
ctx.transform(-1, 0, 0, 1, width, 0);
ctx.transform(-1, 0, 0, -1, width, height);
ctx.transform(1, 0, 0, -1, 0, height);
ctx.transform(0, 1, 1, 0, 0, 0);
ctx.transform(0, 1, -1, 0, height, 0);
ctx.transform(0, -1, -1, 0, height, width);
ctx.transform(0, -1, 1, 0, 0, width);
ctx에서 이미지를 그리기 전에
@ user3096626 외에도 ok 답변 누군가가 코드 예제를 제공하면 더 도움이 될 것이라고 생각합니다. 다음 예제는 URL (원격 이미지)에서 이미지 방향을 수정하는 방법을 보여줍니다.
해결 방법 1 : 자바 스크립트 사용 (권장)
때문에 로드 이미지 라이브러리 URL 이미지 만 (파일 / BLOB)에서 EXIF 태그를 추출하지 않습니다, 우리는 모두 사용 EXIF-JS 와 로드 이미지 때문에 먼저 다음과 같은 페이지에이 라이브러리를 추가, 자바 스크립트 라이브러리 :
<script src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.1.0/exif.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image-scale.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image-orientation.min.js"></script>
참고 EXIF-JS의 2.2 것 같다 버전을 문제 우리가 2.1을 사용하므로
기본적으로 우리가 할 일은
a-사용하여 이미지를로드
window.loadImage()
b-다음을 사용하여 exif 태그를 읽습니다.
window.EXIF.getData()
c-이미지를 캔버스로 변환하고 다음을 사용하여 이미지 방향 고정
window.loadImage.scale()
d-캔버스를 문서에 배치
여기 당신은 간다 :)
window.loadImage("/your-image.jpg", function (img) {
if (img.type === "error") {
console.log("couldn't load image:", img);
} else {
window.EXIF.getData(img, function () {
var orientation = EXIF.getTag(this, "Orientation");
var canvas = window.loadImage.scale(img, {orientation: orientation || 0, canvas: true});
document.getElementById("container").appendChild(canvas);
// or using jquery $("#container").append(canvas);
});
}
});
물론 캔버스 객체에서 이미지를 base64로 가져 와서 img src 속성에 배치 할 수 있으므로 jQuery를 사용하면 가능합니다.)
$("#my-image").attr("src",canvas.toDataURL());
여기에 전체 코드가 있습니다 : github : https://github.com/digital-flowers/loadimage-exif-example
해결 방법 2 : HTML 사용 (브라우저 핵)
매우 빠르고 쉬운 해킹이 있습니다. 대부분의 브라우저는 이미지가 html (LOL i 이유를 모르겠습니다)없이 새 탭에서 직접 열면 이미지를 올바른 방향으로 표시하므로 기본적으로 iframe을 사용하여 이미지를 표시 할 수 있습니다 iframe src 속성을 이미지 URL로 직접 입력하여 :
<iframe src="/my-image.jpg"></iframe>
해결 방법 3 : CSS 사용 (ios에서는 Firefox 및 Safari 만 해당)
이미지 방향을 수정하는 CSS3 속성이 있지만 파이어 폭스와 사파리 / iOS에서만 작동하는 문제는 곧 모든 브라우저에서 사용할 수 있기 때문에 언급 할 가치가 있습니다 ( 캐니 저 에서 브라우저 지원 정보 )
img {
image-orientation: from-image;
}
입력 컨트롤에서 파일을 가지고있는 사람들에게 오리엔테이션이 무엇인지 알지 못하고 약간 게으 르며 아래 큰 라이브러리를 포함하고 싶지 않은 경우 @WunderBart가 제공 한 코드는 방향을 찾는 https://stackoverflow.com/a/32490603 ).
function getDataUrl(file, callback2) {
var callback = function (srcOrientation) {
var reader2 = new FileReader();
reader2.onload = function (e) {
var srcBase64 = e.target.result;
var img = new Image();
img.onload = function () {
var width = img.width,
height = img.height,
canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d");
// set proper canvas dimensions before transform & export
if (4 < srcOrientation && srcOrientation < 9) {
canvas.width = height;
canvas.height = width;
} else {
canvas.width = width;
canvas.height = height;
}
// transform context before drawing image
switch (srcOrientation) {
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: break;
}
// draw image
ctx.drawImage(img, 0, 0);
// export base64
callback2(canvas.toDataURL());
};
img.src = srcBase64;
}
reader2.readAsDataURL(file);
}
var reader = new FileReader();
reader.onload = function (e) {
var view = new DataView(e.target.result);
if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
var length = view.byteLength, offset = 2;
while (offset < length) {
var marker = view.getUint16(offset, false);
offset += 2;
if (marker == 0xFFE1) {
if (view.getUint32(offset += 2, false) != 0x45786966) return callback(-1);
var little = view.getUint16(offset += 6, false) == 0x4949;
offset += view.getUint32(offset + 4, little);
var tags = view.getUint16(offset, little);
offset += 2;
for (var i = 0; i < tags; i++)
if (view.getUint16(offset + (i * 12), little) == 0x0112)
return callback(view.getUint16(offset + (i * 12) + 8, little));
}
else if ((marker & 0xFF00) != 0xFF00) break;
else offset += view.getUint16(offset, false);
}
return callback(-1);
};
reader.readAsArrayBuffer(file);
}
이런 식으로 쉽게 부를 수 있습니다
getDataUrl(input.files[0], function (imgBase64) {
vm.user.BioPhoto = imgBase64;
});
WunderBart의 답변이 제게 최고였습니다. 회전이 필요하지 않은 경우 방향을 먼저 테스트하고 나머지 코드를 무시하여 이미지가 올바른 방향으로 이동하는 경우 속도를 크게 높일 수 있습니다.
wunderbart의 모든 정보를 다음과 같이 정리하십시오.
var handleTakePhoto = function () {
let fileInput: HTMLInputElement = <HTMLInputElement>document.getElementById('photoInput');
fileInput.addEventListener('change', (e: any) => handleInputUpdated(fileInput, e.target.files));
fileInput.click();
}
var handleInputUpdated = function (fileInput: HTMLInputElement, fileList) {
let file = null;
if (fileList.length > 0 && fileList[0].type.match(/^image\//)) {
isLoading(true);
file = fileList[0];
getOrientation(file, function (orientation) {
if (orientation == 1) {
imageBinary(URL.createObjectURL(file));
isLoading(false);
}
else
{
resetOrientation(URL.createObjectURL(file), orientation, function (resetBase64Image) {
imageBinary(resetBase64Image);
isLoading(false);
});
}
});
}
fileInput.removeEventListener('change');
}
// from http://stackoverflow.com/a/32490603
export function getOrientation(file, callback) {
var reader = new FileReader();
reader.onload = function (event: any) {
var view = new DataView(event.target.result);
if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
var length = view.byteLength,
offset = 2;
while (offset < length) {
var marker = view.getUint16(offset, false);
offset += 2;
if (marker == 0xFFE1) {
if (view.getUint32(offset += 2, false) != 0x45786966) {
return callback(-1);
}
var little = view.getUint16(offset += 6, false) == 0x4949;
offset += view.getUint32(offset + 4, little);
var tags = view.getUint16(offset, little);
offset += 2;
for (var i = 0; i < tags; i++)
if (view.getUint16(offset + (i * 12), little) == 0x0112)
return callback(view.getUint16(offset + (i * 12) + 8, little));
}
else if ((marker & 0xFF00) != 0xFF00) break;
else offset += view.getUint16(offset, false);
}
return callback(-1);
};
reader.readAsArrayBuffer(file.slice(0, 64 * 1024));
};
export function resetOrientation(srcBase64, srcOrientation, callback) {
var img = new Image();
img.onload = function () {
var width = img.width,
height = img.height,
canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d");
// set proper canvas dimensions before transform & export
if (4 < srcOrientation && srcOrientation < 9) {
canvas.width = height;
canvas.height = width;
} else {
canvas.width = width;
canvas.height = height;
}
// transform context before drawing image
switch (srcOrientation) {
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: break;
}
// draw image
ctx.drawImage(img, 0, 0);
// export base64
callback(canvas.toDataURL());
};
img.src = srcBase64;
}
@fareed namrouti의 답변 외에도
파일 입력 요소에서 이미지를 찾아보아야하는 경우에 사용해야합니다.
<input type="file" name="file" id="file-input"><br/>
image after transform: <br/>
<div id="container"></div>
<script>
document.getElementById('file-input').onchange = function (e) {
var image = e.target.files[0];
window.loadImage(image, function (img) {
if (img.type === "error") {
console.log("couldn't load image:", img);
} else {
window.EXIF.getData(image, function () {
console.log("load image done!");
var orientation = window.EXIF.getTag(this, "Orientation");
var canvas = window.loadImage.scale(img,
{orientation: orientation || 0, canvas: true, maxWidth: 200});
document.getElementById("container").appendChild(canvas);
// or using jquery $("#container").append(canvas);
});
}
});
};
</script>
혼합 솔루션 (php + css)을 사용하고 있습니다.
컨테이너는 다음을 위해 필요합니다 :
div.imgCont2
컨테이너를 회전해야합니다.div.imgCont1
축소하기 위해 필요한 컨테이너-width:150%
;div.imgCont
이미지가 축소 일 때 스크롤 막대에 필요한 컨테이너입니다.
.
<?php
$image_url = 'your image url.jpg';
$exif = @exif_read_data($image_url,0,true);
$orientation = @$exif['IFD0']['Orientation'];
?>
<style>
.imgCont{
width:100%;
overflow:auto;
}
.imgCont2[data-orientation="8"]{
transform:rotate(270deg);
margin:15% 0;
}
.imgCont2[data-orientation="6"]{
transform:rotate(90deg);
margin:15% 0;
}
.imgCont2[data-orientation="3"]{
transform:rotate(180deg);
}
img{
width:100%;
}
</style>
<div class="imgCont">
<div class="imgCont1">
<div class="imgCont2" data-orientation="<?php echo($orientation) ?>">
<img src="<?php echo($image_url) ?>">
</div>
</div>
</div>
이미지를 회전시키는 작은 PHP 스크립트를 작성했습니다. 각 요청마다 이미지를 다시 계산하기 위해 이미지를 저장하십시오.
<?php
header("Content-type: image/jpeg");
$img = 'IMG URL';
$exif = @exif_read_data($img,0,true);
$orientation = @$exif['IFD0']['Orientation'];
if($orientation == 7 || $orientation == 8) {
$degrees = 90;
} elseif($orientation == 5 || $orientation == 6) {
$degrees = 270;
} elseif($orientation == 3 || $orientation == 4) {
$degrees = 180;
} else {
$degrees = 0;
}
$rotate = imagerotate(imagecreatefromjpeg($img), $degrees, 0);
imagejpeg($rotate);
imagedestroy($rotate);
?>
건배
하나의 라이너?
나는 아무도 browser-image-compression
도서관을 언급하는 것을 보지 못했다 . 이것에 완벽한 도우미 기능이 있습니다.
용법: const orientation = await imageCompression.getExifOrientation(file)
다른 많은 방법으로도 유용한 도구입니다.
'Programing' 카테고리의 다른 글
Angular 6에서 'ng serve'를 통해 환경을 설정하는 방법 (0) | 2020.07.03 |
---|---|
Java List에서 Scala List를 얻는 방법? (0) | 2020.07.03 |
iPad에서 UITableView backgroundColor가 항상 회색 (0) | 2020.07.03 |
루비로 무한대를 표현하는 방법? (0) | 2020.07.03 |
Rails 3 : Rails 애플리케이션에 정의 된 모든 경로를 나열하고 싶습니다 (0) | 2020.07.03 |