The ColorPalette class has no constructor so how does one use it?

  • Thread starter Thread starter active
  • Start date Start date
A

active

The ColorPalette class has no constructor so how does one use it?
I define a variable by:

Dim cp as ColorPalette

but don't know how assign an object to the variable.



Thanks in advance
 
The ColorPalette class has no constructor so how does one use it?
I define a variable by:

Dim cp as ColorPalette

but don't know how assign an object to the variable.

If there is no constructor, then you can only get a ColorPalette from
other objects. For example:

Dim cp As ColorPalette
Dim bmp As Bitmap = New Bitmap("figure2.bmp")

cp = bmp.Palette
 
Lke the other poster says...

Just create a 1x1 bitmap of the appropriate bit depth and retrieve it's
color palette into your variable.

It's not elegant, but it's the only way.
 
thanks

Blake said:
Lke the other poster says...

Just create a 1x1 bitmap of the appropriate bit depth and retrieve it's
color palette into your variable.

It's not elegant, but it's the only way.
 
thanks

Jack Jackson said:
If there is no constructor, then you can only get a ColorPalette from
other objects. For example:

Dim cp As ColorPalette
Dim bmp As Bitmap = New Bitmap("figure2.bmp")

cp = bmp.Palette
 
What do you need it for anyway?

The ColorPalette class is just a wrapper for a simple
1-dimensional array of System.Drawing.Color entries.

It contains two internal (Friend) methods:
- ConvertFromMemory
- ConvertToMemory

All they do is to convert between 32-bit integers and
System.Drawing.Color.

Just copy the class to MyColorPalette or whatever and
add the missing "Entries" setter, if that is what you are
looking for.

Do you just want the conversion functions or do you
actually need to assign an actual
System.Drawing.Imaging.ColorPalette object to something?

Regards,

Joergen Bech
 
For each entry:
get an entry from a Bitmap color table
modify it
store the modified entry in a color table


Assign the new color table to the bitmap.

So I think I can do what the other posters suggested.

But I would like to know what you meant by the following.


Just copy the class to MyColorPalette


Thanks
 
My suggestion was that if you needed a class
with the same behavior as ColorPalette, but with
a few changes, you could just copy the code from
the ColorPalette class to another class with the
name and additional functionality of your choice.
There are various tools for decompiling the framework.

But if you need to assign a ColorPalette object
to a property that expects the type found in the
framework, this might not be an option.

As for assigning a palette from a dummy palette
indirectly created by creating a new bitmap of the
same bit depth: No can do.

MyBitmap.Palette = <ColorPalette object>

is not the same as

MyBitmap.Palette = <some other bitmap>.Palette.

In the latter case, you are going through some
GDI+ functions to get a new palette rather than
just getting a ColorPalette object directly.

When assigned to MyBitmap.Palette, you are
jumping through similar hoops.

Try the code below. You will find that nothing
works as expected. All copies are identical to
the original. Attempts to change the colors in
any of these manners are ignored.

I use an imaging toolkit for similar needs, so I
haven't digged deeper into this. There might be
a solution. Then again, there might not. It is possible
that Microsoft has made it *possible* to change the
Palette.Entries values, but not *intended* for them
to be changed or react to such changes.

Please prove me wrong.

Regards,

Joergen Bech

---snip---

'Load image
Dim lena8 As New Bitmap("d:\lena8.bmp")

'Save it again to verify that we read it correctly
lena8.Save("d:\lena8-original.bmp",
System.Drawing.Imaging.ImageFormat.Bmp)

'Work with a palette created as a copy of the palette of the
original image
Dim cp As ColorPalette = lena8.Palette

For i As Integer = 0 To 255
cp.Entries(i) = Color.FromArgb(i, i, i)
Next
lena8.Palette = cp
lena8.Save("d:\lena8-cp.bmp",
System.Drawing.Imaging.ImageFormat.Bmp)

'Work with a dummy palette created by creating another bitmap
Dim bm As New Bitmap(1, 1, PixelFormat.Format8bppIndexed)
For i As Integer = 0 To 255
bm.Palette.Entries(i) = Color.FromArgb(i, i, i)
Next
lena8.Palette = bm.Palette
lena8.Save("d:\lena8-bm.bmp",
System.Drawing.Imaging.ImageFormat.Bmp)

'Modify palette entries directly in the original image
For i As Integer = 0 To 255
lena8.Palette.Entries(i) = Color.FromArgb(i, i, i)
Next
lena8.Save("d:\lena8-0-255.bmp",
System.Drawing.Imaging.ImageFormat.Bmp)

---snip---
 
Never decompiled the framework so it didn't occur to me that was what you
meant.

Thanks for taking so much time to answer so completely.

I need to study the code.

thanks
 
What was MS thinking?
Why not make Entries readonly?
I add a statement to yout code:
The line written did not reflect i,i,i

lena8.Palette.Entries(i) = Color.FromArgb(i, i, i)

Console.WriteLine("Entry({0} = {1}", i, lena8.Palette.Entries(i))
 
Have a look at
http://www.codeproject.com/cs/media/Image_Processing_Lab.asp

To create a grayscale image from a 256-color image, he creates
a new 8-bit image of the same size as the original, sets the Palette
values of the new image to 0,0,0 1,1,1 2,2,2 ... 255,255,255,
then proceeds to set the pixel data of the new image by calculating
the intensities of the original image.

It would have been much faster had he just modified the palette
entries of the original image.

I made another test (create a new Windows application project):
---snip---
Private _bm As Bitmap

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Test2()
End Sub

Private Sub Test2()
Dim lena8 As New Bitmap("d:\lena8.bmp")
SetGrayscalePalette(lena8)
_bm = lena8
lena8.Save("d:\lena8-gray.bmp",
System.Drawing.Imaging.ImageFormat.Bmp)
End Sub

Public Shared Sub SetGrayscalePalette(ByVal image As Bitmap)
If (image.PixelFormat <> PixelFormat.Format8bppIndexed) Then
Throw New ArgumentException
End If
Dim palette As ColorPalette = image.Palette
Dim i As Integer
For i = 0 To &H100 - 1
'palette.Entries(i) = Color.FromArgb(i, i, i)
Dim original As Color = palette.Entries(i)
Dim gray As Integer = CType((original.G * 4 + original.R *
2 + original.B) / 7, Integer)
palette.Entries(i) = Color.FromArgb(gray, gray, gray)
Next i
image.Palette = palette
End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles Me.Paint
If _bm Is Nothing Then
Exit Sub
End If

e.Graphics.DrawImage(_bm, 0, 0, _bm.Width, _bm.Height)

End Sub

---snip---

(Yes, I know that (G*4+R*2+B)/7 is simplistic and incorrect)

You will notice that the palette entries actually have changed when
the image is painted on the form, but the saved copy retains the
original colors.

If we were to paint the image from the code above onto a 24-bit
bitmap and save it, we get a nice grayscale image, albeit 24-bit:
---snip---
Dim dst As New Bitmap(lena8.Width, lena8.Height,
PixelFormat.Format24bppRgb)
Dim g As Graphics = Graphics.FromImage(dst)
g.DrawImage(lena8, 0, 0, dst.Width, dst.Height)
g.Dispose()
dst.Save("d:\dst.bmp", ImageFormat.Bmp)
---snip---

(it is not possible to create a Graphics object from an indexed
image).

I have not spent any time digging into why the original palette
is used when saving an indexed image, but as I mentioned in the
other post, I use an imaging library myself (LeadTools).

Perhaps the link at the top might give you a few ideas of how
to go about this in an entirely different way.

Regards,

Joergen Bech
 
How dose powell get a way with this.
It works including saving to a file.
The last line I show he is inserting a color table into a Bitmap!
He then inserts the bitmap data.

Isn't this what we are saying can't be effective?

Thanks if you can explain this


Private Sub panel1_Click(...
'Creates a new GIF image with a modified colour palette

If Not (cp Is Nothing) Then

'Create a new 8 bit per pixel image

Dim bm As New Bitmap(_gifImage.Width, _gifImage.Height,
PixelFormat.Format8bppIndexed)

'get it's palette

Dim ncp As ColorPalette = bm.Palette



'copy all the entries from the old palette removing any transparency

Dim n As Integer = 0

Dim c As Color

For Each c In cp.Entries

ncp.Entries(n) = Color.FromArgb(255, c)

n += 1

Next c

'Set the newly selected transparency

ncp.Entries(CurrentEntry) = Color.FromArgb(0,
cp.Entries(CurrentEntry))

're-insert the palette

bm.Palette = ncp
 
If my memory serves me right, the original problem was that
if the 8-bit indexed image was loaded from a file, any attempt
(at least any attempt I made) would fail to change the palette.

In your (Powell's) example, you are creating a NEW bitmap
object, then setting the palette - which actually works - but
that is not as interesting as changing the palette for an
existing image we just loaded.

As you say, the last line you show sets the palette for the
bitmap object, but you fail to show how Powell "inserts the
bitmap data"?!?

Could you please post a complete, working sample based
on this information that actually loads a gif from disk, changes
the palette, then writes it back to disk, changed palette and all?

Regards,

Joergen Bech
 
I believe I just found the answer in Q319061.
....snip
You can write an unmodified Bitmap with the GIF encoder and keep the Bitmap
color table intact; therefore, you can use this method to save a .gif file
with a new color table.

The method is to copy the image data from an original Image object to a
temporary Bitmap object. This temporary Bitmap is created as an 8-BPP
indexed Bitmap, which is the pixel format that is used to save a .gif file.
The Bitmap color table is set by using the SetPalette method, and then the
image definition is copied to the temporary Bitmap. After you create the
temporary Bitmap with a duplicate definition, you can use the Save() method
to save it with the GIF encoder, which preserves the 8-BPP color table.


...snip

I guess the "unmodified" is what allows it. Maybe when the bitmap data is
added the "save" color table get frozen. You think?

Q319061 shows how and I believe it is just what Powell does.

Code is at the bottom of this link in the panel1_Click sub at

http://www.bobpowell.net/giftransparency.htm

====

Do you know why it is always 8bpp. Other formats such as 4bpp are possible
but never seem to be saved by GDI+


Also, I found Q319061 when I was looking for the file format for a GIF file
(read via a stream) if you know where that is I'd appreciate the link.


Thanks for answering



Joergen Bech @ post1.tele.dk> said:
If my memory serves me right, the original problem was that
if the 8-bit indexed image was loaded from a file, any attempt
(at least any attempt I made) would fail to change the palette.

In your (Powell's) example, you are creating a NEW bitmap
object, then setting the palette - which actually works - but
that is not as interesting as changing the palette for an
existing image we just loaded.


He copies the image data so it creates a new bitmap with the same image an a
new palette which can be saved and viewed.
As you say, the last line you show sets the palette for the
bitmap object, but you fail to show how Powell "inserts the
bitmap data"?!?

It's a little long and I don't know if that is OK with Powell.
Could you please post a complete, working sample based
on this information that actually loads a gif from disk, changes
the palette, then writes it back to disk, changed palette and all?

He plays with the transparency but that can be removed.
 
I believe I just found the answer in Q319061.
...snip
You can write an unmodified Bitmap with the GIF encoder and keep the Bitmap
color table intact; therefore, you can use this method to save a .gif file
with a new color table.

The method is to copy the image data from an original Image object to a
temporary Bitmap object. This temporary Bitmap is created as an 8-BPP
indexed Bitmap, which is the pixel format that is used to save a .gif file.
The Bitmap color table is set by using the SetPalette method, and then the
image definition is copied to the temporary Bitmap. After you create the
temporary Bitmap with a duplicate definition, you can use the Save() method
to save it with the GIF encoder, which preserves the 8-BPP color table.
I guess the "unmodified" is what allows it. Maybe when the bitmap data is
added the "save" color table get frozen. You think?

I wouldn't presume to guess, but it appears to be the case.
Q319061 shows how and I believe it is just what Powell does.

Code is at the bottom of this link in the panel1_Click sub at

http://www.bobpowell.net/giftransparency.htm

ok, that is exactly what I thought. Surely there must be faster
methods of transferring the image data, but I guess that sample
would work fine for small images.
Do you know why it is always 8bpp. Other formats such as 4bpp are possible
but never seem to be saved by GDI+

The GDI+ codecs are extremely limited. Use a proper image library if
you need anything other than the most basic formats.
Also, I found Q319061 when I was looking for the file format for a GIF file
(read via a stream) if you know where that is I'd appreciate the link.

A link to the gif specification?
http://www.w3.org/Graphics/GIF/spec-gif89a.txt

Surely you are not thinking about converting raw<->gif yourself?
Too much work. No need to reinvent the wheel.

Yes, Q319061 seems to hold all the answers we (you) were looking
for.

Regards,

Joergen Bech
 
The GDI+ codecs are extremely limited. Use a proper image library if
you need anything other than the most basic formats.

You don't know of a free one do you?
A link to the gif specification?
http://www.w3.org/Graphics/GIF/spec-gif89a.txt
thanks


Surely you are not thinking about converting raw<->gif yourself?
Too much work. No need to reinvent the wheel.
No. Maybe just reading things like the Color Resolution because I don't
know what's in the file and what GDI+ did to the data.
 
You don't know of a free one do you?

Not really. There are free or open source imaging libraries around,
but they usually add functionality not found in GDI+ rather than
completely replacing GDI+

What you want is probably something that allows you to control
the image format and perform image operations within that format
without ever going to 32-bit and back again, which GDI+ is likely
to force you to do. Something like LeadTools, which will set you back
a pretty penny.

I have yet to find a freeware imaging library that completely replaces
GDI+ - codecs, raster operations, and all.

Even something like Paint .Net does not really let you work with
8-bit images natively. You can load and save 8-bit images, but as
soon as the image goes in, it is converted to 32-bit and the image
must be converted again if saving using one of the 8-bit formats.

Not much general interest in <32-bit imaging these days :)

/Joergen Bech
 
I would think that for the Internet if a 4-bpp would look OK it would be
preferred to 8-bpp.

Don't you think?

">
 
No, when we are dealing with low-color images in the compressed
formats (such as gif or png), it does not really matter much if the
image is stored using 16 colors or 256 colors (where the 240 colors
are unused).

As a test, I took an enormous image, reduced it to 4 colors and
saved it as a 4-bit (16MB) as well as an 8-bit (32MB) image.
I then compressed those two. The results were 1.0MB for the
4-bit version and 1.1MB for the 8-bit version.

Yes, the 8-bit version was larger, but do you really want to jump
through hoops (write a lot of code and decide on different color
depths for each image) just to save 10% or thereabouts?
I think you are optimizing before actually having tested if the
optimization is necessary.

Keep it simple. You really only need to decide between 8-bit
and lossless, 24-bit and lossy, or 24-bit and lossless. The latter
case is probably rare.

/Joergen Bech
 
Joergen Bech @ post1.tele.dk> said:
No, when we are dealing with low-color images in the compressed
formats (such as gif or png), it does not really matter much if the
image is stored using 16 colors or 256 colors (where the 240 colors
are unused).

As a test, I took an enormous image, reduced it to 4 colors and
saved it as a 4-bit (16MB) as well as an 8-bit (32MB) image.
I then compressed those two. The results were 1.0MB for the
4-bit version and 1.1MB for the 8-bit version.

Yes, the 8-bit version was larger, but do you really want to jump
through hoops (write a lot of code and decide on different color
depths for each image) just to save 10% or thereabouts?
I think you are optimizing before actually having tested if the
optimization is necessary.

I'm not doing Internet development.
It was just a random thought.

Thanks for the insight
 
Back
Top