작업 전



작업 후


개요


위와 같이 이미지와 그 내부에 글자를 쓰고자 할 때 매번 포토샵 같은 프로그램에 들어가서 작업하려면 귀차니즘이 발동하기 때문에 힘든데 이럴때를 위해 만든 유틸성 자바 프로그램의 소스를 공유하고자 합니다. 좀 더 응용하면 더 좋은 프로그램이 나올수도 있겠네요


동작방법


자바최신 버전 설치(1.7이상 권장) 후 실행하시면 됩니다. (자바 프로그램에 대한 설명은 생략하겠습니다. main에 예제까지 넣었으니 ㅜㅜ )




소스 간단 설명


TEXT 드로잉

텍스트의 크기정보 GET

배경의 width를 텍스트에 맞춰 resize 이후 텍스트를 이미지 위에 overlay

배경 이미지 CROP 및 이미지 생성


소스

package com.wonsama.wswriter.utils; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; import java.net.URL; import javax.imageio.ImageIO; /** * 입력 텍스트를 이미지로 만들어 준다 * @author parkwon * @since 2017.03.24 */ public class WsImageTextUtil { /** * 테스트용 진입점 * @param args 파라미터 * @since 2017.03.24 */ public static void main(String[] args) { try{ new WsImageTextUtil(); }catch (Exception e) { e.printStackTrace(); } } /** * 생성자 * @since 2017.03.24 */ WsImageTextUtil() throws Exception { // drawText("어머니가 짜장면이 싫다고 하셨어", "/Users/parkwon/Desktop/sample.png"); String[] texts = {"아이폰 7 붉은색 사주세요"}; drawTextWithImage(texts , "/Users/parkwon/Desktop/writes/title.png" , "http://imgnews.naver.com/image/5463/2017/03/21/0000000101_003_20170322105216516.png"); } /** * 텍스트를 이미지로 만들어준다 * @param text 텍스트 * @param fileLoc 파일위치 * @throws Exception 오류 * @since 2017.03.27 */ public void drawText(String text, String fileLoc) throws Exception { Font font = new Font("나눔고딕", Font.PLAIN, 28); Rectangle r = getFontrect(text, font); int width = (int) r.getWidth(); int height = (int) r.getHeight(); BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = getG2D(img); g2d.setFont(font); FontMetrics fm = g2d.getFontMetrics(); g2d.setColor(Color.BLACK); g2d.drawString(text, 0, fm.getAscent()); g2d.dispose(); // 이미지 파일을 생성한다 ImageIO.write(img, "png", new File(fileLoc)); } /** * 웹 이미지 내부에 텍스트를 포함하여 이미지로 만들어준다 * @param texts 텍스트 문자열 * @param fileLoc 파일위치 * @param backgrondImageURL 웹이미지 주소 * @throws Exception 오류 * @since 2017.03.27 */ public void drawTextWithImage(String[] texts, String fileLoc, String backgrondImageURL) throws Exception { final int FONT_SIZE = 18; final int POS_X = 30; final int POS_Y = 20; BufferedImage img = ImageIO.read(new URL(backgrondImageURL)); Graphics g = img.getGraphics(); Font font = new Font("나눔고딕", Font.PLAIN, FONT_SIZE); // 우선은 첫 라인 정보만 가져온다. 일반적으로 가장 길게 설정하는 것이 맞다고 생각함. Rectangle rect = getFontrect(texts[0], font); int oriWidth = img.getWidth(); int oriHeight = img.getHeight(); double ratio = (rect.getWidth() + POS_X*2) / oriWidth; int newWidth = (int) (rect.getWidth() + POS_X*2); int newHeight = (int) (oriHeight * ratio); // 배경 이미지 RESIZE 처리 img = resizeImage(img, newWidth, newHeight*texts.length); // 텍스트 처리 for(int i=0;i<texts.length;i++){ Graphics2D g2d = getG2D(img); g2d.setFont(font); int x = POS_X; int y = (FONT_SIZE + POS_Y)*(i + 1); // 그림자 처리 drawStringDropshadow(g2d, texts[i], x, y); } g.dispose(); // 배경 이미지 CROP 처리 img = cropImage(img, new Rectangle(0, 0, newWidth, (FONT_SIZE+POS_Y)*texts.length+POS_Y) ); // 이미지 파일을 생성한다 ImageIO.write(img, "png", new File(fileLoc)); } /** * 입력받은 문자열의 사각영역을 반환한다 * @param text 문자열 * @param font 폰트 * @return 사각크기 * @since 2017.03.24 */ private Rectangle getFontrect(String text, Font font){ BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = img.createGraphics(); g2d.setFont(font); FontMetrics fm = g2d.getFontMetrics(); int width = fm.stringWidth(text); int height = fm.getHeight(); g2d.dispose(); return new Rectangle(0, 0, width, height); } /** * 아웃라인 처리 * @param g2d 2D 그래픽스 * @param text 문자열 * @param x X좌표 * @param y Y좌표 * @param cin 내부 색상 * @param cout 외부 색상 * @since 2017.03.27 */ private void drawStringOutline(Graphics2D g2d, String text, int x, int y, Color cin, Color cout){ g2d.setColor(cout); g2d.drawString(text, ShiftWest(x, 1), ShiftNorth(y, 1)); g2d.drawString(text, ShiftWest(x, 1), ShiftSouth(y, 1)); g2d.drawString(text, ShiftEast(x, 1), ShiftNorth(y, 1)); g2d.drawString(text, ShiftEast(x, 1), ShiftSouth(y, 1)); g2d.setColor(cin); g2d.drawString(text, x, y); } /** * 그림자 텍스트를 그려준다 * @param g2d 2D 그래픽스 * @param text 문자열 * @param x X좌표 * @param y Y좌표 * @since 2017.03.27 */ private void drawStringDropshadow(Graphics2D g2d, String text, int x, int y) { g2d.setColor(new Color(20, 20, 20)); g2d.drawString(text, ShiftEast(x, 2), ShiftSouth(y, 2)); g2d.setColor(new Color(220, 220, 220)); g2d.drawString(text, x, y); } /** * 폰트를 회전 처리한다 * @param font 폰트 * @param angle 회전각 0~360 / -를 넣으면 반시계 방향으로 계산 * @return 회전처리 된 폰트 * @since 2017.03.24 */ private Font rotatedFont(Font font, double angle){ // 폰트 회전처리 AffineTransform form = new AffineTransform(); form.rotate(Math.toRadians(angle), 0, 0); return font.deriveFont(form); } /** * 이미지 크롭처리 * @param img 이미지 * @param rect 사각정보 * @return 신규 이미지 * @since 2017.03.24 */ private BufferedImage cropImage(BufferedImage img, Rectangle rect) { BufferedImage dest = img.getSubimage(rect.x, rect.y, rect.width, rect.height); return dest; } /** * 이미지 리사이징 * @param img 이미지 * @param newW 새로운 넓이 * @param newH 새로운 높이 * @return 신규 이미지 * @since 2017.03.24 */ private BufferedImage resizeImage(BufferedImage img, int newW, int newH) { Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH); BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = dimg.createGraphics(); g2d.drawImage(tmp, 0, 0, null); g2d.dispose(); return dimg; } /** * 이미지에서 2D 그래픽스 개체를 얻어온다 * @param img 이미지버퍼 * @return 2D 그래픽스 * @since 2017.03.24 */ private Graphics2D getG2D(BufferedImage img) { Graphics2D g2d = img.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); return g2d; } /** * 좌표 이동처리 - 위쪽 / 북 * @param p 현 좌표 * @param distance 이동거리 * @return 변경된 좌표 * @since 2017.03.27 */ int ShiftNorth(int p, int distance) { return (p - distance); } /** * 좌표 이동처리 - 아래쪽 / 남 * @param p 현 좌표 * @param distance 이동거리 * @return 변경된 좌표 * @since 2017.03.27 */ int ShiftSouth(int p, int distance) { return (p + distance); } /** * 좌표 이동처리 - 오른쪽 / 동 * @param p 현 좌표 * @param distance 이동거리 * @return 변경된 좌표 * @since 2017.03.27 */ int ShiftEast(int p, int distance) { return (p + distance); } /** * 좌표 이동처리 - 왼쪽 / 서 * @param p 현 좌표 * @param distance 이동거리 * @return 변경된 좌표 * @since 2017.03.27 */ int ShiftWest(int p, int distance) { return (p - distance); } }



1. 그래픽 버튼을 상속 받아 텍스트 버튼 클래스 만들기
2. 사용 예제


1. 그래픽 버튼을 상속 받아 텍스트 버튼 클래스 만들기
public class MyGraphicHaviButton extends HGraphicButton
{
private String text;
private int xTextPosition;
private int yTextPosition;

public MyGraphicHaviButton (String text,int xTextPosition,int yTextPosition,
Image image,int xPos,int yPos,int xDim,int yDim)
{
super(image,xPos,yPos,xDim,yDim);
this.text=text;
this.xTextPosition=xTextPosition;
this.yTextPosition=yTextPosition;
}

public void paint(Graphics g){
//displays the image...
super.paint(g);
// display the String
g.drawString(text,xTextPosition,yTextPosition);
}
}


2. 사용 예제
Image sfondoNotSelected = Tools.loadImage("resource/notselected.png");

myButton=new MyGraphicHaviButton ("PROGRAMMI TV",430,274,sfondoNotSelected,410,254,210,60);
myButton.setFont(new Font("Tiresias",1,20));
myButton.setVisible(true);
myButton.repaint();

만화를 좋아하시는 분이라면 ... 웹에 존재하는 이미지를 보시는 경우가 있는데 이미지가 가령...
1.jpg , 2.jpg 이런식으로 이어지는 경우라면 일일이 마우스 우클릭하고 다른이름 저장 하고 다운 받는 것은 귀찮자나요.. -_-
그렇다고 해서 한페이지 씩 클릭하면서 보는 경우도 귀찮구 그냥 좀 기달렸다가 한번에 모든 이미지를 보고 싶은 경우가 있는데... 그럴때 사용하면 나름 괘안을거 같아요 .. 흠


대충 만들은 것인지라 보시고 자신에 취향에 맞게 수정하여 쓰시면 될거 같아요.. 아니면 뭐 다른 프로그램 다운 받아서 사용하셔도 되는데 그 프로그램 이름이 기억 안나서 ㅜㅜ 아.. 이 망할 기억력 ;;;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class ImageDownload {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  new ImageDownload();
 }

 public ImageDownload()
 {
  int len = 43;
  for(int i=3;i<len;i++){
    downloadFromUrl("http://194.100.19.194/3172%2F3_PHMZH%2Faki-sora_v01_c003-aki_sora_itosugi_masahiro_chapter003_"+getNum(i)+"-png","C:\\test\\"+getNum(i)+".jpg"); 
  }
 }
 
 private String getNum(int num)
 {
  if(num<10) return "0"+num;
  return ""+num;
 }
 
 public void downloadFromUrl(String imageURL, String fileName)
 {
  try
  {
   URL url = new URL(imageURL);
   URLConnection ucon = url.openConnection();
   InputStream is = ucon.getInputStream();
   
   FileOutputStream fos = new FileOutputStream(fileName);
   
   BufferedInputStream bis = new BufferedInputStream(is);
   BufferedOutputStream bos = new BufferedOutputStream(fos);
   
   int len=0;
   byte[]buf = new byte[1024];
   while((len=bis.read(buf,0,1024))!=-1){
    bos.write(buf,0,len);
   }
   
   //close
   bos.close();
   bis.close();
   fos.close();
   is.close();
   
  }
  catch(Exception e)
  {
   System.out.print(e);
  }
 }
}


만든목적 :
1. 다량의 이미지를 한번에 로딩하자
2. 로딩시 순차적으로 이미지를 보여주자.
3. 프로그래스 바 표현을 해주자

이런 목적으로 제작 했습니다. 사용은 그냥 잘 쓰시면 됩니다.(수정 맘대로 하셔도 됨)

===> 자세한 내용은 첨부 파일을 참조하기 바랍니다.



테스트 이미지 (순차적으로 이미지를 한번에 로딩 할 수 있음 ㅋㅋㅋㅋㅋ)
==> 10 읽어들인 이미지 개수임.



테스트 코드

<?xmlversion="1.0" encoding="utf-8"?>

<mx:Application

       backgroundColor="#ffffff"

       creationComplete="init()"

       xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

       <mx:Script>

             <![CDATA[

                   

                    importmx.controls.Image;

                    importwonsama.info.ImageLoaderInfo;

                    importwonsama.event.ImageLoaderEvent;

                    importwonsama.loader.ImageLoader;

                    importmx.containers.Canvas;

                   

                    /**

                     * 초기화

                     * */

                    private function init():void{

                          

                           //테스트용 이미지 주소 생성 ==> 배열에 삽입

                           var imgArr:Array = new Array;

                           for(var i:uint=0;i<10;i++){

                                 var imgSource:String = "assets/img/number/0"+i+".png";

                                 imgArr.push(imgSource);

                           }

                          

                           //이미지 로더 생성 이벤트 등록

                           var loader:ImageLoader = newImageLoader;

                           loader.loadImages(imgArr);

                           loader.addEventListener(ImageLoaderEvent.UPDATE_PROGRESS,imageProgressHandler);

                           loader.addEventListener(ImageLoaderEvent.COMPLETE_LOAD,imageCompleteHandler);

                    }

                   

                    /**

                     * 이미지가 1 로딩 완료가 되었을 발생하는 이벤트 핸들러

                     * @param e 이미지 로더 이벤트

                     * */

                    private function imageProgressHandler(e:ImageLoaderEvent):void{

                          

                           //일반적으로  프로그래스 처리 내용이 들어가면 될거 같음

                          

                           var info:ImageLoaderInfo = e.info as ImageLoaderInfo;

                           txtInfo.text =String(info.countSuccess);

                    }

                   

                    /**

                     * 이미지가 모두 로딩 완료가 되었을 발생하는 이벤트 핸들러

                     * @param e 이미지 로더 이벤트

                     * */

                    private function imageCompleteHandler(e:ImageLoaderEvent):void{

                          

                           //일반적으로 로딩된 이미지를 보여주는 처리를 하면 될거 같음

                          

                           var info:ImageLoaderInfo = e.info as ImageLoaderInfo;

                          

                           for(var s:String ininfo.loadImgArr){

                                 var imgLoad:Image = info.loadImgArr[s];

                                 if(imgLoad==null){

                                        //기본 이미지 삽입

                                        //main.addChild("기본이미지");

                                 }

                                 else{

                                        main.addChild(imgLoad);

                                 }

                           }                               

                    }

                   

             ]]>

       </mx:Script>

       <mx:Label id="txtInfo"fontFamily="굴림"fontSize="12"/>

       <mx:HBox id="main"width="100%" height="100%"/>

      

</mx:Application>

'etc > old' 카테고리의 다른 글

[AS3.0] Shallow copy 와 Deep copy  (0) 2009.07.07
아이온을 넷북에서 즐긴다?  (0) 2009.07.03
아이폰, '외산폰 무덤인 한국'서 통할까?  (0) 2009.07.02
미리보기 켄버스  (0) 2009.07.01
Fixed Size of a Pie Chart  (0) 2009.07.01

package wonsama.util.image

{

       import flash.display.IBitmapDrawable;

       import flash.net.URLRequest;

       import flash.net.URLVariables;

      

       import mx.graphics.ImageSnapshot;

       import mx.graphics.codec.PNGEncoder;

      

       /**

        * 화면 캡춰를 도와주는 유틸 클래스

        * */

       public final class WCapture

       {

            

             private static const _targetUrl:String = "http://localhost:8080/blazeds/web/imageProcess.jsp";

            

             /**

              * 지정한 UIComponent 화면 캡춰한다.

              * 기본적으로 설정된 서버 주소를 참조

              * @param target 스샷을 찍을 대상체(UIComponent여야 함에 유의)

              * @param targetUrl 값을 전송할 URL

              * */

             public static function takePicture(target:IBitmapDrawable,targetUrl:String=_targetUrl):void{

                   

                    var onSnapShot:ImageSnapshot = ImageSnapshot.captureImage(target);

                    ImageSnapshot.defaultEncoder = mx.graphics.codec.PNGEncoder;       //JPEGEncoder 화질이 떨어짐.75%부터 동작유의

                    var url:URLRequest = new URLRequest(targetUrl);

                                       

                    var params:URLVariables = new URLVariables();

                    params.imageData = ImageSnapshot.encodeImageAsBase64(onSnapShot);       //64Base 인코딩한 것을 파라미터로 설정한다.

                   

                    url.method = "POST";

                    url.data = params;

                    flash.net.navigateToURL(url,'_self');

             }

      

}

=====> 아래글은 참조 원문입니다. 감사합니다 쿠노기 님 ^^

[출처] 간단한 이미지 캡쳐 소스 - Flex 3.0 [JSP] (FlexComponent) |작성자 쿠노기

============================================================================

ImageCapture.mxml

============================================================================

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
  initialize="System.useCodePage=true" width="669" height="393">
 <mx:Script>
  <![CDATA[

   import mx.collections.ArrayCollection;
   import mx.graphics.ImageSnapshot;
   import mx.graphics.codec.*;


   [Bindable]
       public var expenses:ArrayCollection = new ArrayCollection([
          {Month:"Jan", Profit:2000, Expenses:1500},
          {Month:"Feb", Profit:1000, Expenses:200},
          {Month:"Mar", Profit:1500, Expenses:500}
       ]);
      
   private function doCapture():void{
    ImageSnapshot.defaultEncoder =  PNGEncoder;   //defaultEncoder 의 codec 타입을 jpeg로 했더니 화질이 좀 깨져버리네용...
    var onSnapShot:ImageSnapshot = ImageSnapshot.captureImage(myChartVBox);    //걍 챠트를 캡펴했더니 배경이 검게 나와서리 VBOX에 챠트를 넣고 VBOX를 캡쳐 했습니당..
    encodeType.text = onSnapShot.contentType;
    myTextarea.text = ImageSnapshot.encodeImageAsBase64(onSnapShot);
    //myTextarea.text = onSnapShot.contentType;

   }

   private function  sendChartImageToJsp():void{
    doCapture();
    var url:URLRequest = new URLRequest("http://{서버}/decoding.jsp");
    var params:URLVariables = new URLVariables();
    params.test = myTextarea.text;
    url.method = "POST";
    url.data = params;
    navigateToURL(url,'_self');
   }
  ]]>
 </mx:Script>
 <mx:Button x="10" y="337" label="캡쳐" click="doCapture()"/>
 <mx:TextArea x="10" y="191" id="myTextarea" width="558" height="108"/>
 <mx:TextInput x="10" y="307" width="558" id="encodeType"/>
 <mx:Button x="66" y="337" label="Send" click="sendChartImageToJsp()"/>
 <mx:VBox x="10" y="10" width="558" height="173" backgroundColor="#FFFFFF" id="myChartVBox">
  <mx:ColumnChart id="myChart" dataProvider="{expenses}" width="558" height="173" showDataTips="true">
      <mx:horizontalAxis>
         <mx:CategoryAxis  categoryField="Month"/>
      </mx:horizontalAxis>
      <mx:series>
         <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" />
         <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" />
      </mx:series>
   </mx:ColumnChart>
 </mx:VBox>
 
</mx:Application>

============================================================================

decoding.jsp    /서버단 jsp 코딩...초 간당....

============================================================================

<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>

<%@ page import="java.io.*" %>
<%@ page import="sun.misc.*" %>                  //sun.misc.BASE64Decoder 사용
<%
String str=request.getParameter("test");
OutputStream outs = null;
try{
// 쿠키 등의 정보를 지우므로 이전에 세팅을 해서는 않된다네요...^^ 
     response.reset(); 
     response.setContentType("application/smnet");
     response.setHeader("Content-Disposition","attachment; filename=capture.png");     //filename에 원하는 저장 파일의 이름을 ..확장자는 .png로 주세요
     response.setHeader("Content-Transfer-Encoding", "binary;");
     response.setHeader("Pragma", "no-cache;");
     response.setHeader("Expires", "-1;");


     BASE64Decoder decode= new BASE64Decoder(); 
     byte[] bt= decode.decodeBuffer(str);
     outs = response.getOutputStream();
     outs.write(bt);
     outs.close();
}finally{
     outs.close();
}
%>


[ JSP 코딩 참조사항 ]
outs = response.getOutputStream();  라인을
OutputStream outs = null; 아래 바로 적어주면 getOutputStream()을 또 호출했습니다. 라는 Exception이 발생하지 않게 됩니다.


+ Recent posts