본문 바로가기

WEB개발/JS&HTML

이미지 파일처리

 

  • PNG: 고품질 이미지, 투명도 지원.
  • JPG: 사진에 적합, 파일 크기 작음, 손실 압축.
  • GIF: 애니메이션 지원, 색상 제한.

 

파일업로드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Upload</title>
</head>
<body>
    <h2>Upload an Image</h2>
    <form action="/upload" method="POST" enctype="multipart/form-data">
        <input type="file" name="image" accept="image/*">
        <button type="submit">Upload</button>
    </form>
</body>
</html>

 

  • <input type="file">: 파일 업로드를 위한 입력 필드입니다.
    • name="image": 서버로 전송될 때의 파라미터 이름입니다.
    • accept="image/*": 이미지 파일만 선택하도록 제한합니다.
  • enctype="multipart/form-data": 파일 데이터를 포함해 폼을 제출하려면 반드시 설정해야 합니다

 

이미지프리뷰

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Upload with Preview</title>
</head>
<body>
    <h2>Upload and Preview an Image</h2>
    <form>
        <input type="file" id="imageInput" accept="image/*">
        <div id="preview">
            <p>No image uploaded yet.</p>
        </div>
    </form>

    <script>
        const imageInput = document.getElementById('imageInput');
        const preview = document.getElementById('preview');

        imageInput.addEventListener('change', function(event) {
            const file = event.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = function(e) {
                    preview.innerHTML = `<img src="${e.target.result}" alt="Uploaded Image" style="max-width: 100%; max-height: 300px;">`;
                };
                reader.readAsDataURL(file);
            } else {
                preview.innerHTML = '<p>No image uploaded yet.</p>';
            }
        });
    </script>
</body>
</html>

 

다운로드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Download with JavaScript</title>
</head>
<body>
    <h2>Download Image with JavaScript</h2>
    <button id="downloadButton">Download Image</button>

    <script>
        document.getElementById('downloadButton').addEventListener('click', function () {
            const link = document.createElement('a');
            link.href = '/download/example.jpg'; // 서버 파일 URL
            link.download = 'example.jpg'; // 다운로드 파일 이름
            link.click();
        });
    </script>
</body>
</html>

 

 Chrome, Samsung Browser

const blob = new Blob(["hello"], { type: "text/plain" });
const url = URL.createObjectURL(blob);

const a = document.createElement("a");
a.href = url;
a.download = "test.txt";
a.click();

 

Safari  

window.open(blobUrl, "_blank");

 

위 방법도 완전하지는 않음

Content-Disposition: attachment

Content-Disposition: attachment

 

를 응답해더에서 붙여주는 방법이 가장 안정적

 

web서버와 was가 분리되어 있다면 특정 웹서버는 설정을 통해 web의 파일을 다운로드할 수 있다.

더보기

[Browser]
   │ 1️⃣ 다운로드 요청
   ▼
[Spring WAS]
   │ - 인증 / 권한 체크
   │ - Content-Disposition 결정
   │ - X-Accel-Redirect 헤더 응답
   ▼
[Nginx]
   │ 2️⃣ 내부 경로 매핑
   │ 3️⃣ 실제 파일 전송
   ▼
[File System (/data/files)]

 

Nginx 설정 (파일 전송자)
예: 실제 파일 위치

/data/files/report.pdf

 

location /internal-files/ {
    internal;                     # 외부 직접 접근 차단
    alias /data/files/;            # 실제 파일 디렉토리
}

 

 

Spring Boot 컨트롤러 (허가·헤더 결정자)

@GetMapping("/files/download/{filename}")
public ResponseEntity<Void> download(
        @PathVariable String filename,
        Principal principal) {

    // 1️⃣ 권한 체크
    if (!hasPermission(principal, filename)) {
        return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
    }

    // 2️⃣ 파일명 인코딩 (한글 필수)
    String encoded = URLEncoder.encode(filename, StandardCharsets.UTF_8)
            .replaceAll("\\+", "%20");

    String contentDisposition =
            "attachment; filename*=UTF-8''" + encoded;

    // 3️⃣ Nginx에게 파일 전송 위임
    return ResponseEntity.ok()
        .header("X-Accel-Redirect", "/internal-files/" + filename)
        .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
        .build();
}

 


 

 

 

Jquery 이미지 서버전송

/**
 * BASE64를 BLOB데이터로 변환
 * @param base64
 * @param contentType
 * @returns {Blob}
 */
function convertBlobToJson(base64, contentType) {
	const byteCharacteres = atob(base64);
	const byteArrays = [];
	
	
	for(let offset = 0; offset < byteCharacteres.length; offset += 512) {
		const slice = byteCharacteres.slice(offset, offset+512);
		
		const byteNumbers = new Array(slice.length);
		for(let i = 0; i<slice.length ; i++) {
			byteNumbers[i] = slice.charCodeAt(i);
		}
		
		const byteArray = new Uint8Array(byteNumbers);
		byteArrays.push(byteArray);
	}
	
	return new Blob(byteArrays, {type : contentType});
}


const imgBlob = convertBlobToJson(base64img, "image/jpg");
const jpegData = new File([imgBlob], "img.jpg", {type : "image/jpg"});
const formData = new FormData();
formData.append("jpegData", jpegData);

$.ajax({
    url: "/upload",  // 파일을 전송할 서버의 URL (Spring Boot, Express 등)
    type: "POST",
    data: formData,
    contentType: false,  // jQuery가 Content-Type을 자동으로 설정하지 않도록 설정
    processData: false,  // jQuery가 데이터를 처리하지 않도록 설정
    success: function (response) {
        $("#response").html("<p>Upload successful! " + response.message + "</p>");
    },
    error: function (xhr, status, error) {
        $("#response").html("<p>Error: " + error + "</p>");
    }
});

'WEB개발 > JS&HTML' 카테고리의 다른 글

Typescript  (1) 2023.12.18
[JS] 자바스크립트 템플릿 리터럴 백틱(``), 달러(${ })  (0) 2023.10.25
[JS] 모듈(module, import, export)  (0) 2023.10.25
[JS] Deferred  (0) 2023.07.22
[JS] Async, Await, Fetch, PromiseAll  (0) 2023.03.06