The first part searches for the instances of the Graphics Output protocol in the system, chooses the one where the maze will be displayed and stores a pointer to it in a global variable.
Now that we have found handles for all drivers that support the Graphics Output protocol, we examine each handle to see if it also has an instance of the Device Path protocol. Why? Because the one way to distinguish the Console Splitter from all other graphical devices in the system is that it is not actually a hardware device. Since it is not a hardware device, it does not have a Device Path protocol associated with it, since the Device Path protocol used to describe how a device is attached to the system. If we find a handle that doesn't have an instance, the pointer to that instance of the Graphics Output protocol is saved in a global variable.
Now we just have to clean things up and return. First, we free the buffer that the system allocated when we called LocateHandleBuffer. Then, we check whether we found a Graphics Output protocol instance that meets our need and return TRUE if we did and FALSE if we did not.
Now, in the next section, we're going to dive into the meat of converting a buffer formatted as a Bitmap (BMP) into a format that can be used with the Graphics Output protocol.
|Figure 2 - Converting .bmp Files to Graphics Output format, Bitmap.c|
On entry, this function takes a buffer that is formatted following the BMP format (see here for more information), along with its size. On output, this function returns a pointer to an array of pixels (GopBlt), the size of that buffer in bytes (GopBltSize). The pixels are divided into PixelHeight rows, with each row containing PixelWidth pixels. Each of the output pixels is formatted as a EFI_GRAPHICS_OUTPUT_BLT_PIXEL structure. This structure has 8 bits for red, green and blue, and 8 reserved bits, making 32-bits per pixel.
These are the local variable declarations. BmpHeader and BmpColorMap are pointers to structures that are part of the BMP specification. The EDK2 implementation stores these structures in MdePkg\Include\IndustryStandard\Bmp.h.
A simple sanity check makes sure that the buffer passed in at least has the number of bytes required to hold the standard BMP format header structure.
The color map translates bytes in the bitmap buffer portion of the BMP format into actual colors. The pixels in the bitmap are packed as 1-bit per pixel (2 colors), 4-bits per pixel (16 colors), 8-bits per pixel (256 colors) or the default (24-bits per pixel). The color map translates the bits-per-pixel in the bitmap into actual colors. So 0 might be black, but 1 might be blue (not black) and 2 might be green, etc.
The number of pixels determines the size of the color map. So 1-bit per pixel has two possible color map values (0 and 1) while 4-bits per pixel has 16 possible color map values (0, 1...15). If there are 24-bits per pixel, then no color map is needed. The color map appears between the BMP header and the actual bitmap, so the function performs a sanity check to make sure that the color map is the right size.
Now the temporary Image and ImageHeader are set to the beginning of the image within the BMP format. Image will be incremented as pixels are processed while ImageHeader remains unchanged.
This outer loop cycles through all of the rows in the input image buffer, setting Blt to the first pixel in the output row.
This inner loop cycles through all of the packed pixels in an input image buffer row.
Each of the following switch case statements deals with one way of packing pixels into bytes. Each of the case statements is responsible for leaving the loop counter Width and the output buffer pointer Blt in the correct location for the next iteration of the inner loop.
This section handles the case whether there are 8 pixels packed in a single byte in the input image buffer. The loop works through all 8 bits, isolating the pixel value and then translating it to a full GOP pixel value in the output buffer using the color map.
This section handles the 4-bits per pixel case, where two pixels are packed into a single byte. Each half of the byte is translated into a pixel in the output bitmap using the color map. There is a special check for the case when there are an odd number of pixels on a line and this is the last byte in the input image buffer.
This section handles the 8-bits per pixel case, where a single pixel is packed into a single byte. Each byte is translated into a pixel in the output bitmap using the color map.
This section handles the 24-bits per pixel case, where a single pixel is packed into three bytes. No translation is done with the color map, since it is already in full color encoding.
This section handles the case when the bitmap header specified anything other than 1, 4, 8 or 24-bits per pixel. In this case, buffers are freed and an error status code is returned.
After finishing a single row, the input buffer pointer is bumped up to the next 32-bit boundary.
At this point, we're all done and have a completely decoded bitmap.
The next section loads any file into memory.
This function loads an entire file into memory. On entry, the caller provides the path of the file. Since this is a shell application, the caller can use mappings such as FS0, FS1, etc. On exit, this function returns a pointer to the buffer containing the entire file's contents and the size of the file, in bytes.
Using the standard C library functions, the file is opened. If there is a problem, an error is returned.
Now that the file is open, see to the end in order to determine the file's size. Then return back to the start.
Now allocate a buffer large enough to hold the entire file, using the file size calculated.
Read the entire file into the allocated buffer, close the file and return.
Now we will wrap up this article with a helper function that uses all of the pieces we've introduced so far. This function reads a file into memory, converts it into a Graphics Output protocol bitmap, and then frees the allocated memory for the file.
On entry, the caller provides the path of the BMP format file to convert. On exit, this function returns a pointer to the bitmap, and the bitmap's width and height.
First, load the file into an allocated buffer.
Now convert the file into a GOP style bitmap.
Now free the memory occupied by the file (but not the bitmap) and return success.
Now we have come to the end of our little program. The files will be checked into the sourceforge repository in the next week.