2008/10/29 19:46
[컴퓨터]
MacRuby(rubycocoa도 포함)는 Objective-C와 달리 콘솔에서 바로 명령을 내리고 결과를 볼 수 있어서 클래스나 컨트롤의 사용법을 익히기에 좋습니다. 이번에는 이미지의 리사이즈, thumbnail 만들기에 도전해 보겠습니다.
어떤 툴이거나 보통 thumbnail은 원본 파일을 읽어들이고 작은 크기의 thumbnail 이미지를 만든 다음 원본 파일을 thumbnail에 그려넣고 저장하는 순서로 이루어집니다. OSX에서 thumbnail을 만드는 방법은 크게 Cocoa의 NSImage를 사용하는 것과 Quartz의 CoreImage를 사용하는 방법이 있습니다. NSImage가 더 나중의 방법이고 내부적으로는 아마 core image를 사용하는 것 같습니다.
먼저 원본이미지를 읽어들입니다.
이제 작은 크기의 thumbnail을 만듭니다. 엄청나게 긴 함수이름을 가지고 있습니다.
다음 2행은 graphics context를 thumbnail의 것으로 만들고 원본 이미지를 thumbnail 크기로 그려넣습니다. Graphics context를 thumbnail의 것으로 지정하면 image에서의 그림 그리기가 thumbnail에 이루어집니다.
이제 그려진 thumbnail을 파일로 저장합시다.
다음은 그 결과물입니다.

그림이 작아지기는 했습니다만 영 거칠고 화질이 좋지 않습니다. 건물벽도 이상하게 보이네요.
이미지의 크기를 확인해 봅시다.
원본은 3648, 2736 크기의 사진입니다. Cocoa에서는 픽셀단위를 사용하지 않고 출력 device, window, view에 따라 다른 단위를 사용합니다. 우리는 비트맵 단위로 다루고 싶으므로 다음과 같은 방법을 써서 크기를 원본으로 맞추어 줍니다.
이후 결과물은 다음과 같습니다.

거의 차이가 없네요. 그림을 그릴때 화질을 조절하는 옵션이 있습니다. 속도는 조금 느리더라도 더 좋은 화질을 얻도록 합시다.
마지막 결과물...

이제야 볼만한 그림이 나온것 같네요.
NSBitmapImageRep 인스턴스의 메소드 representationUsingType은 JPEG이외에 TIFF, BMP, GIF, PNG 그리고 JPEG2000까지 지원해줍니다. 그리고 properties 인자에 이미지의 옵션을 지정해 줄 수 있습니다. 예를 들어 JPEG의 화질을 95%로 하고 싶다면 인자로 { NSImageCompressionFactor => 0.95 }를 주면 됩니다.
다음은 전체 소스입니다.
어떤 툴이거나 보통 thumbnail은 원본 파일을 읽어들이고 작은 크기의 thumbnail 이미지를 만든 다음 원본 파일을 thumbnail에 그려넣고 저장하는 순서로 이루어집니다. OSX에서 thumbnail을 만드는 방법은 크게 Cocoa의 NSImage를 사용하는 것과 Quartz의 CoreImage를 사용하는 방법이 있습니다. NSImage가 더 나중의 방법이고 내부적으로는 아마 core image를 사용하는 것 같습니다.
먼저 원본이미지를 읽어들입니다.
framework 'Cocoa'
img = NSImage.alloc.initWithContentsOfFile("파일이름")
img = NSImage.alloc.initWithContentsOfFile("파일이름")
이제 작은 크기의 thumbnail을 만듭니다. 엄청나게 긴 함수이름을 가지고 있습니다.
thumb = NSBitmapImageRep.alloc.initWithBitmapDataPlanes(nil,
:pixelsWide=>200.0, :pixelsHigh=>150.0,
:bitsPerSample=>8, :samplesPerPixel=>4, :hasAlpha=>true, :isPlanar=>false,
:colorSpaceName=>NSDeviceRGBColorSpace, :bytesPerRow=>0, :bitsPerPixel=>0)
pixelsWide, pixelsHigh에서 thumbnail의 넓이와 높이를 지정합니다.:pixelsWide=>200.0, :pixelsHigh=>150.0,
:bitsPerSample=>8, :samplesPerPixel=>4, :hasAlpha=>true, :isPlanar=>false,
:colorSpaceName=>NSDeviceRGBColorSpace, :bytesPerRow=>0, :bitsPerPixel=>0)
다음 2행은 graphics context를 thumbnail의 것으로 만들고 원본 이미지를 thumbnail 크기로 그려넣습니다. Graphics context를 thumbnail의 것으로 지정하면 image에서의 그림 그리기가 thumbnail에 이루어집니다.
NSGraphicsContext.setCurrentContext(NSGraphicsContext.graphicsContextWithBitmapImageRep(thumb))
img.drawInRect([0.0, 0.0, 200.0, 150.0], :fromRect=>NSZeroRect, :operation=>NSCompositeCopy, :fraction=>1.0)
콘솔에서 실행시키면 두번째 명령에서 에러가 발생합니다. XCode에서 Button의 핸들러 같은 곳에서 실행시켜 프로그램이 돌아가는 윈도우를 만들어주어야 에러가 발생하지 않습니다.img.drawInRect([0.0, 0.0, 200.0, 150.0], :fromRect=>NSZeroRect, :operation=>NSCompositeCopy, :fraction=>1.0)
이제 그려진 thumbnail을 파일로 저장합시다.
jpg = thumb.representationUsingType(NSJPEGFileType, :properties=>nil)
jpg.writeToFile("썸네일 파일이름", :atomically=>false)
jpg.writeToFile("썸네일 파일이름", :atomically=>false)
다음은 그 결과물입니다.
그림이 작아지기는 했습니다만 영 거칠고 화질이 좋지 않습니다. 건물벽도 이상하게 보이네요.
이미지의 크기를 확인해 봅시다.
>> img.size
=> #<NSSize width=836.484069824219 height=627.363037109375>
=> #<NSSize width=836.484069824219 height=627.363037109375>
원본은 3648, 2736 크기의 사진입니다. Cocoa에서는 픽셀단위를 사용하지 않고 출력 device, window, view에 따라 다른 단위를 사용합니다. 우리는 비트맵 단위로 다루고 싶으므로 다음과 같은 방법을 써서 크기를 원본으로 맞추어 줍니다.
img_bitmap = img.bestRepresentationForDevice(nil)
img.setSize([img_bitmap.pixelsWide, img_bitmap.pixelsHigh])
img.setSize([img_bitmap.pixelsWide, img_bitmap.pixelsHigh])
이후 결과물은 다음과 같습니다.
거의 차이가 없네요. 그림을 그릴때 화질을 조절하는 옵션이 있습니다. 속도는 조금 느리더라도 더 좋은 화질을 얻도록 합시다.
NSGraphicsContext.currentContext.setImageInterpolation(NSImageInterpolationHigh)
마지막 결과물...
이제야 볼만한 그림이 나온것 같네요.
NSBitmapImageRep 인스턴스의 메소드 representationUsingType은 JPEG이외에 TIFF, BMP, GIF, PNG 그리고 JPEG2000까지 지원해줍니다. 그리고 properties 인자에 이미지의 옵션을 지정해 줄 수 있습니다. 예를 들어 JPEG의 화질을 95%로 하고 싶다면 인자로 { NSImageCompressionFactor => 0.95 }를 주면 됩니다.
다음은 전체 소스입니다.
def makeThumb(sender)
NSGraphicsContext.saveGraphicsState
img = NSImage.alloc.initWithContentsOfFile("test.jpg")
img_bitmap = img.bestRepresentationForDevice(nil)
img.setSize([img_bitmap.pixelsWide, img_bitmap.pixelsHigh]);
thumbrect = [0.0, 0.0, 200.0, 150.0]
thumb = NSBitmapImageRep.alloc.initWithBitmapDataPlanes(nil,
:pixelsWide=>thumbrect[2], :pixelsHigh=>thumbrect[3],
:bitsPerSample=>8, :samplesPerPixel=>4, :hasAlpha=>true, :isPlanar=>false,
:colorSpaceName=>NSDeviceRGBColorSpace, :bytesPerRow=>0, :bitsPerPixel=>0)
NSGraphicsContext.setCurrentContext(NSGraphicsContext.graphicsContextWithBitmapImageRep(thumb))
NSGraphicsContext.currentContext.setImageInterpolation(NSImageInterpolationHigh)
img.drawInRect(thumbrect, :fromRect=>NSZeroRect, :operation=>NSCompositeCopy, :fraction=>1.0)
jpg = thumb.representationUsingType(NSJPEGFileType, :properties=>nil)
jpg.writeToFile("test_200.jpg", :atomically=>false)
NSGraphicsContext.restoreGraphicsState
end
NSGraphicsContext.saveGraphicsState
img = NSImage.alloc.initWithContentsOfFile("test.jpg")
img_bitmap = img.bestRepresentationForDevice(nil)
img.setSize([img_bitmap.pixelsWide, img_bitmap.pixelsHigh]);
thumbrect = [0.0, 0.0, 200.0, 150.0]
thumb = NSBitmapImageRep.alloc.initWithBitmapDataPlanes(nil,
:pixelsWide=>thumbrect[2], :pixelsHigh=>thumbrect[3],
:bitsPerSample=>8, :samplesPerPixel=>4, :hasAlpha=>true, :isPlanar=>false,
:colorSpaceName=>NSDeviceRGBColorSpace, :bytesPerRow=>0, :bitsPerPixel=>0)
NSGraphicsContext.setCurrentContext(NSGraphicsContext.graphicsContextWithBitmapImageRep(thumb))
NSGraphicsContext.currentContext.setImageInterpolation(NSImageInterpolationHigh)
img.drawInRect(thumbrect, :fromRect=>NSZeroRect, :operation=>NSCompositeCopy, :fraction=>1.0)
jpg = thumb.representationUsingType(NSJPEGFileType, :properties=>nil)
jpg.writeToFile("test_200.jpg", :atomically=>false)
NSGraphicsContext.restoreGraphicsState
end
