From 52b0f03803a94689ccc08578b5538405c88be1f2 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Mon, 20 Oct 2025 11:15:54 +0000
Subject: (대표님) 데이터룸 관련: 워터마크, PDF 뷰어, 로그인
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/file-manager/creaetWaterMarks.tsx | 233 +++++++++++++++++++--------
 1 file changed, 168 insertions(+), 65 deletions(-)

(limited to 'components/file-manager/creaetWaterMarks.tsx')

diff --git a/components/file-manager/creaetWaterMarks.tsx b/components/file-manager/creaetWaterMarks.tsx
index 524b18ee..a9072150 100644
--- a/components/file-manager/creaetWaterMarks.tsx
+++ b/components/file-manager/creaetWaterMarks.tsx
@@ -1,71 +1,174 @@
 export const createCustomWatermark: CreateCustomWatermark = ({
-    text,
-    fontSize,
-    color,
-    opacity,
-    rotation = -45,
-    fontFamily = "Helvetica",
-  }) => {
-    return (ctx, pageNumber, pageWidth, pageHeight) => {
-      if (!text) return;
-   
-      const lines = text.split("\n"); // 줄바꿈 기준 멀치 처리
-   
-      ctx.save();
-      ctx.translate(pageWidth / 2, pageHeight / 2);
-      ctx.rotate((rotation * Math.PI) / 180);
-      ctx.fillStyle = color;
-      ctx.textAlign = "center";
-      ctx.textBaseline = "middle";
-   
-      const lineHeights = lines.map((s) => {
-        return fontSize;
-      });
-   
-      const totalHeight =
-        lineHeights.reduce((sum, h) => sum + h, 0) - lineHeights[0]; // 첫 줄은 기준선 0
-   
-      let yOffset = -totalHeight / 2;
-   
-      lines.forEach((line, i) => {
-        ctx.font = `900 ${fontSize}px ${fontFamily}`;
-        ctx.fillText(line, 0, yOffset);
-        yOffset += lineHeights[i];
-      });
-   
-      ctx.restore();
-    };
+  text,
+  fontSize = 14,
+  color = "rgba(128, 128, 128, 0.15)", // 더 연한 회색, 더 투명하게
+  opacity = 15, // 더 낮은 opacity
+  rotation = -45,
+  fontFamily = "Arial",
+}) => {
+  return (ctx, pageNumber, pageWidth, pageHeight) => {
+    if (!text) return;
+
+    const lines = text.split("\n");
+    
+    ctx.save();
+    
+    // 전체 opacity 설정
+    ctx.globalAlpha = opacity / 100;
+    
+    // 텍스트 스타일 설정
+    ctx.fillStyle = color;
+    ctx.font = `${fontSize}px ${fontFamily}`;
+    ctx.textAlign = "center";
+    ctx.textBaseline = "middle";
+    
+    // 텍스트 크기 계산
+    const maxLineWidth = Math.max(...lines.map(line => 
+      ctx.measureText(line).width
+    ));
+    const lineHeight = fontSize * 1.2;
+    const textBlockHeight = lines.length * lineHeight;
+    
+    // 격자 간격 계산 (텍스트 블록 크기 기반)
+    const horizontalSpacing = maxLineWidth * 1.8; // 가로 간격
+    const verticalSpacing = textBlockHeight * 2.5; // 세로 간격
+    
+    // 회전을 고려한 대각선 길이 계산
+    const diagonal = Math.sqrt(pageWidth * pageWidth + pageHeight * pageHeight);
+    const rotationRad = (rotation * Math.PI) / 180;
+    
+    // 시작 위치 계산 (페이지 밖에서 시작하여 전체 커버)
+    const startX = -diagonal / 2;
+    const startY = -diagonal / 2;
+    const endX = diagonal / 2;
+    const endY = diagonal / 2;
+    
+    // 격자 패턴으로 워터마크 그리기
+    for (let x = startX; x <= endX; x += horizontalSpacing) {
+      for (let y = startY; y <= endY; y += verticalSpacing) {
+        ctx.save();
+        
+        // 중심점으로 이동
+        ctx.translate(pageWidth / 2, pageHeight / 2);
+        
+        // 회전 적용
+        ctx.rotate(rotationRad);
+        
+        // 현재 위치로 이동
+        ctx.translate(x, y);
+        
+        // 각 줄 그리기
+        let yOffset = -(lines.length - 1) * lineHeight / 2;
+        lines.forEach((line) => {
+          ctx.fillText(line, 0, yOffset);
+          yOffset += lineHeight;
+        });
+        
+        ctx.restore();
+      }
+    }
+    
+    ctx.restore();
   };
-   
+};
 
-  import { Core, WebViewerInstance } from "@pdftron/webviewer";
+// 대안 1: 더 촘촘한 격자 패턴 (보안 강화)
+export const createDenseGridWatermark: CreateCustomWatermark = ({
+  text,
+  fontSize = 12, // 더 작은 폰트
+  color = "rgba(150, 150, 150, 0.08)", // 매우 연한 색상
+  opacity = 8,
+  rotation = -45,
+  fontFamily = "Arial",
+}) => {
+  return (ctx, pageNumber, pageWidth, pageHeight) => {
+    if (!text) return;
 
-export interface WaterMarkOption {
-  fontSize: number;
-  color: string;
-  opacity: number;
-  rotation: number;
-  fontFamily: string;
-  split: boolean;
-  shipNameCheck: boolean;
-  shipName: string;
-  ownerNameCheck: boolean;
-  ownerName: string;
-  classNameCheck: boolean;
-  className: string;
-  classList: string[];
-  customCheck: boolean;
-  text: string;
-}
+    const lines = text.split("\n");
+    
+    ctx.save();
+    ctx.globalAlpha = opacity / 100;
+    ctx.fillStyle = color;
+    ctx.font = `${fontSize}px ${fontFamily}`;
+    ctx.textAlign = "center";
+    ctx.textBaseline = "middle";
+    
+    // 더 촘촘한 간격
+    const horizontalSpacing = 120; // 고정 간격
+    const verticalSpacing = 80;
+    
+    const diagonal = Math.sqrt(pageWidth * pageWidth + pageHeight * pageHeight);
+    const rotationRad = (rotation * Math.PI) / 180;
+    
+    for (let x = -diagonal; x <= diagonal; x += horizontalSpacing) {
+      for (let y = -diagonal; y <= diagonal; y += verticalSpacing) {
+        ctx.save();
+        ctx.translate(pageWidth / 2 + x, pageHeight / 2 + y);
+        ctx.rotate(rotationRad);
+        
+        let yOffset = 0;
+        lines.forEach((line) => {
+          ctx.fillText(line, 0, yOffset);
+          yOffset += fontSize * 1.2;
+        });
+        
+        ctx.restore();
+      }
+    }
+    
+    ctx.restore();
+  };
+};
 
-type CreateCustomWatermark = ({
+// 대안 2: 랜덤 위치 워터마크 (패턴 예측 방지)
+export const createRandomizedWatermark: CreateCustomWatermark = ({
   text,
-  fontSize,
-  color,
-  opacity,
-  rotation,
-  fontFamily,
-}: Pick<
-  WaterMarkOption,
-  "text" | "fontSize" | "color" | "opacity" | "rotation" | "fontFamily"
->) => Core.DocumentViewer.CustomWatermarkCallback;
\ No newline at end of file
+  fontSize = 14,
+  color = "rgba(140, 140, 140, 0.1)",
+  opacity = 10,
+  rotation = -45,
+  fontFamily = "Arial",
+}) => {
+  return (ctx, pageNumber, pageWidth, pageHeight) => {
+    if (!text) return;
+
+    const lines = text.split("\n");
+    
+    ctx.save();
+    ctx.globalAlpha = opacity / 100;
+    ctx.fillStyle = color;
+    ctx.font = `${fontSize}px ${fontFamily}`;
+    ctx.textAlign = "center";
+    ctx.textBaseline = "middle";
+    
+    // 페이지 번호를 시드로 사용하여 일관된 랜덤 생성
+    const seed = pageNumber * 1000;
+    const random = (min: number, max: number, index: number) => {
+      const x = Math.sin(seed + index) * 10000;
+      return min + (x - Math.floor(x)) * (max - min);
+    };
+    
+    // 워터마크 개수 (페이지 크기에 비례)
+    const count = Math.floor((pageWidth * pageHeight) / 40000); // 조정 가능
+    
+    for (let i = 0; i < count; i++) {
+      const x = random(0, pageWidth, i * 2);
+      const y = random(0, pageHeight, i * 2 + 1);
+      const rotationVariation = random(-5, 5, i * 3); // ±5도 변화
+      
+      ctx.save();
+      ctx.translate(x, y);
+      ctx.rotate((rotation + rotationVariation) * Math.PI / 180);
+      
+      let yOffset = 0;
+      lines.forEach((line) => {
+        ctx.fillText(line, 0, yOffset);
+        yOffset += fontSize * 1.2;
+      });
+      
+      ctx.restore();
+    }
+    
+    ctx.restore();
+  };
+};
\ No newline at end of file
-- 
cgit v1.2.3

