1

I have 24-bit image, I read bitmap and transform it to the grayscale and save like 8-bit.

RGBTRIPLE temp;
unsigned char t;
...
t = (temp.rgbtBlue * 0.114 + temp.rgbtGreen * 0.587 + temp.rgbtRed * 0.299);
fwrite(&t, sizeof(UCHAR), 1, newFile);

After that image didn't open, I understand I must smth to change in headers. I try change size of file and size of bitmap in headers, but it didn't working.

BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
...
bfh.bfSize = sizeof(UCHAR) * img.Width * img.Height + bfh.bfOffBits;
bih.biSizeImage = sizeof(UCHAR) * img.Width * img.Height;
bih.biCompression = BI_BITFIELDS;
bih.biBitCount = 8;

What I need to change for save image like 8-bit BMP?

Vlad
  • 256
  • 3
  • 14
  • row size in bytes must be a multiple of 4, also the pixel data must start with an offset of multiply of 4. Just a tip, maybe that's your problem. Try to use padding bytes. Also I don't get your t= ... function:D – David Szalai Dec 09 '13 at 21:08
  • If I will read data like RGB, i.e.I will copy t variable to Red, Green, Blue I get image wich I can read. So I think there no problem with offset. Grayscale function i get here [link](http://en.wikipedia.org/wiki/YCbCr) – Vlad Dec 09 '13 at 21:09
  • 1
    I believe BI_BITFIELDS is only valid for 16 and 32 bpp images and you seem to be using it for an 8-bit image. Try converting an image to 8-bit greyscale using a tool that produces correctly viewable images and dump out the hex to see what Microsoft are up to. – Mark Setchell Dec 09 '13 at 21:30
  • @MarkSetchell: correct, but in fact there is no BMP flavor called "grayscale". It's just an 8-bit color indexed image with an all-grays color map. (BMP used to be my bitmap format of choice, but I switched to PNG so I could use alpha. :-/) – Jongware Dec 09 '13 at 21:54

2 Answers2

2

Actually, the easiest way is not to change anything in the headers. You read 3 values (RGB), convert them to gray using the standard PAL/NTSC formula, and then you can output the calculated gray value 3 times back. That way, you get 1 pixel again, but with the altered value.

Your simply changing just the header doesn't work because for an 8-bit, color indexed image, you also need to provide a color index map -- the palette. In addition, depending on the original image size, you may need to change the stride of each row (that's what it is called -- Google is your friend too!).

As Mark Setchell remarks, BI_BITFIELDS is not what you need here (Wikipedia on BMP). Use BI_RGB for a true color or color indexed image; the other values are very specialized -- and I've never seen them "in the wild".

Jongware
  • 22,200
  • 8
  • 54
  • 100
1

It will be much easier if using Gdiplus class Bitmap's member function ConvertFormat

void GrayScale(Bitmap* bmp)
{
    void* p = malloc(sizeof(Gdiplus::ColorPalette) + 255 * sizeof(ARGB));
    Gdiplus::ColorPalette *cpal = (Gdiplus::ColorPalette*)p;
    for (int i = 0; i < 256; i++) cpal->Entries[i] = Color::MakeARGB(0, i, i, i);
    cpal->Flags = PaletteFlagsGrayScale;
    cpal->Count = 256;
    bmp->ConvertFormat(PixelFormat8bppIndexed, DitherTypeSolid, PaletteTypeCustom, cpal, 0);
    free(p);
}
luckbyluck
  • 11
  • 1