[iOS] 이미지 회전하기

iOS에서 이미지를 화면에 표시하는 방법 중 2가지에 대해 정리해 봅니다. 첫번째는 UIView를 상속 받아 drawRect 함수를 재정의해 이미지를 직접 그리는 방식, 두번째는 이미지를 표시하는 UIImageView 컨트롤을 이용하는 방식입니다.

먼저 첫번째 방식인 UIView를 상속받아 drawRect 함수를 재정의해 이미지를 그리는 방식입니다. 여타 다른 코드는 소스 코드에 대한 첨부 파일을 살펴보면 될 것이고… 중요한 drawRect 함수만을 살펴보면 다음과 같습니다.
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
        
    UIImage *img = [UIImage imageNamed:@"goon.png"];
    CGSize imgSize = [img size];

    static CGFloat angle = 0;
    angle += 5;
    CGFloat imgWidth = imgSize.width/1.5;
    CGFloat imgHeight = imgSize.height/1.5;
    CGFloat x = 80;
    CGFloat y = 120;
    
    CGRect rc = CGRectMake(x, y, imgWidth, imgHeight);
    
    CGContextTranslateCTM(context, imgWidth/2+x, imgHeight/2+y);
    CGContextRotateCTM(context, angle * M_PI/180);
    CGContextTranslateCTM(context, -imgWidth/2-x, -imgHeight/2-y);
    
    [img drawInRect:rc];
}

이미지 회전에 대해서 인지해야할 코드만을 설명드리면 8번의 angle 값이 회전값입니다. 그리고 12번과 13번 코드는 이미지를 표시할 화면상의 좌표입니다. 17번 ~ 19번 코드가 실제 이미지를 회전시키기 위한 코드로써 이미지를 중심으로 회전하기 위해 이동 변환과 회전 변환 다시 역이동 변환을 수행하고 있습니다. 이렇게 하면 다음처럼 화면에 이미지가 표시됩니다.

사용자 삽입 이미지
GooN이라는 버튼을 누르면 이미지가 5도씩 회전됩니다. 코드중 angle 변수를 static으로 지정한 이유가 바로 회전 각도 값을 유지하기 위함이였습니다.
이제 두번째로 UIImageView를 통해 이미지를 표시하고 회전해 보는 코드를 살펴보겠습니다. 일단 .xib 파일을 편집해 UI 단에 UIImageView 컨트롤을 원하는 위치에 배치하고 이 컴포넌트에 이미지 파일을 지정하면 쉽게 이미지를 표현할 수 있습니다. 이제 여기서 버튼을 클릭하면 이미지를 회전하는 코드를 살펴보면 다음과 같습니다.
-(IBAction)rotateAction:(id)sender
{
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:3];
    
    CGAffineTransform rotateTransform =
        CGAffineTransformMakeRotation(angle * M_PI / 180);
    
    angle = (angle == 180 ? 360 : 180);
    imageView.transform = rotateTransform;
    
    [UIView commitAnimations];
}

보시면 앞서 살펴본 첫번째 방법처럼 단순히 회전된 상태의 이미지를 화면에 찍는 것이 아닌 애니메이션 효과를 주어서 이미지를 회전시키고 있습니다. 이게 바로 UIImageView와 같은 컨트롤을 통해 이미지를 표현하는 가장 큰 장점입니다. 코드도 훨씬 간결하구요 !! 🙂 실행 결과는 첫번째에서 소개한 실행 화면과 동일하므로 생략하겠습니다. 차이점은 애니메이션을 통해 이미지가 회전된다는 것입니다.

끝으로 첫번째 방법과 두번째 방법에 대한 XCode 프로젝트에 대한 전체 소스 코드를 첨부합니다.

firstMethod.zip 파일이 UIView의 drawRect 함수의 재정의를 통해 이미지를 회전해 표시하는 것이고 secondMethod.zip 파일이 UIImageView 컨트롤을 이용해 이미지를 회전하는 것입니다.

Apache Commons IO 라이브러리

아파치 소프트웨어 재단에서 제공하는 자바 기반의 오픈소스 중  Commons IO 라이브러리가 있습니다. 얼마전 고객과의 미팅을 통해 요구사항을 파악하던 중.. 예상치 못한 기능을 요청받았고 이 기능을 기존 시스템에 추가하려면 상당한 코딩을 해야 할 상황에서 요긴하게 사용한 라이브러리 중에 하나입니다.

사용자 삽입 이미지
이  Commons IO 라이브러리는 기존의 JDK에서 제공하는 클래스들에 대해서 자주 사용하는(Commons 한) 기능들을 클래스화 해 놓은 것으로 이해하면 크게 틀리지 않습니다. 물론 기존의 JDK에서 제공되는 클래스들에 대해 보다 개선된 클래스를 제공하고 있기는 하지만 말입니다.

이 글은 Commons IO 라이브러리의 공식 홈페이지에서 매우 간단한 예제를 통해 해당 라이브러리를 소개하고 있는 글을 한글로 정리한 것입니다. 사실.. 제가 이 Commons IO를 직접 사용한것이 아니고 대용량 파일을 서버로 업로드하는 기능을 제공하는 아파치 소프트웨어 재단에서 제공하는 또 다른 Commons Fileupload 라이브러리에서 이 Commons IO 라이브러리를 사용하는 것을 보고 관심을 가져 보게 되었고 실제 기본적인 내용을 살펴보게 되었습니다.

먼저 해당 URL에 대한 데이터 전체를 문자열로 가져오는 예입니다.

InputStream in = null;
try {
    in = new URL("href='http://www.google.co.kr").openStream();
    System.out.println(IOUtils.toString(in));
} catch (MalformedURLException e) {
     e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(in);
}

JDK에서 제공하는 기본적인 클래스들을 이용해 위의 코드를 작성했다면 더 긴 코드가 필요했을테고.. 코드가 길다는 것은 그만큼 문제가 발생할 가능성이 높다는 것입니다. 아파치의 Commons IO는 수많은 프로그램에서 사용된 검증된 라이브러리입니다.

다음은 텍스트 파일을 라인별로 읽어 List 컨테이너로 파싱하는 예입니다.

File file = new File("c:/text.txt");
try {
    List lines = FileUtils.readLines(file, "utf-8");
    Iterator it = lines.iterator();
    while(it.hasNext()) {
        System.out.println(it.next());
    }
} catch (IOException e) {
    e.printStackTrace();
}

매우 직관적이고 심플합니다.. 하지만 대용량의 텍스트 파일의 경우 모든 데이터를 읽어 하나의 리스트 컨테이너에 집어 넣으니 메모리 문제가 발생할 수 있다는 점을 염두해 둬야 합니다.

다음은 텍스트 파일을 구성하는 라인을 하나 하나 필요할때마다 읽어 처리할 수 있는 예입니다.

File file = new File("c:/text.txt");
LineIterator it = null;
try {
    it = FileUtils.lineIterator(file);
    while(it.hasNext()) {
        System.out.println(it.next());
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(it != null) {
        LineIterator.closeQuietly(it);
    }
}

다음은 파일 경로를 정규화해주는 코드입니다.

 String filename = "c:/commons/io/../../lang/../project.txt";
  String normailzed = FilenameUtils.normalize(filename);
  System.out.println(normailzed);

위 코드의 결과는 c:/project.txt가 됩니다.

그리고 해당 경로에 대한 저장 장치의 가용 용량을 얻는 코드입니다.

try {
    long freeSpace = FileSystemUtils.freeSpaceKb("c:/");
    System.out.println(freeSpace + "kb");
} catch (IOException e) {
    e.printStackTrace();
}

이 외에도 파일의 복사, Endian 처리, 다양한 응용 스트림 클래스 등을 제공합니다. 이 처럼 일반적으로 많이 사용되는 IO 루틴에 대해서 더 짧은 코드를 통해서, 그리고 검증된 방법을 통해 구현할 수 있는 라이브러리를 사용한다면 원하는 기능을 더욱 빠르고 안정적으로 추가 개발할 수 있습니다. 이러한 라이브러리를 미리 알고 있는 것으로 개발자의 역량은 기술면에서 더 높아질 것입니다.

차량의 위험운전행동 정의

차량의 행동 분석에 대한 통계 항목으로 고려될 수 있는 것들.. 정확한 용어 및 내용을 파악할 수 있도록 찬찬히 타이핑하며 암기(ㅡOㅡ;)하는 중..

  • 장기과속 : 과속 상태로 1분 이상 운행한 경우
  • 과속 : 제한속도보다 20km/h를 초과하여 운행한 경우
  • 급감속 : 브레이크를 사용하지 않고 초당 속도가 7.5km/h 이상 감속한 경우
  • 급제동 : 브레이크를 사용하면서 초당 속도가 11km/h 이상 감속된 경우
  • 급정지 : 브레이크를 사용하면서 초당 속도가 7.5km/h 이상 감속하여 차량이 멈춘 경우
  • 급가속 : 속도가 초당 11km/h 이상 가속된 경우
  • 급출발 : 차량이 멈춘 상태에서 출발하여 초당 속도가 11km/h 이상 올라간 경우
  • 앞자르기 : 속도가 초당 11km/h 이상 증가하면서 방위각이 30도 이상 좌우로 변하는 경우
  • 진로변경 : 속도 변화 없이 방위각이 15도 이상 좌우로 변하는 경우
  • 회전 : 15km/h 이상의 속도를 유지하면서 일정시간에 방위각이 좌측 또는 우측 방향으로 60도 이상 변하는 경우