I'm a newbie programmer. Is there any algorithm to convert an image to 16-bit or 8-bit? I didn't find it on google, I'am desperate.
Asked
Active
Viewed 6,255 times
3 Answers
1
Changing to 16 bit is the easier one. Assuming that the original image is in image
, you can simply draw it into the result.
Bitmap result = new Bitmap(image.Width, image.Height, PixelFormat.Format16bppRgb565);
using (Graphics g = Graphics.FromImage(result))
{
g.DrawImage(image, 0, 0, image.Width, image.Height);
}
Unfortunately, this does not work for indexed images (images with palette, up to 256 colors). But you can find a solution in my answer here, see the ConvertPixelFormat
method.

Community
- 1
- 1

György Kőszeg
- 17,093
- 6
- 37
- 65
0
The only difference between 16 bit rgb and 8 bit rgb is the range, 16 bit has values form 0 to 65536 while 8 bit has values from 0 to 256, hence you should just be able to devide a 16 bit rgb value by 256 using integer division (for simplicity) and that will be it converted. (You need to decide the value in each plane by 256)

Cjen1
- 1,826
- 3
- 17
- 47
-
That's not true at all. 8-bit images are indexed, meaning the value on the pixel in the image is not the colour but a reference to a table of 256 colours. 16 bit images actually contain a full RGB colour inside the 16 bit pixel value. – Nyerguds Jan 07 '18 at 18:57
-
@Nyerguds that is for the Gif format to save on space. For a generic RGB (bitmap style) image (arbitrary precision of colour) it is normally stored as 3 greyscale bitmaps of the requisite size (8 bit, 16 bit, 23 bit...) denoting the red channel, green channel and blue channel. – Cjen1 Jan 08 '18 at 22:25
-
Are you talking about planar images? Three planes with 8-bit values is still a 24-bit image, you know. The way it's saved doesn't change that; in terms of quality (and size) it's identical to having RGB triplets per pixel. Actual 8-bit images literally have only one byte per pixel, which is not enough to save meaningful RGB information, so images with 8bpp or lower [are _always_ indexed](https://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat). This is completely unrelated to what file type it is saved in; you can have 8 bit BMP or PNG too, and it's the same. – Nyerguds Jan 09 '18 at 07:55
-
By the way, no image format in the .Net framework uses planar, and I don't know any file formats that use it either, except some raw camera ones and some very old bit-planar EGA game formats. – Nyerguds Jan 09 '18 at 08:04
0
Convert RGB image to 8-bit
public static Bitmap ConvertFromRGBTo8bit(this Bitmap rgbBmp)
{
// Copy image to byte Array
var BoundsRectSrc = new Rectangle(0, 0, rgbBmp.Width, rgbBmp.Height);
BitmapData bmpDataSrc = rgbBmp.LockBits(BoundsRectSrc, ImageLockMode.WriteOnly, rgbBmp.PixelFormat);
IntPtr ptrSrc = bmpDataSrc.Scan0;
int imgSizeSrc = bmpDataSrc.Stride * rgbBmp.Height;
byte[] rgbValues = new byte[imgSizeSrc];
Marshal.Copy(ptrSrc, rgbValues, 0, imgSizeSrc);
// Crearte bitmap with 8 index grayscale
Bitmap newBmp = new Bitmap(rgbBmp.Width, rgbBmp.Height, PixelFormat.Format8bppIndexed);
ColorPalette ncp = newBmp.Palette;
for (int i = 0; i < 256; i++)
ncp.Entries[i] = Color.FromArgb(255, i, i, i);
newBmp.Palette = ncp;
var BoundsRectDst = new Rectangle(0, 0, rgbBmp.Width, rgbBmp.Height);
BitmapData bmpDataDst = newBmp.LockBits(BoundsRectDst, ImageLockMode.WriteOnly, newBmp.PixelFormat);
IntPtr ptrDst = bmpDataDst.Scan0;
int imgSizeDst = bmpDataDst.Stride * newBmp.Height;
byte[] grayValues = new byte[imgSizeDst];
// Convert image to 8 bit according average pixel
if (rgbBmp.PixelFormat == PixelFormat.Format16bppRgb555 || rgbBmp.PixelFormat == PixelFormat.Format16bppRgb565)
for (int i = 0, j = 0; i < grayValues.Length; i++, j += 2)
grayValues[i] = (byte)((rgbValues[j] + rgbValues[j + 1]) / 2);
else if (rgbBmp.PixelFormat == PixelFormat.Format24bppRgb)
for (int i = 0, j = 0; i < grayValues.Length; i++, j += 3)
grayValues[i] = (byte)((rgbValues[j] + rgbValues[j + 1] + rgbValues[j + 2]) / 3);
else if (rgbBmp.PixelFormat == PixelFormat.Format32bppRgb)
for (int i = 0, j = 0; i < grayValues.Length; i++, j += 4)
grayValues[i] = (byte)((rgbValues[j] + rgbValues[j + 1] + rgbValues[j + 2] + rgbValues[j + 3]) / 4);
Marshal.Copy(grayValues, 0, ptrDst, imgSizeDst);
newBmp.UnlockBits(bmpDataDst);
rgbBmp.UnlockBits(bmpDataSrc);
return newBmp;
}

Effi Barak
- 1
- 1
-
That converts to _grayscale_ 8-bit though. Actual colour reduction is quite a bit harder. – Nyerguds Jul 06 '17 at 08:25