Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to save 8 bit images as jpg 8 bit image using gdi+

879 views
Skip to first unread message

Tom Becker

unread,
Oct 2, 2009, 10:40:42 AM10/2/09
to
Hallo

I have a custom 8 bit image stored as BYTE*
BYTE* m_pData;

It contains grayscal values.

I created a Bitmap
Bitmap bm(m_width, m_height, m_pitch, PixelFormat8bppIndexed, m_pData);

Then I adjusted its ColorPalette to get correct greyscale values:

UINT nPaletteSize = bm.GetPaletteSize();
pPalette = new Gdiplus::ColorPalette[nPaletteSize];
bm.GetPalette(pPalette, nPaletteSize);
bm.Flags = 0;//PaletteFlagsGrayScale;

for(UINT i = 0; i < pPalette->Count; i++)
{
pPalette->Entries[i] = Color::MakeARGB(0xFF, (BYTE)i, (BYTE)i, (BYTE)i);
}

bm.SetPalette(pPalette);


Next step is getting the CLSID for jpg (see CImage),
set up EncoderParameters and call bm.Save(...).


Here are my questions:
- Saving it as a "bmp" works as expected i get a 8 bit bmp. But
saving it as a "jpg" I get a 24 bit jpg. How to get a 8 bit jpg?

- Maybe a stupid question:
HowTo reserve memory (C++) for EncoderParameters so that I can use
more than one parameter?
EncoderParameters ep;
//ToDo: howto alloc mem
//
ep.Count = 2;
ep.Parameter[0] = ...
ep.Parameter[1] = ...

- Why is it necessary to adjust the ColorPalette?
I thought it would be sufficent to create a Gdiplus::Bitmap
with the correct format.

thx
Tom

Michael Phillips, Jr.

unread,
Oct 2, 2009, 12:00:39 PM10/2/09
to
> Here are my questions:
> - Saving it as a "bmp" works as expected i get a 8 bit bmp. But
> saving it as a "jpg" I get a 24 bit jpg. How to get a 8 bit jpg?

8bpp greyscale images and 8bpp jpg is not supported with gdiplus version
1.0.

There is a new version of gdiplus in Windows 7 that supports greyscale
images and more enhanced codec support.

I have not tried the new version so I do not know if the jpeg codec was
updated to support 8bpp greyscale images.

I do know that greyscale and 8bpp indexed jpeg images are supported with
Microsoft's WIC API.

You can try it yourself by downloading the WIC explorer from Microsoft's
download site.


>
> - Maybe a stupid question:
> HowTo reserve memory (C++) for EncoderParameters so that I can use
> more than one parameter?
> EncoderParameters ep;
> //ToDo: howto alloc mem
> //
> ep.Count = 2;
> ep.Parameter[0] = ...
> ep.Parameter[1] = ...

//To allocate memory for "Count" parameters
int Count = 2;
EncoderParameters *ep = new EncoderParameters[Count];

> - Why is it necessary to adjust the ColorPalette?
> I thought it would be sufficent to create a Gdiplus::Bitmap
> with the correct format.

It is not sufficient. It is your responsibility to create a palette, fill
in the palette and finally set the bitmap to use the palette that you
created.


JJ

unread,
Oct 2, 2009, 5:13:20 PM10/2/09
to

AFAIK, standard JPEG only supports 24-bit image. It also doesn't support
transparency nor multiple layers.

Tom Becker

unread,
Oct 5, 2009, 3:01:50 AM10/5/09
to

Michael Phillips, Jr. schrieb:

>> Here are my questions:
>> - Saving it as a "bmp" works as expected i get a 8 bit bmp. But
>> saving it as a "jpg" I get a 24 bit jpg. How to get a 8 bit jpg?
>
> 8bpp greyscale images and 8bpp jpg is not supported with gdiplus version
> 1.0.
>
> There is a new version of gdiplus in Windows 7 that supports greyscale
> images and more enhanced codec support.
>
> I have not tried the new version so I do not know if the jpeg codec was
> updated to support 8bpp greyscale images.
>
> I do know that greyscale and 8bpp indexed jpeg images are supported with
> Microsoft's WIC API.
>
> You can try it yourself by downloading the WIC explorer from Microsoft's
> download site.

Thanks. I'll have a look at it.

>> - Maybe a stupid question:
>> HowTo reserve memory (C++) for EncoderParameters so that I can use
>> more than one parameter?
>> EncoderParameters ep;
>> //ToDo: howto alloc mem
>> //
>> ep.Count = 2;
>> ep.Parameter[0] = ...
>> ep.Parameter[1] = ...
>
> //To allocate memory for "Count" parameters
> int Count = 2;
> EncoderParameters *ep = new EncoderParameters[Count];

It seems to work, although I don't know why. IMHO memory allignment
of a struct containing a struct

EncoderParameters
{
UINT
EncoderParameter[]
}

is something like
<sizeof(UINT)><EncoderParameter[0]><EncoderParameter[1]>...

and on the contrary


EncoderParameters *ep = new EncoderParameters[Count];

would result in sth. like
<sizeof(UINT)><EncoderParameter[0]><sizeof(UINT)><EncoderParameter[0]>...

My workaround was creating an own struct and casting it to
EncoderParameters:

MyEncoderParameters
{
UINT Count
EncoderParameter Parameter[10]
}

But I didn't test it in all circumstances.

Michael Phillips, Jr.

unread,
Oct 5, 2009, 10:19:16 AM10/5/09
to
> It seems to work, although I don't know why. IMHO memory allignment
> of a struct containing a struct
>
> EncoderParameters
> {
> UINT
> EncoderParameter[]
> }
>
> is something like
> <sizeof(UINT)><EncoderParameter[0]><EncoderParameter[1]>...
>
> and on the contrary
> EncoderParameters *ep = new EncoderParameters[Count];
>
> would result in sth. like
> <sizeof(UINT)><EncoderParameter[0]><sizeof(UINT)><EncoderParameter[0]>...
>
> My workaround was creating an own struct and casting it to
> EncoderParameters:
>
> MyEncoderParameters
> {
> UINT Count
> EncoderParameter Parameter[10]
> }
>
> But I didn't test it in all circumstances.

Since the EncoderParameters structure already allocates memory for one
EncoderParameter, you may use the following:
EncoderParameters* ep = reinterpret_cast<EncoderParameters*>( new unsigned
char[ sizeof(EncoderParameters) + sizeof(EncoderParameter) * (Count-1) ] );


0 new messages