본문 바로가기


비트맵 드라이버 만들기

How to write a bitmap driver
비트맵 드라이버 만들기

Posted Tuesday, February 21, 2006 5:44 PM by ashwinn
번역 2008년 2월 22일 by DwYoon

It didn't take much for me to come up with the topic for my first blog post. If I only had a penny for the number of times I have seen questions on writing bitmap drivers. So here goes...

첫 블로그 포스트를 뭘로 할지 결정하는 건 쉬웠다. 비트맵 드라이버를 어떻게 만드냐는 질문을 자주 봤다. 자, 이제 그 답변이다.

The best approach for writing a bitmap driver is to write a rendering plugin that implements IPrintOemUni::ImageProcessing. This is the same approach used in the bitmap driver sample that is part of the Windows Driver Kit in Windows Vista.

비트맵 드라이버를 만드는 가장 좋은 방법은 IPrintOemUni::ImageProcessing 을 구현한 랜더링 플러그인을 만드는 것이다. 윈도우 비스타 WDK 의 샘플 비트맵 드라이버의 접근법과 같다.

Firstly, let me mention some details about the IPrintOemUni::ImageProcessing method. The ImageProcessing callback is called quite early in the Unidrv rendering code path. It can be used to modify bitmap data, perform color formatting or halftoning. But implementors of this method should be aware that very little processing would have been done by Unidrv before this method is called. So if you are looking for post-processing of the data, IPrintOemUni::FilterGraphics is the method for you. More on FilterGraphics on another day. So coming back to ImageProcessing, some of the important points to remember while implementing it are:
IPrintOemUni::ImageProcessing 메소드에 대해 우선 몇가지 좀 집고 넘어가자. Unidrv 랜더링 코드 경로에서 ImageProcessing 콜백은 꽤 일찍 호출된다. 비트맵 데이터의 변경, 컬러포매팅, 해프토닝을 하는 데 사용될 수 있다. 그러나 이걸 구현하는 프로그래머는 이 메소드가 불리기 전까지 Unidrv가 거의 아무짓도 하지 않는다는 점을 명심할 필요가 있다. 그러니까 데이터의 포스트 프로세싱을 찾는 거라면, IPrintOemUni::FilterGraphics가 바로 찾는 메소드일 것이다. FilterGraphics에 대한 건 나중에 또 이야기 하자. ImageProcessing 으로 돌아가서, 이 메소드를 구현할 때 기억해 둬야 할 중요한 포인트들은 다음과 갈다.


  • Set DevBPP and DevNumOfPlanes to 0 in the GPD.
  • Set IPCallbackID to a non-zero number
  • return TRUE for *ppbResult in ImageProcessing. (*ppbResult = (LPBYTE)(INT_PTR)(TRUE);)
  • If you don't set DevNumOfPlanes and DevBPP to zero, it will totally mess things up unless you actually pass back a pointer instead of TRUE.


  • GPD에서 DevBPP와 DevNumOfPlanes를 0으로 설정하라.
  • IPCallbackID를 0이 아닌 값으로 설정하라.
  • ImageProcessing에서 *ppbResult에 TRUE를 반환하라.  (*ppbResult = (LPBYTE)(INT_PTR)(TRUE);)
  • DevNumOfPlanes와 DevBPP를 0으로 설정하지 않았을 때에는, TRUE 대신에 실제 포인터를 넘겨주지 않으면 완전히 엉망이 되어 버린다.

I think that should suffice for ImageProcessing. I will think about a more detailed post that discusses just ImageProcessing.

이거면 ImageProcessing을 쓰는데 충분할 것이다. ImageProcessing만을 다루는 좀 더 자세한 포스팅을 고려해 보겠다.
So coming back to the bitmap sample, it implements the ImageProcessing callback in order to get access to bitmap data one band at a time. The sample's implementation buffers the band data every time it is called. The ImageProcessing implementation in the sample is also responsible for filling in the BITMAPINFOHEADER and COLORTABLE structures that are necessary for dumping the data out to a bitmap file. In a nutshell, the ImageProcessing method does the processing required to get to a point where we can dump the bitmap data out to file.

비트맵 샘플로 돌아와서, 비트맵 데이터를 한번에 한 밴드씩 접근하기 위해서 ImageProcessing 콜백을 구현한다. 샘플의 구현물은 호출될 때마다 그 밴드의 데이터를 버퍼링한다. 샘플의 ImageProcessing 구현물은 BITMAPINFORHEADER와 COLORTABLE 구조체도 채워서 데이터를 비트맵 파일로 덤프한다. 략하면, ImageProcessing 메소드는 비트맵을 파일로 덤프할 수 있게까지의 과정을 해준다.

This task of dumping the bitmap data to file is done by implementing the OEMEndDoc DDI hook. This results in all the pages being part of a single output bitmap file. If you wanted each page saved as a separate bitmap file, you should perform the dumping of the bitmap data using the OEMEndPage DDI hook.

비트맵 데이터를 파일로 덤프하는 일은 OEMEndDoc DDI 훅으로 구현된다. 그래서 모든 페이지가 하나의 비트맵 파일로 만들어지는 결과를 가져온다. 각 페이지를 하나의 비트맵으로 저장하고 싶다면, 덤프를 OEMEndPage DDI 훅에서 해야 한다.
Apart from implementing ImageProcessing and OEMEndDoc/OEMEndPage, we also need to take care of color byte-order in the case of 24bpp.

ImageProcessing과 OEMEndDoc/OEMEndPage 를 구현하는 것 이외에, 24bpp의 경우 바이트 오더에도 신경을 써야 한다.

In the case of 24bpp, the source bitmap data that you receive in ImageProcesing will have a color order of PRIMARY_ORDER_CBA. In other words, moving from low memory addresses to high memory addresses, there are eight bits of blue data, then eight bits of green data, and then eight bits of red data, after which the pattern repeats. This is also known as BGR device output order. In order to avoid having to do color byte-order manipulation, the plugin should ask GDI to use a BGR palette. This is done at OEMEnablePDEV time.

24bpp의 경우 ImageProcessing에서 받는 소스 비트맵 데이터는 PRIMARY_ORDER_CBA 의 컬러오더로 되어 있다. 무슨 말인고 하면, 낮은 메모리 주소에서 높은 메모리 주소로 올라가면서, 8비트 파란색 데이터, 8비트 초록색 데이터, 그리고 마지막 8비트 빨강색 데이터가 놓여있다. 이런 순서는 BGR 장치 출력 오더로도 알려져 있다. 캘러 바이트-오더 조작을 하지 않으려면, 플러그인은 GDI에게 BGR 팔레트를 사용하도록 요청해야 한다. 이것은 OEMEnablePDEV 에서 이루어진다.

// Create a BGR palette for 24bpp to avoid color byte order manipulation
if (pGdiInfo->cBitsPixel == 24)
    pDevInfo->hpalDefault = EngCreatePalette(PAL_BGR, 0, 0, 0, 0, 0);

Ideally, I would like to paste snippets of code from the bitmap sample here. But since the snippets span many files including the GPD, I am not sure if I can capture all the necessary information in the form of snippets. So I am afraid, I will have to refer you to the WDK if you want the full code.

비트맵 샘플의 코드조각을 붙여놓고 싶다. 하지만, 샘플은 GPD까지 포함해서 많은 파일에 널려 있어서, 필요한 정보를 코드조각의 형태로 캡쳐할 수 있을지 확신이 안 섰다. 미안하지만, 전체 코드를 보려면 WDK를 참고하도록 조언할 수 밖에 없다.

Hope this puts to rest many of the questions regarding bitmap drivers. 

이 포스팅이 비트맵 드라이버에 관련된 수많은 질문들을 잠재울 수 있길 바란다.