[Deferred] PEP 368 - Standard image protocol and class
원문 링크: PEP 368 - Standard image protocol and class
상태: Deferred 유형: Standards Track 작성일: 28-Jun-2007
PEP 368 – 표준 이미지 프로토콜 및 클래스
- 작성자: Lino Mastrodomenico
- 상태: 연기됨 (Deferred)
- 유형: Standards Track
- 생성일: 2007년 6월 28일
- Python 버전: 2.6, 3.0
요약 (Abstract)
현재 Python 이미지 저장 및 조작 환경은 매우 파편화되어 있습니다. 거의 모든 이미지 관련 라이브러리가 각자의 고유한 이미지 클래스를 구현하고 있으며, 이들은 서로 호환되지 않고 Pythonic하지 않은 경우가 많습니다. 표준 라이브러리에는 기본적인 RGB 이미지 클래스 (Tkinter.PhotoImage
)가 존재하지만, Tkinter 프로그래밍 외에는 거의 사용되지 않고 활용도가 낮습니다.
이러한 파편화는 개발자의 학습 부담을 가중시킬 뿐만 아니라, 여러 라이브러리 간 이미지 교환(비교적 흔한 사용 사례)을 필요 이상으로 느리고 복잡하게 만듭니다.
PEP 368은 간단하고 Pythonic한 이미지 프로토콜/인터페이스를 정의하여 이 문제를 개선하고자 제안되었습니다. 이 프로토콜은 기존 이미지 클래스들이 하위 호환성을 깨뜨리지 않고 표준 라이브러리 내부 및 외부에서 채택하고 구현할 수 있도록 하는 것을 목표로 합니다. 사실상 이는 최소한의 이미지 객체가 어떻게 보이고 작동해야 하는지에 대한 정의입니다(파일류 객체의 read()
및 write()
메서드와 유사).
또한, 이 PEP는 새로운 프로토콜을 구현하고 기본적인 이미지 조작 기능을 제공하는 클래스를 표준 라이브러리에 포함할 것을 제안하며, 기존 이미지 클래스에 프로토콜 지원을 추가하는 데 도움이 되는 믹스인(mixin) 클래스도 함께 제안합니다.
PEP 연기 사유 (PEP Deferral Rationale)
이 PEP에서 다루는 개념에 대한 추가 탐색은 현재 PEP의 목표를 추진하고 피드백을 수집 및 통합하며, 이를 효과적으로 수행할 충분한 시간을 가진 ‘챔피언(champion)’의 부재로 인해 연기되었습니다.
배경 (Rationale)
Python 표준 라이브러리에 포함될 고품질 모듈을 확보하는 좋은 방법은 경쟁하는 외부 라이브러리들 중에서 유용한 기능과 큰 사용자 기반을 가진 확실한 승자가 자연스럽게 선택될 때까지 기다리는 것입니다. 그런 다음 사실상의 표준(de facto standard)을 표준 라이브러리에 포함시켜 공식적으로 승인할 수 있습니다.
그러나 이러한 접근 방식은 Python 세계에서 지배적인 이미지 클래스를 만드는 데 효과적이지 못했습니다. 거의 모든 타사 라이브러리가 이미지 객체를 필요로 할 때 자체 클래스를 만들어 다른 라이브러리의 클래스와 호환되지 않게 만듭니다. 이는 예를 들어, PIL(Python Imaging Library)을 사용하여 이미지를 생성하고 조작한 다음 wxPython 또는 pygame을 사용하여 표시하는 것이 전적으로 합리적인 프로그램에서 실질적인 문제가 됩니다. 하지만 이 라이브러리들은 서로 다른 비호환적인 이미지 클래스를 가지고 있으며, 일반적인 해결책은 원본 이미지에서 (너비, 높이, 바이트 문자열) 튜플로 수동으로 “내보내기”하고 대상 형식으로 새 인스턴스를 생성하여 “가져오기”하는 것입니다. 이 접근 방식은 작동하지만, 필요 이상으로 복잡하고 느립니다.
또 다른 “해결책”은 클래스 간의 특정 어댑터(adapter) 및/또는 변환기(converter)를 만드는 것이었습니다(예: PIL은 PIL 이미지를 Tkinter와 호환되는 클래스로 변환하는 ImageTk 모듈을 제공합니다). 그러나 이 접근 방식은 관련된 라이브러리 수에 따라 확장이 잘 되지 않으며 사용자에게 여전히 번거롭습니다. 완벽하게 좋은 이미지 객체가 있는데, 다음 메서드에 전달하기 전에 왜 변환해야 할까요? 왜 그냥 있는 그대로 내 이미지를 받아들일 수 없을까요?
이 문제는 앞서 언급된 세 라이브러리에만 국한되지 않으며 여러 원인이 있을 수 있습니다. 그 중 두 가지는 이 문제를 해결하기 전에 이해하는 것이 매우 중요합니다.
- 오늘날 컴퓨팅 세계에서 이미지는 특정 도메인에 엄격하게 묶이지 않은 기본 유형입니다. 이것이 앞서 언급된 세 라이브러리(PIL, wxPython, pygame)의 이미지 클래스 간에 확실한 승자가 없을 이유입니다. 이들은 서로 다른 도메인을 다루며 실제로는 서로 경쟁하지 않습니다.
- Python 표준 라이브러리는 타사 모듈이 채택하거나 모방할 수 있는 좋은 이미지 클래스를 제공한 적이 없습니다.
Tkinter.PhotoImage
는 기본적인 RGB 기능을 제공하지만, 가장 느리고 보기 흉하며 Tkinter 루트 창이 생성된 후에만 인스턴스화할 수 있습니다.
이 PEP는 다음 네 가지 방법으로 이 상황을 개선하고자 합니다.
- 새로운 이미지 프로토콜 정의: 기존 이미지 클래스들이 하위 호환성을 깨뜨리지 않고 표준 라이브러리 내부 및 외부에서 채택하고 구현할 수 있는 간단하고 Pythonic한 이미지 프로토콜/인터페이스(Python 및 C 측면 모두)를 정의합니다.
- 표준 라이브러리에 새로운 클래스 포함 제안: 세 가지 새로운 클래스를 표준 라이브러리에 포함할 것을 제안합니다.
ImageMixin
: 새로운 프로토콜을 구현하는 데 필요한 거의 모든 것을 제공합니다. 주요 목적은 기존 라이브러리가 이 인터페이스를 가능한 한 간단하게 지원할 수 있도록 하는 것입니다. 경우에 따라 기본 클래스 목록에 추가하고 생성자에 약간의 추가만 하면 됩니다.Image
:ImageMixin
의 서브클래스이며, 이미지 크기를 조절하고 다른 픽셀 형식 간에 변환할 수 있는 생성자를 추가합니다. 이는 새로운 프로토콜의 빠르고 효율적인 기본 구현을 제공하기 위함입니다.ImageSize
: 사소한 헬퍼 클래스입니다. 자세한 내용은 아래를 참조하세요.
Tkinter.PhotoImage
개선:Tkinter.PhotoImage
가 새로운 프로토콜을 구현하고(대부분ImageMixin
클래스를 통해), 이미지를 받을 수 있는 모든 Tkinter 메서드가 인터페이스를 구현하는 모든 객체를 허용하도록 수정됩니다. 이 PEP의 작성자는 가장 일반적인 외부 라이브러리 개발자들과 협력하여 동일한 목표(클래스에서 프로토콜 지원 및 이를 구현하는 모든 클래스 허용)를 달성할 것입니다.- CPython C API 확장: CPython C API에 새로운
PyImage_*
함수가 추가됩니다. 이 함수들은 프로토콜의 C 측면을 구현하며,Image
/ImageMixin
클래스의 인스턴스가 아니더라도 이를 지원하는 모든 객체를 첫 번째 매개변수로 받아들입니다.
최종 사용자에게 미치는 주요 영향은 다른 라이브러리 간의 이미지 교환이 단순화되고(모든 것이 잘 된다면, 모든 Python 라이브러리가 다른 모든 라이브러리의 이미지를 받아들일 것임) 새로운 Image
클래스를 즉시 사용할 수 있게 되는 것입니다. 이 새로운 클래스는 사진 자르기 및/또는 원하는 크기로 조정하여 창에 표시하기 위한 적절한 위젯에 전달하거나, 텍스처를 어둡게 하여 3D 라이브러리에 전달하는 것과 같은 간단하지만 일반적인 사용 사례를 다루는 것을 목표로 합니다.
Image
클래스는 PIL, Pythonmagick 또는 NumPy를 대체하거나 경쟁하기 위한 것이 아니며, 이 세 라이브러리의 (매우 작은) 기능 하위 집합을 제공하더라도 그러합니다. 특히 PIL은 수십 개의 클래스, 필터, 변환 및 파일 형식으로 매우 풍부한 이미지 조작 기능을 제공합니다. PIL(또는 유사한 것)을 표준 라이브러리에 포함하는 것이 가치 있는 목표일 수도 있고 아닐 수도 있지만, 이는 이 PEP의 범위를 완전히 벗어납니다.
명세 (Specification)
새로운 클래스와 객체를 위한 기본 위치로 imageop
모듈이 사용됩니다. 이 모듈은 오랫동안 다소 유사한 기능을 제공하는 함수들을 호스팅해왔기 때문입니다. 그러나 필요하다면 새로운 모듈(image
또는 media
모듈 등)이 생성될 수도 있습니다. 후자는 결국 다른 멀티미디어 클래스도 포함할 수 있습니다.
MODES
는 새로운 모듈 수준 상수입니다. 이는 Image
클래스에서 지원하는 픽셀 형식의 집합입니다. 새로운 프로토콜을 구현하는 모든 이미지 객체는 이 모드 중 하나로 형식이 지정되도록 보장되지만, 이미지를 받아들이는 라이브러리는 그 중 일부만 지원할 수 있습니다.
이 모드들은 또한 모듈 수준 상수(예: imageop.RGB
)로도 사용 가능합니다.
현재 지원되는 모드 및 그 속성은 다음과 같습니다.
Name | Component names | Bits per component | Subsampling | Valid intervals |
---|---|---|---|---|
L | l | 8 | no | full range |
L16 | l | 16 | no | full range |
L32 | l | 32 | no | full range |
LA | l, a | 8 | no | full range |
LA32 | l, a | 16 | no | full range |
RGB | r, g, b | 8 | no | full range |
RGB48 | r, g, b | 16 | no | full range |
RGBA | r, g, b, a | 8 | no | full range |
RGBA64 | r, g, b, a | 16 | no | full range |
YV12 | y, cr, cb | 8 | 1, 2, 2 | 16-235, 16-240, 16-240 |
JPEG_YV12 | y, cr, cb | 8 | 1, 2, 2 | full range |
CMYK | c, m, y, k | 8 | no | full range |
CMYK64 | c, m, y, k | 16 | no | full range |
모드 이름이 숫자로 끝나는 경우, 이는 픽셀당 평균 비트 수를 나타냅니다. 다른 모든 모드는 픽셀당 구성 요소당 1바이트를 사용합니다. 팔레트 모드 또는 구성 요소당 8비트 미만인 모드는 지원되지 않습니다.
모드에 대한 간략한 설명과 포함 이유는 다음과 같습니다.
- Grayscale (L* 모드): 과학 컴퓨팅에서 많이 사용되며, 높은 동적 범위와 정밀도가 필요한 경우
L32
(구성 요소당 32비트)를 사용합니다. 컬러 이미지의 단일 구성 요소를 그레이스케일 이미지로 간주하는 것이 유용할 수 있습니다. 구성 요소 이름 ‘l’은 휘도(luminance)를 나타내며, 선택적 두 번째 구성 요소 ‘a’는 알파 값으로 픽셀의 불투명도를 나타냅니다. (alpha = 0은 완전 투명, alpha = 255/65535는 완전 불투명). - RGB* 모드: 일반적인 컬러 이미지입니다. 선택적 알파 구성 요소는 그레이스케일 모드와 동일한 의미를 가집니다.
- YCbCr, 일명 YUV (*YV12 모드): 이 모드는 플래너(planar) 방식입니다(각 구성 요소의 모든 픽셀 값이 연속된 메모리 영역에 저장됨). 1, 2, 2 (4:2:0) 서브샘플링을 사용합니다. 각 픽셀은 자체 Y 값을 가지지만, Cb 및 Cr 구성 요소는 2x2 인접 픽셀 그룹 간에 공유됩니다. 이는 YCbCr 이미지에서 가장 흔한 형식이기 때문입니다. V(Cr) 평면이 U(Cb) 평면보다 먼저 저장됩니다.
YV12
는 MPEG2, MPEG4, Theora 비디오 프레임에 일반적으로 사용됩니다. Y의 유효 범위는range(16, 236)
이며, Cb 및 Cr의 유효 범위는range(16, 241)
입니다.JPEG_YV12
는YV12
와 유사하지만, 세 구성 요소 모두 256가지 전체 범위를 가질 수 있습니다. 거의 모든 JPEG/JFIF 파일 및 MJPEG 비디오 프레임에서 사용되는 기본 형식입니다.
- CMYK* 모드 (Cyan, Magenta, Yellow, Black): 감산 혼합 색상 모드로, 인쇄용으로 사용됩니다.
Python API
모드 객체 (Mode Objects)
모드 객체는 여러 유형의 이미지에서 작동하는 일반 알고리즘을 구현하는 데 사용할 수 있는 여러 속성 및 메서드를 제공합니다.
components
: 픽셀당 구성 요소 수 (예: RGBA 이미지의 경우 4).component_names
: 문자열 튜플 (위 표의 “Component names” 참조).bits_per_component
: 8, 16 또는 32.bytes_per_pixel
:components * bits_per_component // 8
, 비플래너 모드에만 사용 가능.planar
: 불리언(Boolean), 이미지 구성 요소가 각각 별도의 평면에 있는 경우True
. 현재는 모드가 서브샘플링을 사용하는 경우에만 해당됩니다.subsampling
: 모드의 각 구성 요소에 대해 가로 및 세로 방향의 다운샘플링 양을 나타내는 두 개의 정수 튜플을 포함하는 튜플.YV12
및JPEG_YV12
의 경우((1, 1), (2, 2), (2, 2))
이며, 그 외의 경우((1, 1),) * components
입니다.x_divisor
:max(x for x, y in subsampling)
. 이 모드를 사용하는 이미지의 너비는 이 값으로 나눌 수 있어야 합니다.y_divisor
:max(y for x, y in subsampling)
. 이 모드를 사용하는 이미지의 높이는 이 값으로 나눌 수 있어야 합니다.intervals
: 모드의 각 구성 요소에 대해 최소 및 최대 유효 값을 포함하는 두 개의 정수 튜플.YV12
의 경우((16, 235), (16, 240), (16, 240))
이며, 그 외의 경우((0, 2 ** bits_per_component - 1),) * components
입니다.get_length(iterable[integer]) -> int
: 너비와 높이를 포함하는 이터러블을 매개변수로 받아, 해당 모드와 크기의 이미지를 저장하는 데 필요한 바이트 수를 반환합니다.
이미지 프로토콜 (Image Protocol)
이미지 프로토콜을 지원하는 모든 객체는 다음 메서드와 속성을 제공해야 합니다.
mode
: 이미지의 픽셀 형식 및 배열.MODES
집합의 상수 중 하나입니다.size
:ImageSize
클래스의 인스턴스. 너비와 높이를 나타내는 두 개의 정수 이름을 가진 튜플입니다. 둘 다 1 이상이어야 하며size.width
및size.height
속성으로도 접근할 수 있습니다.buffer
: 0에서 255 사이의 정수 시퀀스. 이미지 데이터를 저장하는 데 사용되는 실제 바이트입니다. 데이터는 패딩 없이 행 우선/C-contiguous 순서로 저장되며 특별한 메모리 정렬은 없습니다. 지원되는 메서드는__len__
,__getitem__
/__setitem__
(정수 및 슬라이스 인덱스 모두 사용),__iter__
뿐입니다. C 측면에서는 버퍼 프로토콜을 구현합니다.info
: 이미지와 관련된 임의의 메타데이터(예: DPI, 감마, ICC 프로필, 노출 시간 등)를 포함할 수 있는dict
객체.bits_per_component
,bytes_per_pixel
,component_names
,components
,intervals
,planar
,subsampling
: 해당mode.*
속성에 대한 단축키.map(function[, function...]) -> None
: 이미지의 모든 픽셀에 대해 해당 함수를 통해 각 구성 요소를 매핑합니다. 이미지를 인플레이스(in-place)로 수정합니다.rotate90() -> image
,rotate180() -> image
,rotate270() -> image
: 이미지의 사본을 반시계 방향으로 90, 180 또는 270도 회전하여 반환합니다.clip() -> None
:YV12
이미지에서 유효하지 않은 구성 요소 값을 최소 또는 최대 허용 값으로 포화(saturates)시킵니다. 다른 이미지 모드의 경우 아무것도 하지 않습니다.split() -> tuple[image]
: 이미지의 개별 구성 요소에 해당하는L
,L16
또는L32
이미지 튜플을 반환합니다.
비플래너 이미지는 다음 추가 메서드를 제공합니다.
pixels() -> iterator[pixel]
: 이미지의 모든 픽셀을 반복하는 이터레이터를 반환합니다.__iter__() -> iterator[line]
: 이미지의 모든 라인을 반복하는 이터레이터를 반환합니다.__len__() -> int
: 이미지의 라인 수(size.height
)를 반환합니다.__getitem__(integer) -> line
: 지정된 (y) 위치의 라인을 반환합니다.__getitem__(tuple[integer]) -> pixel
: x, y 좌표에 해당하는 픽셀 객체를 반환합니다.__getitem__(slice | tuple[integer | slice]) -> image
: 이미지의 선택된 영역을 복사하고 새 이미지를 반환합니다.__setitem__(tuple[integer], integer | iterable[integer]) -> None
: 지정된 위치의 픽셀을 수정합니다.__setitem__(slice | tuple[integer | slice], image) -> None
: 영역을 선택하고 두 번째 인수의 이미지에서 픽셀 사본을 할당합니다.
Image 및 ImageMixin 클래스 (Image and ImageMixin Classes)
ImageMixin
클래스는 위에서 설명한 mode
, size
, buffer
, info
를 제외한 모든 메서드와 속성을 구현합니다. Image
는 ImageMixin
의 서브클래스로, 이 네 가지 속성에 대한 지원을 추가하고 다음 생성자를 제공합니다.
__init__(mode, size, color, source)
:mode
:MODES
집합의 상수 중 하나여야 합니다.size
: 두 개의 정수(새 이미지의 너비와 높이) 시퀀스입니다.color
: 이미지의 각 구성 요소에 대한 정수 시퀀스로, 모든 픽셀을 동일한 값으로 초기화하는 데 사용됩니다.source
: 적절한 크기 및 형식의 정수 시퀀스로, 새 이미지의 버퍼에 그대로 복사되거나 기존 이미지일 수 있습니다. Python 2.x에서는str
인스턴스도 가능하며 바이트 시퀀스로 해석됩니다.color
와source
는 상호 배타적이며, 둘 다 생략되면 이미지는 투명한 검정(transparent black)으로 초기화됩니다.source
가 존재하고 이미지인 경우,mode
및/또는size
는 생략할 수 있습니다. 지정되고 원본 모드 및/또는 크기와 다른 경우, 원본 이미지가 변환됩니다.
Line 객체 (Line Objects)
라인 객체는 다음 속성 및 메서드를 지원합니다.
mode
: 이 라인이 속한 이미지의 모드.__iter__() -> iterator[pixel]
: 라인의 모든 픽셀을 반복하는 이터레이터를 반환합니다.__len__() -> int
: 라인의 픽셀 수(이미지 너비)를 반환합니다.__getitem__(integer) -> pixel
: 지정된 (x) 위치의 픽셀을 반환합니다.__getitem__(slice) -> image
: 라인의 선택된 부분이 복사되고 새 이미지가 반환됩니다. 새 이미지의 높이는 항상 1입니다.__setitem__(integer, integer | iterable[integer]) -> None
: 지정된 위치의 픽셀을 수정합니다.__setitem__(slice, image) -> None
: 라인의 일부를 선택하고 두 번째 인수의 이미지에서 픽셀 사본을 할당합니다.
Pixel 객체 (Pixel Objects)
픽셀 객체는 다음 속성 및 메서드를 지원합니다.
mode
: 이 픽셀이 속한 이미지의 모드.value
: 각 구성 요소에 대한 정수 튜플.r, g, b, a, l, c, m, y, k
: 각 구성 요소의 정수 값. 현재 모드에 해당하는 것만 사용 가능합니다.__iter__() -> iterator[int]
,__len__() -> int
,__getitem__(integer | slice) -> int | tuple[int]
,__setitem__(integer | slice, integer | iterable[integer]) -> None
: 이 네 가지 메서드는 각 픽셀 구성 요소에 대한 고정 길이 정수 목록을 에뮬레이트합니다.
ImageSize 클래스 (ImageSize Class)
ImageSize
는 named tuple
이며, 다음을 제외하고 tuple
과 동일한 클래스입니다.
- 생성자는 너비와 높이 두 개의 정수만 허용합니다.
width
및height
속성이 있습니다.__repr__
메서드가imageop.ImageSize(width=%d, height=%d)
형식의 문자열을 반환합니다.
ImageSize
는 일반적으로 최종 사용자가 인스턴스화하지 않지만, 이미지 프로토콜을 구현하는 새 클래스를 생성할 때 size
속성이 ImageSize
인스턴스여야 하므로 사용될 수 있습니다.
C API
사용 가능한 이미지 모드는 C 수준에서 PyImage_*
상수(PyObject *
유형, 예: PyImage_RGB
)로 표시됩니다.
다음 함수는 모드 및 이미지 객체에 대한 C 친화적인 인터페이스를 제공합니다 (모든 함수는 실패 시 NULL 또는 -1을 반환합니다).
int PyImageMode_Check(PyObject *obj)
: 객체가 유효한 이미지 모드인지 확인합니다.int PyImageMode_GetComponents(PyObject *mode)
: 모드의 구성 요소 수를 반환합니다.PyObject* PyImageMode_GetComponentNames(PyObject *mode)
: 모드의 구성 요소 이름 튜플을 반환합니다.int PyImageMode_GetBitsPerComponent(PyObject *mode)
: 구성 요소당 비트 수를 반환합니다.int PyImageMode_GetBytesPerPixel(PyObject *mode)
: 픽셀당 바이트 수를 반환합니다.int PyImageMode_GetPlanar(PyObject *mode)
: 모드가 플래너인지 여부를 반환합니다.PyObject* PyImageMode_GetSubsampling(PyObject *mode)
: 모드의 서브샘플링 정보를 반환합니다.int PyImageMode_GetXDivisor(PyObject *mode)
: 모드의 x_divisor를 반환합니다.int PyImageMode_GetYDivisor(PyObject *mode)
: 모드의 y_divisor를 반환합니다.-
Py_ssize_t PyImageMode_GetLength(PyObject *mode, Py_ssize_t width, Py_ssize_t height)
: 주어진 모드, 너비, 높이의 이미지를 저장하는 데 필요한 바이트 수를 반환합니다. int PyImage_Check(PyObject *obj)
: 객체가 Image 객체 또는 Image 유형의 서브타입 인스턴스인지 확인합니다.int PyImage_CheckExact(PyObject *obj)
: 객체가 정확히 Image 객체인지 확인합니다.PyObject* PyImage_New(PyObject *mode, Py_ssize_t width, Py_ssize_t height)
: 새 Image 인스턴스를 반환합니다.PyObject* PyImage_FromImage(PyObject *image, PyObject *mode, Py_ssize_t width, Py_ssize_t height)
: 기존 이미지 객체의 내용으로 새 Image 인스턴스를 반환합니다.PyObject* PyImage_FromBuffer(PyObject *buffer, PyObject *mode, Py_ssize_t width, Py_ssize_t height)
: 버퍼 객체의 내용으로 새 Image 인스턴스를 반환합니다.-
int PyObject_CheckImage(PyObject *obj)
: 객체가 이미지 프로토콜의 충분한 하위 집합을 구현하는지 확인합니다. PyObject* PyImage_GetMode(PyObject *image)
: 이미지의 모드를 반환합니다.Py_ssize_t PyImage_GetWidth(PyObject *image)
: 이미지의 너비를 반환합니다.Py_ssize_t PyImage_GetHeight(PyObject *image)
: 이미지의 높이를 반환합니다.int PyImage_Clip(PyObject *image)
: 이미지의 값을 클립합니다.PyObject* PyImage_Split(PyObject *image)
: 이미지를 구성 요소 이미지로 분할합니다.PyObject* PyImage_GetBuffer(PyObject *image)
: 이미지의 버퍼를 반환합니다.int PyImage_AsBuffer(PyObject *image, const void **buffer, Py_ssize_t *buffer_len)
: 이미지 메모리에 직접 접근할 수 있도록 버퍼 정보를 반환합니다.
예시 (Examples)
새로운 Image
클래스 및 프로토콜을 사용한 일반적인 작업의 몇 가지 예시입니다.
# 6x9 픽셀의 새로운 검은색 RGB 이미지를 생성합니다.
rgb_image = imageop.Image(imageop.RGB, (6, 9))
# 위와 동일하지만 이미지를 밝은 빨간색으로 초기화합니다.
rgb_image = imageop.Image(imageop.RGB, (6, 9), color=(255, 0, 0))
# 이미지를 YCbCr로 변환합니다.
yuv_image = imageop.Image(imageop.JPEG_YV12, source=rgb_image)
# 픽셀 값을 읽고 세 개의 정수로 분할합니다.
r, g, b = rgb_image[x, y]
# CMYK 이미지에서 픽셀의 마젠타(magenta) 구성 요소를 수정합니다.
cmyk_image[x, y].m = 13
# *YV12 이미지에서 픽셀의 Y(휘도) 구성 요소와
# 해당 서브샘플링된 Cr(적색 색차)를 수정합니다.
yuv_image.y[x, y] = 42
yuv_image.cr[x // 2, y // 2] = 54
# 이미지를 반복합니다.
for line in rgb_image:
for pixel in line:
# 빨강과 파랑을 바꾸고 초록을 0으로 설정합니다.
pixel.value = pixel.b, 0, pixel.r
# 이미지에서 빨간색 구성 요소의 최댓값을 찾습니다.
max_red = max(pixel.r for pixel in rgb_image.pixels())
# 이미지의 색상 수를 계산합니다.
num_of_colors = len(set(tuple(pixel) for pixel in image.pixels()))
# 이미지의 오른쪽 상단 모서리 근처의 4x2 픽셀 블록을 복사하여
# 같은 이미지의 왼쪽 하단 모서리에 붙여넣습니다.
image[:4, -2:] = image[-6:-2, 1:3]
# 새 이미지에는 다른 (보통 비어 있는) info dict를 가질 수 있도록
# 이미지의 사본을 생성합니다.
new_image = image[:]
# 좌우가 뒤집힌 미러링된 이미지 사본을 생성합니다.
flipped_image = image[::-1, :]
# 이미지를 원래 크기의 절반으로 다운샘플링합니다.
# 빠르고 낮은 품질의 작업과 느리고 높은 품질의 작업 두 가지 방법입니다.
low_quality_image = image[::2, ::2]
new_size = image.size.width // 2, image.size.height // 2
high_quality_image = imageop.Image(size=new_size, source=image)
# 직접 버퍼 접근
rgb_image[0, 0] = r, g, b
assert tuple(rgb_image.buffer[:3]) == (r, g, b)
하위 호환성 (Backwards Compatibility)
이 PEP가 다루는 세 가지 영역에서 하위 호환성을 고려해야 합니다.
- Python 2.6:
imageop
모듈에 새로운 클래스와 객체가 추가되지만 기존 모듈 내용은 변경되지 않습니다.Tkinter.PhotoImage
에 새로운 메서드와 속성이 추가되고__getitem__
및__setitem__
메서드는 정수, 튜플, 슬라이스를 허용하도록 수정됩니다 (현재는 문자열만 허용). 모든 변경 사항은 기존 기능의 상위 집합을 제공하므로 주요 호환성 문제는 예상되지 않습니다. - Python 3.0: PEP 3108에 따라
imageop
모듈의 레거시 내용은 삭제됩니다. 이 제안에서 정의된 모든 것은 Python 2.x와 동일하게 작동하지만, 일반적인 2.x/3.0 차이점(예: long 정수 지원 및str
인스턴스를 바이트 시퀀스로 해석하는 기능이 제거됨)이 적용됩니다. - 외부 라이브러리: 표준 이미지 메서드 및 속성의 이름과 의미는 이미지 조작 라이브러리(PIL, wxPython, pygame 등)가 기존 코드와의 호환성을 깨뜨리지 않고 새로운 프로토콜을 구현할 수 있도록 신중하게 선택되었습니다. 이미지 프로토콜과 NumPy 배열 간의 유일한 명백한 충돌은
size
속성의 값과image[x, y]
표현식의 좌표 순서입니다.
참조 구현 (Reference Implementation)
이 PEP가 수락되면, 작성자는 순수 Python으로 구현된 새로운 클래스의 참조 구현(CPython, PyPy, Jython, IronPython에서 실행 가능)과 Python 및 C로 속도를 최적화한 두 번째 구현(CPython 표준 라이브러리에 포함하기에 적합)을 제공할 것입니다. 또한 작성자는 필요한 Tkinter 패치도 제출할 것입니다. 모든 코드에 대해 Python 2.x 버전과 Python 3.0 버전이 제공될 것입니다 (두 버전은 매우 유사할 것이며 Python 3.0 버전은 거의 완전히 자동으로 생성될 것으로 예상됩니다).
⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.
Comments