Bitmap Writing Coming Out Diagonally - opengl

My code as follows is giving me issues trying to write a bitmap image with an odd size 250x250 pixels. When I write it with an evenly divisibly by 3 area, eg. 160x160 everything is fine. I have spent a few hours now trying to get the 250x250 and other odd area's to write correctly but they just won't, the image is diagonal and half of it with the wrong color bits.
int screen_save_part(string filename,unsigned x,unsigned y,unsigned w,unsigned h) //Assumes native integers are little endian
{
unsigned sz = w * h;
FILE *bmp=fopen(filename.c_str(), "wb");
if (!bmp) return -1;
fwrite("BM", 2, 1, bmp);
std::vector<unsigned char> rgbdata(3*sz);
glReadPixels(x,window_get_region_height_scaled()-h-y,w,h,GL_BGR, GL_UNSIGNED_BYTE, &rgbdata[0]);
//glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo);
sz <<= 2;
fwrite(&sz,4,1,bmp);
fwrite("\0\0\0\0\x36\0\0\0\x28\0\0",12,1,bmp);
fwrite(&w,4,1,bmp);
fwrite(&h,4,1,bmp);
fwrite("\1\0\x18\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",28,1,bmp);
if (w & 3) {
w *= 3;
size_t pad = 3 - (w % 3);
sz -= sz >> 2;
for(unsigned i = 0; i <= sz; i += w) {
fwrite(&rgbdata[0] + i,sizeof(char),w,bmp);
fwrite("\0\0\0",sizeof(char),pad,bmp);
}
} else { fwrite(&rgbdata[0], w*3, h, bmp); }
fclose(bmp);
rgbdata.clear();
return 0;
}
Ok, but yah I am about to start pulling my hair out here I have gone through literally everything the closest I got was a for loop after that one without any padding and just added an extra row of null data but that gave me a black line on the very top 1px scanline of the image, but it had no stretching issue.

You want the stride between scanlines (in terms of bytes) to be a DWORD multiple. What you are doing right now is based entirely on the number of pixels (at least the if (w & 3) branch suggests this) and not the number of bytes-per-pixel. I would expect to see a test for (w * 3) % 4 if you have a 24-bpp pixel. If this value is > 0, then you need to add that many bytes (per-scanline) to satisfy alignment.
Try replacing your branch:
if (w & 3) {
...
}
With something more along the lines of this (24-bpp image):
int scanline_padding = (w * 3) % 4; // This will be a value from 0-3
// DWORD alignment not satisfied, for each scanline add [scanline_padding] bytes
if (scanline_padding > 0) {
for(unsigned i = 0; i < h; i++) {
fwrite(&rgbdata[0] + (i * 3 * w),sizeof(char)*3,w,bmp); // Nothing special here
fwrite("\0\0\0", scanline_padding, 1, bmp); // Now for the magic
}
}
// DWORD alignment was satisfied, so we can write the entire thing all at once
else {
fwrite(&rgbdata[0], w*3, h, bmp);
}
This is untested, but should work, or should at least give you some general direction...

Related

Optimize image buffer

Here is a code that decodes a WebM frame and put them in a buffer
image->planes[p] = pointer to the top left pixel
image->linesize[p] = strides betwen rows
framesArray = vector of unsigned char*
while ( videoDec->getImage(*image) == VPXDecoder::NO_ERROR)
{
const int w = image->getWidth(p);
const int h = image->getHeight(p);
int offset = 0;
for (int y = 0; y < h; y++)
{
// fwrite(image->planes[p] + offset, 1, w, pFile);
for(int i=0;i<w;i++){
framesArray.at(count)[i+(w*y)] = *(image->planes[p]+offset+ i) ;
}
offset += image->linesize[p];
}
}
.............................
How can I write intro buffer line by line not pixel by pixel or optimize the writing of frame intro buffer?
if the source image and destination buffer share the same Width, Height and bit per pixel, you can use std::copy to copy the whole image into it.
std::copy(image->planes[p] + offset, image->planes[p] + (image->getHeight(p) * image->linesize[p], framesArray.begin()) ;
if it is same bit per pixel but different width and height, you can use std::copy by line.

Broken BMP when save bitmap by SOIL. Screenshot area

This is continuation of my last question about saving screenshot to SOIL .here Now I wonder, how to make screenshot of part of screen and eliminate the reason that strange behaviour. My code:
bool saveTexture(string path, glm::vec2 startPos, glm::vec2 endPos)
{
const char *charPath = path.c_str();
GLuint widthPart = abs(endPos.x - startPos.x);
GLuint heightPart = abs(endPos.y - startPos.y);
BITMAPINFO bmi;
auto& hdr = bmi.bmiHeader;
hdr.biSize = sizeof(bmi.bmiHeader);
hdr.biWidth = widthPart;
hdr.biHeight = -1.0 * heightPart;
hdr.biPlanes = 1;
hdr.biBitCount = 24;
hdr.biCompression = BI_RGB;
hdr.biSizeImage = 0;
hdr.biXPelsPerMeter = 0;
hdr.biYPelsPerMeter = 0;
hdr.biClrUsed = 0;
hdr.biClrImportant = 0;
unsigned char* bitmapBits = (unsigned char*)malloc(3 * widthPart * heightPart);
HDC hdc = GetDC(NULL);
HDC hBmpDc = CreateCompatibleDC(hdc);
HBITMAP hBmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&bitmapBits, nullptr, 0);
SelectObject(hBmpDc, hBmp);
BitBlt(hBmpDc, 0, 0, widthPart, heightPart, hdc, startPos.x, startPos.y, SRCCOPY);
//UPDATE:
- int bytes = widthPart * heightPart * 3;
- // invert R and B chanels
- for (unsigned i = 0; i< bytes - 2; i += 3)
- {
- int tmp = bitmapBits[i + 2];
- bitmapBits[i + 2] = bitmapBits[i];
- bitmapBits[i] = tmp;
- }
+ unsigned stride = (widthPart * (hdr.biBitCount / 8) + 3) & ~3;
+ // invert R and B chanels
+ for (unsigned row = 0; row < heightPart; ++row) {
+ for (unsigned col = 0; col < widthPart; ++col) {
+ // Calculate the pixel index into the buffer, taking the
alignment into account
+ const size_t index{ row * stride + col * hdr.biBitCount / 8 };
+ std::swap(bitmapBits[index], bitmapBits[index + 2]);
+ }
+ }
int texture = SOIL_save_image(charPath, SOIL_SAVE_TYPE_BMP, widthPart, heightPart, 3, bitmapBits);
return texture;
}
When I run this if widthPart and heightPart is even number, that works perfect. But if something from this is odd number I get this BMP's.:
I checked any converting and code twice, but it seems to me the reason is in my wrong blit functions. Function of converting RGB is not affect on problem. What can be a reason? It's the right way blitting of area in BitBlt ?
Update No difference even or odd numbers. Correct picture produces when this numbers is equal. I don't know where is a problem.((
Update2
SOIL_save_image functions check parameters for errors and send to stbi_write_bmp:
int stbi_write_bmp(char *filename, int x, int y, int comp, void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
outfile function:
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int
y, int comp, void *data, int alpha, int pad, char *fmt, ...)
{
FILE *f = fopen(filename, "wb");
if (f) {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
fclose(f);
}
return f != NULL;
}
The broken bitmap images are the result of a disagreement of data layout between Windows bitmaps and what the SOIL library expects1. The pixel buffer returned from CreateDIBSection follows the Windows rules (see Bitmap Header Types):
The scan lines are DWORD aligned [...]. They must be padded for scan line widths, in bytes, that are not evenly divisible by four [...].
In other words: The width, in bytes, of each scanline is (biWidth * (biBitCount / 8) + 3) & ~3. The SOIL library, on the other hand, doesn't expect pixel buffers to be DWORD aligned.
To fix this, the pixel data needs to be converted before being passed to SOIL, by stripping (potential) padding and exchanging the R and B color channels. The following code does so in-place2:
unsigned stride = (widthPart * (hdr.biBitCount / 8) + 3) & ~3;
for (unsigned row = 0; row < heightPart; ++row) {
for (unsigned col = 0; col < widthPart; ++col) {
// Calculate the source pixel index, taking the alignment into account
const size_t index_src{ row * stride + col * hdr.biBitCount / 8 };
// Calculate the destination pixel index (no alignment)
const size_t index_dst{ (row * width + col) * (hdr.biBitCount / 8) };
// Read color channels
const unsigned char b{ bitmapBits[index_src] };
const unsigned char g{ bitmapBits[index_src + 1] };
const unsigned char r{ bitmapBits[index_src + 2] };
// Write color channels switching R and B, and remove padding
bitmapBits[index_dst] = r;
bitmapBits[index_dst + 1] = g;
bitmapBits[index_dst + 2] = b;
}
}
With this code, index_src is the index into the pixel buffer, which includes padding to enforce proper DWORD alignment. index_dst is the index without any padding applied. Moving pixels from index_src to index_dst removes (potential) padding.
1 The tell-tale sign is scanlines moving to the left or right by one or two pixels (or individual color channels at different speeds). This is usually a safe indication, that there is a disagreement of scanline alignment.
2 This operation is destructive, i.e. the pixel buffer can no longer be passed to Windows GDI functions once converted, although the original data can be reconstructed, even if a bit more involved.

How to efficiently render a 24-bpp image on a 32-bpp display?

First of all, I'm programming in the kernel context so no existing libraries exist. In fact this code is going to go into a library of my own.
Two questions, one more important than the other:
As the title suggests, how can I efficiently render a 24-bpp image onto a 32-bpp device, assuming that I have the address of the frame buffer?
Currently I have this code:
void BitmapImage::Render24(uint16_t x, uint16_t y, void (*r)(uint16_t, uint16_t, uint32_t))
{
uint32_t imght = Math::AbsoluteValue(this->DIB->GetBitmapHeight());
uint64_t ptr = (uint64_t)this->ActualBMP + this->Header->BitmapArrayOffset;
uint64_t rowsize = ((this->DIB->GetBitsPerPixel() * this->DIB->GetBitmapWidth() + 31) / 32) * 4;
uint64_t oposx = x;
uint64_t posx = oposx;
uint64_t posy = y + (this->DIB->Type == InfoHeaderV1 && this->DIB->GetBitmapHeight() < 0 ? 0 : this->DIB->GetBitmapHeight());
for(uint32_t d = 0; d < imght; d++)
{
for(uint32_t w = 0; w < rowsize / (this->DIB->GetBitsPerPixel() / 8); w++)
{
r(posx, posy, (*((uint32_t*)ptr) & 0xFFFFFF));
ptr += this->DIB->GetBitsPerPixel() / 8;
posx++;
}
posx = oposx;
posy--;
}
}
r is a function pointer to a PutPixel-esque thing that accepts x, y, and colour parameters.
Obviously this code is terribly slow, since plotting pixels one at a time is never a good idea.
For my 32-bpp rendering code (which I also have a question about, more on that later) I can easily Memory::Copy() the bitmap array (I'm loading bmp files here) to the frame buffer.
However, how do I do this with 24bpp images? On a 24bpp display this would be fine but I'm working with a 32bpp one.
One solution I can think of right now is to create another bitmap array which essentially contains values of 0x00(colour) and the use that to draw to the screen -- I don't think this is very good though, so I'm looking for a better alternative.
Next question:
2. Given, for obvious reasons, one cannot simply Memory::Copy() the entire array at once onto the frame buffer, the next best thing would be to copy them row by row.
Is there a better way?
Basically something like this:
for (uint32_t l = 0; l < h; ++l) // l line index in pixels
{
// srcPitch is distance between lines in bytes
char* srcLine = (char*)srcBuffer + l * srcPitch;
unsigned* trgLine = ((unsigned*)trgBuffer) + l * trgPitch;
for (uint32_t c = 0; c < w; ++c) // c is column index in pixels
{
// build target pixel. arrange indexes to fit your render target (0, 1, 2)
++(*trgLine) = (srcLine[0] << 16) | (srcLine[1] << 8)
| srcLine[2] | (0xff << 24);
srcLine += 3;
}
}
A few notes:
- better to write to a different buffer than the render buffer so the image is displayed at once.
- using functions for pixel placement like you did is very (very very) slow.

Get HBITMAPs For *ALL* Sizes and Depths of a File Type Icon (C++)

Compiler: MinGW/GCC
I'm trying to get the HICON of a file type based on what icon windows has registered for that file type, and then grab all of the HICON's images.
The problem is, I can't seem to get anything other than the 32x32 or 16x16 icon. Also, I've looked at GetIconInfoEx() but that function doesn't allow me to choose the icon size that I'm wanting, it just sort of arbitrarily pukes up whatever Windows feels like handing me at the time.
I want to at least have all of the 16x16, 32x32, and 48x48 icons, but I would really enjoy being able to extract every size that's in the HICON that I pass in.
Here's the code I'm currently working with (copy and pasted most of this from the web and stitched it together):
HBITMAP GetFileTypeIcon(const char* ext, int type, int depth)
{
HICON hIcon;
SHFILEINFO sfi= {0};
UINT flag = SHGFI_ICON|SHGFI_USEFILEATTRIBUTES;
int wh = 16;
switch(type)
{
default:
case FILE_ICON_SIZE_16:
{
wh = 16; flag|=SHGFI_SMALLICON;
}
break;
case FILE_ICON_SIZE_32:
{
wh = 32; flag|=SHGFI_LARGEICON;
}
break;
case FILE_ICON_SIZE_48:
{
wh = 48; flag|=SHGFI_SYSICONINDEX;
}
break;
case FILE_ICON_SIZE_256:
{
wh = 256; flag|=SHGFI_SYSICONINDEX;
}
break;
}
HRESULT hr = SHGetFileInfo(ext,FILE_ATTRIBUTE_NORMAL,&sfi,sizeof(sfi),flag);
if(SUCCEEDED(hr))
{
if((type == FILE_ICON_SIZE_48) || (type == FILE_ICON_SIZE_256))
{
// THIS PART DOESN'T COMPILE: undeclared function/indentifiers
// HIMAGELIST* imageList;
// hr = SHGetImageList(((type == FILE_ICON_SIZE_256)?SHIL_JUMBO:SHIL_EXTRALARGE), IID_IImageList, (void**)&imageList);
// if(SUCCEEDED(hr))
// {
// //Get the icon we need from the list. Note that the HIMAGELIST we retrieved
// //earlier needs to be casted to the IImageList interface before use.
// hr = ((IImageList*)imageList)->GetIcon(sfi.iIcon, ILD_TRANSPARENT, &hIcon);
// }
}
else
{
hIcon=sfi.hIcon;
}
}
// Convert to an HBITMAP (to get it out of the icon...)
HDC hDC = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, wh, wh);
HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp);
DrawIconEx(hMemDC, 0, 0, hIcon, wh, wh, 0, NULL, DI_NORMAL);
SelectObject(hMemDC, hOrgBMP);
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
DestroyIcon(hIcon);
return hMemBmp;
}
I don't even know what to do about color depths. I'll hazard a guess: make a DC that has a certain color depth (rather than just a compatible DC) and pass that into DrawIconEx()?
Edit: I answered my own question after much research/work.
See my answer below for a way to find and parse the raw icon data.
I basically had to do everything myself (with the help of the web, Stack Overflow, and several MSDN articles) so I think I'll just post my own solution here.
I ended up parsing the registry to find the locations of the icons of each previously registered file extension, since the API functions that should have easily gotten me the information I wanted have some... problems.
After that I spent several days manually observing the data formats at hand by observing output of an icon program, and with this information in hand I was able to construct an image loader.
I used Allegro game library to make dealing with BITMAP images easier - Win32/GDI is a bit too much to deal with and would have made the code exorbitantly messy.
Finding the Icon Location and Index:
(1) Look for extension under HKEY_CLASSES_ROOT, eg HKCR\.foo\(default) = "foofile"
(2) Default data of this is the next key to look at, eg HKCR\foofile\
(3) Default data here is the description eg HKCR\foofile\(default) = "Foo Document"
(4) The icon location may be in one of two places that I know of:
Either in HKCR\foofile\DefaultIcon\(default) or there may be an entry something like HKCR\foofile\CurVer\(default) = "foofile.1" which tells you to look at the key HKCR\foofile.1\DefaultIcon\(default) for the icon location.
Parsing the Icon Location String:
The string is simply a path followed by a comma, white space, possibly a negative sign, and a number indicating the "index" of the icon.
Here's the big gotcha: Let the icon index be N. If N is negative (might want to check for negative zeros!), it is a resource ID within the file specified. If N is positive, it means to find the N'th icon within the file, but the icon is not necessarily at resource ID number N.
Parsing Icon Structures Manually:
This is the bulk of the code and time spent, but it works beautifully. First off, here's the data formats for the various sections of color and mask data.
Data Block Formats:
32bit ... Color Data:
====================================================================================
Little Endian 4 byte ARGB values.
The rows are stored in reverse order (bottom to top).
24bit ... Color Data:
====================================================================================
Little Endian 3 byte RGB values.
Tightly Packed (NO PADDING).
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).
16bit ... Color Data:
====================================================================================
Little Endian 2 byte RGB values. 5 bits each with MSB = 0.
Tightly Packed (NO PADDING).
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).
8bit ... Palette & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There *might* be up to 256 palette entries.
If number of colors is reported as zero, assume 256 color entires.
The Pixels are 1 byte index values.
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).
4bit ... Palette & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There *might* be up to 16 palette entries.
If number of colors is reported as zero, assume 16 color entires.
The Pixels are nybble-length index values.
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).
Mask Data:
====================================================================================
Is a string of bytes with mask bits starting at MSB and going towards LSB.
There are ((imagewidth+31)>>5) DWORDS per row in *BIG ENDIAN* order.
Like the color data, there is a set of DWORDS for each row.
The rows are stored in reverse order (bottom to top).
Set unused padding bits/pixels at end of each row to 1.
0 indicates opaque and 1 indicates transparent.
1bit ... XOR Mask, AND Mask, & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There should be exactly 2 palette entries: usually 0x00000000 and 0x00FFFFFF.
The two masks follow the Mask Data format decribed above.
The following results from combining two mask bits:
XOR AND RESULT:
0 0 Color #0 (Black)
0 1 Transparent
1 0 Color #1 (White)
1 1 Invert Destination Bitmap
Of course I wouldn't have left it at this. There's code to be had!
The following code will load up and convert all of the icon images for a given icon location to a vector of 32bpp BITMAPs. If loading a given image fails, it will simply just not be added to the vector (or, in the case of a corrupt icon, it will most likely generate a corrupted image, so be careful).
The code does not support the "invert" color in monochrome images, and will just generate a different color that still has zero alpha.
WARNING: Some psuedo-code is included to shorten things to just the essentials.
Icon Loader Code (Supports: EXE, DLL, 32bit ICL, ICO):
// Code written by Simion32.
// Please feel free to use it anywhere.
// Credit would be nice but isn't required.
#include "include.h" //std::vectors and whatever else you need
#include <allegro.h>
#include <winalleg.h> //Allegro and Win32
#include "Shellapi.h"
// In the following block, the (required!!) pragmas
// force correct data alignment. Needed in at least GCC.
#pragma pack( push, 1 )
typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved ( must be 0)
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // How many bytes in this resource?
DWORD dwImageOffset; // Where in the file is this image?
} ICONDIRENTRY, *LPICONDIRENTRY;
typedef struct
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource Type (1 for icons)
WORD idCount; // How many images?
ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
} ICONDIR, *LPICONDIR;
typedef struct
{
BITMAPINFOHEADER icHeader; // DIB header
RGBQUAD icColors[1]; // Color table
BYTE icXOR[1]; // DIB bits for XOR mask
BYTE icAND[1]; // DIB bits for AND mask
} ICONIMAGE, *LPICONIMAGE;
#pragma pack( pop)
#pragma pack( push, 2 )
typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // total size of the RT_ICON resource referenced by the nID member.
WORD nID; // resourceID of RT_ICON (LockResource to obtain a pointer to its ICONIMAGE)
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
typedef struct
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource type (1 for icons)
WORD idCount; // How many images?
GRPICONDIRENTRY idEntries[1]; // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;
#pragma pack( pop )
uint32_t Convert16BitToARGB(uint16_t value)
{
return (0xFF000000|((value >> 7) & 0x0000F8)|((value << 6) & 0x00F800)|((value << 19) & 0xF80000));
}
uint32_t GetMaskBit(uint8_t* data, int x, int y, int w, int h)
{
uint32_t mask_data_rowsize = (((w+31)>>5) * 4);
return ((~(data[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07))) & 1) * 0xFFFFFFFF);
}
uint32_t GetColorMonochrome(uint8_t* xordata, uint8_t* anddata, int x, int y, int w, int h, uint32_t* pal)
{
uint32_t mask_data_rowsize = (((w+31)>>5) * 4);
uint32_t xor_bit = (((xordata[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07))) << 1) & 2);
uint32_t and_bit = (((anddata[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07))) ) & 1);
uint32_t value = (xor_bit | and_bit);
return pal[value];
}
BITMAP* CreateBmp32bppFromIconResData(void* data, int size, int depth, int w, int h, int colors)
{
char* pngheader = "\211PNG\r\n\032\n";
char* cpd = (char*)data;
bool is_png = ((cpd[0]==pngheader[0])
&& (cpd[1]==pngheader[1])
&& (cpd[2]==pngheader[2])
&& (cpd[3]==pngheader[3])
&& (cpd[4]==pngheader[4])
&& (cpd[5]==pngheader[5])
&& (cpd[6]==pngheader[6])
&& (cpd[7]==pngheader[7]));
if(is_png)
{
//###########################################################
//# PSEUDO-CODE: Somehow convert the PNG file into a bitmap.
BITMAP* result = ConvertPngFileToBmp32bpp(data, size);
return result;
}
else
{
uint32_t ignore_size = ((BITMAPINFOHEADER*)(data))->biSize;
BITMAP* bmp = create_bitmap_ex(32,w,h);
uint32_t pixel_count = (w * h);
uint32_t color_data_size = ((((((w * depth)+7) >> 3) +3) & ~3) * h);
switch(depth)
{
default: return bmp; break;
case 32:
{
uint32_t* src = (uint32_t*)(((uint8_t*)data) + ignore_size);
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
_putpixel32(bmp,xx,yy,src[0]);
src++;
}
//There should never be any padding to jump over here.
}
return bmp;
}
break;
case 24:
{
uint32_t* src = (uint32_t*)(((uint8_t*)data) + ignore_size);
uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + color_data_size);
int padding_checker = 0;
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
_putpixel32(bmp,xx,yy,((src[0] & 0x00FFFFFF) | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
src++;
src = (uint32_t*)(((uint8_t*)src)-1); //go back a byte due to packing
padding_checker += 3;
padding_checker &= 3;
}
//This loop jumps over any padding bytes.
while(padding_checker)
{
src = (uint32_t*)(((uint8_t*)src)+1);
padding_checker++;
padding_checker &= 3;
}
}
return bmp;
}
break;
case 16:
{
//Note: there might be a color table present! ignore it.
uint16_t* src = (uint16_t*)(((uint8_t*)data) + ignore_size + (colors << 2));
uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
int padding_checker = 0;
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
_putpixel32(bmp,xx,yy,Convert16BitToARGB(src[0]) & GetMaskBit(bitmask, xx, yy, w, h));
src++;
padding_checker += 2;
padding_checker &= 3;
}
//This loop jumps over any padding bytes.
while(padding_checker)
{
src = (uint16_t*)(((uint8_t*)src)+1);
padding_checker++;
padding_checker &= 3;
}
}
return bmp;
}
break;
case 8:
{
if(colors > 256) colors = 256; //Color Count must be restricted to 256 entries at the most.
if(colors <= 0) colors = 256; //Color Count might be reported as zero. This means 256.
uint8_t* src = (((uint8_t*)data) + ignore_size + (colors << 2));
uint32_t* pal = ((uint32_t*)(((uint8_t*)data) + ignore_size));
uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
int padding_checker = 0;
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
uint8_t color = src[0];
if(color < colors){
_putpixel32(bmp,xx,yy,(pal[color] | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
}else{
_putpixel32(bmp,xx,yy,0x00FF00FF);
}
src++;
padding_checker++;
padding_checker &= 3;
}
//This loop jumps over any padding bytes.
while(padding_checker)
{
src++;
padding_checker++;
padding_checker &= 3;
}
}
return bmp;
}
break;
case 4:
{
if(colors > 16) colors = 16; //Color Count must be restricted to 16 entries at the most.
if(colors <= 0) colors = 16; //Color Count might be reported as zero. This means 16.
uint8_t* src = (((uint8_t*)data) + ignore_size + (colors << 2));
uint32_t* pal = ((uint32_t*)(((uint8_t*)data) + ignore_size));
uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
int padding_checker = 0;
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
uint8_t color = src[0];
if(xx & 1) color = ( color & 0x0F);
else color = ((color >> 4) & 0x0F);
if(color < colors){
_putpixel32(bmp,xx,yy,(pal[color] | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
}else{
_putpixel32(bmp,xx,yy,0x00FF00FF);
}
if(xx & 1)
{
src++;
padding_checker++;
padding_checker &= 3;
}
}
//if the pointer hasn't incremented to the next byte yet, do so.
if(w & 1) //odd width
{
src++;
padding_checker++;
padding_checker &= 3;
}
//This loop jumps over any padding bytes.
while(padding_checker)
{
src++;
padding_checker++;
padding_checker &= 3;
}
}
return bmp;
}
break;
case 1:
{
if(colors > 2) colors = 2; //Color Count must be restricted to 2 entries at the most.
if(colors <= 0) colors = 2; //Color Count might be reported as zero. This means 2.
uint32_t* pal = (uint32_t*)(((uint8_t*)data) + ignore_size);
uint8_t* bitmaskXOR = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2));
uint8_t* bitmaskAND = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
uint32_t ret_colors[4] = {pal[0]|0xFF000000, 0x00FF00FF, pal[1]|0xFF000000, 0x0000FF00};
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
_putpixel32(bmp,xx,yy,GetColorMonochrome(bitmaskXOR, bitmaskAND, xx, yy, w, h, ret_colors));
}
}
return bmp;
}
break;
}
return bmp;
}
}
vector< BITMAP* > ResourceToBitmapVector(HMODULE hm, HRSRC hr, bool is_group_icon)
{
vector< BITMAP* > results;
if(is_group_icon)
{
HGLOBAL hg = LoadResource(hm,hr);
GRPICONDIR* gd = (GRPICONDIR*)LockResource(hg);
if(gd->idType == 1)
{
for(int i = 0; i < gd->idCount; ++i)
{
//WARNING: The GRPICONDIRENTRY's data might be wrong!
GRPICONDIRENTRY* ie = (GRPICONDIRENTRY*)&(gd->idEntries[i]);
HRSRC ihr = FindResource(hm,MAKEINTRESOURCE(ie->nID),RT_ICON);
if(ihr != NULL)
{
HGLOBAL ihg = LoadResource(hm,ihr);
void* data = (void*)LockResource(ihg);
DWORD size = SizeofResource(hm,ihr);
uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
}
}
}
}
else
{
HGLOBAL ihg = LoadResource(hm,hr);
void* data = (void*)LockResource(ihg);
DWORD size = SizeofResource(hm,hr);
uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
}
return results;
}
vector< BITMAP* > IconFileToBitmapVector(void* icon_data, uint32_t icon_size)
{
vector< BITMAP* > results;
ICONDIR* gd = (ICONDIR*)icon_data;
if(gd->idType == 1)
{
for(int i = 0; i < gd->idCount; ++i)
{
//WARNING: The ICONDIRENTRY's data might be wrong!
DWORD offset = gd->idEntries[i].dwImageOffset;
DWORD size = gd->idEntries[i].dwBytesInRes;
void* data = (void*)(((uint8_t*)icon_data) + ((uint32_t)offset));
uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
}
}
return results;
}
vector< BITMAP* > UnearthIconResource(string& file, bool self_refrence, bool res_index, int index)
{
#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x00000010
//prevents a negative indexing error
// (the boolean res_index handles whether it's icon index VS resource ID)
index = abs(index);
vector< BITMAP* > results; //array of results to return (pointers to 32bpp images)
//extract and 'demangle' the file extension by convertng to lowercase.
string ext = get_file_extension(file.c_str());
for(int i = 0; i < ext.size(); ++i) ext[i] = tolower(ext[i]);
bool is_icl = false;
if((ext == "exe") || (ext == "dll") || (ext == "scr") || (is_icl = (ext == "icl")))
{
// Portable Executable Resource (works for both DLL and EXE)
// Also works for any 32bit Icon Library (Microangelo Studio?)
HMODULE hm = LoadLibraryEx(file.c_str(), NULL,
(DONT_RESOLVE_DLL_REFERENCES | LOAD_IGNORE_CODE_AUTHZ_LEVEL | LOAD_LIBRARY_AS_DATAFILE));
if(hm != NULL)
{
HRSRC hr;
if(!self_refrence)
{
if(res_index)
{
//The icon we want is at the resource ID (==index)
bool is_single_icon = false;
hr = FindResource(hm,MAKEINTRESOURCE(index),RT_GROUP_ICON);
if(hr == NULL)
{
hr = FindResource(hm,MAKEINTRESOURCE(index),RT_ICON);
is_single_icon = (hr != NULL);
}
if(hr != NULL)
{
results = ResourceToBitmapVector(hm, hr, !is_single_icon);
}
}
else
{
//The icon we want is the (index)'th icon in the file
//We must preform a manual search for the resource ID!
//WARNING: Using EnumResourceNames() *DOES NOT WORK PROPERLY* for this.
for(int nicon = 0, i = 0; i < 0x8000; ++i)
{
bool is_single_icon = false;
hr = FindResource(hm,MAKEINTRESOURCE(i),RT_GROUP_ICON);
if(hr != NULL)
{
if(nicon == index)
{
results = ResourceToBitmapVector(hm, hr, true);
break;
}
nicon++;
}
}
}
}
else
{
//The icon we want is the "first" icon in the file.
//Happens when location is a %1.
//We must preform a manual search for the resource ID!
//WARNING: Using EnumResourceNames() *DOES NOT WORK PROPERLY* for this.
for(int i = 0; i < 0x8000; ++i)
{
bool is_single_icon = false;
hr = FindResource(hm,MAKEINTRESOURCE(i),RT_GROUP_ICON);
if(hr != NULL)
{
results = ResourceToBitmapVector(hm, hr, true);
break;
}
}
}
FreeLibrary(hm);
}
else /*if(is_icl)
{//OH NOES. We have to load a *16bit* .icl file!
//not supported yet. sorry. left as another excecise to the programmer.
}*/
}
else if(ext == "ico")
{
//Single Icon File
//###################################################
//# PSEUDO-CODE: Do the file loading yourself ;)
void* data_pointer = NULL;
uint32_t data_size = 0;
if(data_pointer = MyLoadFile(file.c_str(), &data_size))
{
if(data_size)
{
results = IconFileToBitmapVector((void*)data_pointer, data_size);
}
}
MyCloseFile(data_pointer);
}
return results;
}
I think that almost covers it all...
One last thing I should mention: Be sure to ignore the size and bit depth information coming from the icon directory entries. They can often be wrong. I've seen a few 256-color images reported as 24bit, causing data corruption inside the image loader.
Wow, talk about reinventing the wheel!
With all due respect, this code is so bloated for nothing. I (and probably thousands of others) achieved the exact same result with 1/10 of this code. Also, this solution contains many inaccuracies.
Here's a quick run-down:
Why parse the registry manually? You state the API has some problems; like what? I've used reg parsing API extensively and never had a problem! The Indexing vs ResID logic is correct though.
Why do all the icon to bitmap conversions manually? This can be achieved with 3 to 5 lines of code using the right Icon API calls. Here's a complete reference.
Why limit the conversion to 32bpp? Again, using the right APIs will generate a device dependent hIcon handle with the max color bit-depth supported by that device. Check out the CreateIconFromResourceEx() API function. All you need to do is combine it with the Find/Load/Lock Resource APIs that you're already using. Using this technique will load icons of any size and color depth (from monochrome up to alpha-channel 32bpp icons).
Finally, regarding the search for icon resources by group (RT_GROUP_ICON), or by single icons (RT_ICON), and matching for a given index instead of resource, it could be done much more efficiently using EnumResourceNames(). It might be that you've failed to account for string resource identifiers when parsing the Enum return, because it seems you've omitted such case in your manual search and match procedure. This might be the source of your problems with EnumResourceNames(). It works perfectly fine for me and for others in countless online samples. At the very least, the "manual" search should match up to 0xFFFF rather than 0x8000. Res IDs are recommended in the 0x0001 to 0x8000 range, but legal in the 0x0000 to 0xFFFF range.
If it does have not to be platform independent:
a bit time ago i wrote a little class that reads a file and extract all icons.
It retreives a std::vector with HICONs.
With GetIconInfo you can retreive the HBITMAP for pixeldata an pixelmask.
The function is a little bit heuristic. It scans the binary Data for a typical icon begin and tries to load them.
The function also works on dlls, exe or icl (16bit dlls that just contain icon resources)
#ifndef __ICON_LIST_H__
#define __ICON_LIST_H__
#include <windows.h>
#include <vector>
class IconFile: public std::vector<HICON>{
public:
IconFile(){};
IconFile(std::string i_filename){
addIconsFromFile(i_filename);
};
int addIconsFromFile(std::string i_fileName){
int iCount=0;
HANDLE file = CreateFile( i_fileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(file!=INVALID_HANDLE_VALUE){
int size = GetFileSize(file,NULL);
DWORD actRead;
BYTE* buffer = new BYTE[size];
ReadFile(file, buffer, size, &actRead, NULL);
CloseHandle(file);
int ind = -1;
for(int p = 0; p< size-4; ++p){
if(buffer[p]==40 && buffer[p+1]==0 && buffer[p+2]==0 && buffer[p+3]==0){
HICON icon = CreateIconFromResourceEx(&buffer[p], size-p, true, 0x00030000,0,0,0);
if(icon){
++iCount;
this->push_back(icon);
}
}
}
delete[] buffer;
}
return iCount;
};
};
#endif //__ICON_LIST_H__

Trouble fitting depth image to RGB image using Kinect 1.0 SDK

I'm trying to get the Kinect depth camera pixels to overlay onto the RGB camera. I am using the C++ Kinect 1.0 SDK with an Xbox Kinect, OpenCV and trying to use the new "NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution" method.
I have watched the image render itself in slow motion and looks as if pixels are being drawn multiple times in the one frame. It first draws itself from the top and left borders, then it gets to a point (you can see a 45 degree angle in there) where it starts drawing weird.
I have been trying to base my code off of the C# code written by Adam Smith at the MSDN forums but no dice. I have stripped out the overlay stuff and just want to draw the depth normalized depth pixels where it "should" be in the RGB image.
The image on the left is what I'm getting when trying to fit the depth image to RGB space, and the image on the right is the "raw" depth image as I like to see it. I was hoping this my method would create a similar image to the one on the right with slight distortions.
This is the code and object definitions that I have at the moment:
// From initialization
INuiSensor *m_pNuiInstance;
NUI_IMAGE_RESOLUTION m_nuiResolution = NUI_IMAGE_RESOLUTION_640x480;
HANDLE m_pDepthStreamHandle;
IplImage *m_pIplDepthFrame;
IplImage *m_pIplFittedDepthFrame;
m_pIplDepthFrame = cvCreateImage(cvSize(640, 480), 8, 1);
m_pIplFittedDepthFrame = cvCreateImage(cvSize(640, 480), 8, 1);
// Method
IplImage *Kinect::GetRGBFittedDepthFrame() {
static long *pMappedBits = NULL;
if (!pMappedBits) {
pMappedBits = new long[640*480*2];
}
NUI_IMAGE_FRAME pNuiFrame;
NUI_LOCKED_RECT lockedRect;
HRESULT hr = m_pNuiInstance->NuiImageStreamGetNextFrame(m_pDepthStreamHandle, 0, &pNuiFrame);
if (FAILED(hr)) {
// return the older frame
return m_pIplFittedDepthFrame;
}
bool hasPlayerData = HasSkeletalEngine(m_pNuiInstance);
INuiFrameTexture *pTexture = pNuiFrame.pFrameTexture;
pTexture->LockRect(0, &lockedRect, NULL, 0);
if (lockedRect.Pitch != 0) {
cvZero(m_pIplFittedDepthFrame);
hr = m_pNuiInstance->NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution(
m_nuiResolution,
NUI_IMAGE_RESOLUTION_640x480,
640 * 480, /* size is previous */ (unsigned short*) lockedRect.pBits,
(640 * 480) * 2, /* size is previous */ pMappedBits);
if (FAILED(hr)) {
return m_pIplFittedDepthFrame;
}
for (int i = 0; i < lockedRect.size; i++) {
unsigned char* pBuf = (unsigned char*) lockedRect.pBits + i;
unsigned short* pBufS = (unsigned short*) pBuf;
unsigned short depth = hasPlayerData ? ((*pBufS) & 0xfff8) >> 3 : ((*pBufS) & 0xffff);
unsigned char intensity = depth > 0 ? 255 - (unsigned char) (256 * depth / 0x0fff) : 0;
long
x = pMappedBits[i], // tried with *(pMappedBits + (i * 2)),
y = pMappedBits[i + 1]; // tried with *(pMappedBits + (i * 2) + 1);
if (x >= 0 && x < m_pIplFittedDepthFrame->width && y >= 0 && y < m_pIplFittedDepthFrame->height) {
m_pIplFittedDepthFrame->imageData[x + y * m_pIplFittedDepthFrame->widthStep] = intensity;
}
}
}
pTexture->UnlockRect(0);
m_pNuiInstance->NuiImageStreamReleaseFrame(m_pDepthStreamHandle, &pNuiFrame);
return(m_pIplFittedDepthFrame);
}
Thanks
I have found that the problem was that the loop,
for (int i = 0; i < lockedRect.size; i++) {
// code
}
was iterating on a per-byte basis, not on a per-short (2 bytes) basis. Since lockedRect.size returns the number of bytes the fix was simply changing the increment to i += 2, even better would be changing it to sizeof(short), like so,
for (int i = 0; i < lockedRect.size; i += sizeof(short)) {
// code
}