C++: преобразование 24 бит / дюйм в 8 бит / дюйм или 1 бит / дюйм изображения
Я должен преобразовать 24bpp
изображение к 1bpp
изображение или 8bpp
изображение на основе таблицы цветов. Звонящий ожидает unsigned char*
в любом случае (который будет дополнительно обработан или, может быть, пока отладочный вывод, отправив BITMAPINFOHEADER.biBitCount
к его правильному значению, 8 или 1).
У меня есть код для извлечения индекса цвета в палитре (colorIndexArray из алгоритмов преобразования цветов или сглаживания)... Я могу получить информацию для растрового изображения 8bpp...
Но моя проблема в том, что я не знаю, как поместить эту информацию в растровое изображение 1bpp
typedef struct {
unsigned int size;
unsigned char* pixels;
} ColorIndexArray;
unsigned char* convertImage(const ColorIndexArray& colorIndexArray, unsigned int paletteSize)
{
unsigned char* outputImage;
if (paleteSize > 2)
{
outputImage = (unsigned char*)LocalAlloc(LPTR, colorIndexArray.size);
for (int i=0; i<colorIndexArray.size; i++)
*(outputImage+i) = colorIndexArray.pixels[i];
// this works great
}
else // monochrome, caller has palette colors likely b/w (or purple/magenta or anything), must be 1bpp
{
outputImage = (unsigned char*)LocalAlloc(LPTR, colorIndexArray.size / 8);
// how can i place the unsigned char* info (which is already
// determined based on desired algorithm, representing index in
// color table) into the output image inside a single bit ?
// (obviously its value for a monochrome image would be 0 or 1 but
// it is saved as unsigned char* at the algorithm output)
// And how do I advance the pointer ?
// Will it be type safe ? Aligned to byte ? or do I have to fill
// with something at the end to make multiple of 8 bits ?
}
return outputImage;
}
Попытка это после предложения комментария:
#include <GdiPlus.h>
....
else {
Gdiplus::Bitmap monoBitmap(w, h, PixelFormat1bppIndexed);
Gdiplus::BitmapData monoBitmapData;
Gdiplus::Rect rect(0, 0, w, h);
monoBitmap.LockBits(&rect, Gdiplus::ImageLockModeWrite, PixelFormat1bppIndexed, &monoBitmapData);
outputImage = (unsigned char*)monoBitmapData.Scan0;
for (unsigned int y = 0; y < h; y++)
{
for (unsigned int x = 0; x < w; x++)
{
if (colorIndexArray.pixels[x + y * w])
outputImage[y*monoBitmapData.Stride + x / 8] |= (unsigned char)(0x80 >> (x % 8));
}
}
monoBitmap.UnlockBits(&monoBitmapData);
}
return outputImage;
(Также необходимо выделить память для outputImage)
1 ответ
Основываясь на примере, предложенном Хансом Пассантом (спасибо вам также за то, что вы указали, как важен этот шаг), я написал это небольшое обращение
unsigned long stride = (((w + 31) & ~31) >> 3);
outputImage = (unsigned char*)LocalAlloc(LPTR, stride * h);
for (unsigned int y = 0; y < h; y++)
{
unsigned char* b = (unsigned char*)LocalAlloc(LPTR, stride);
for (unsigned int x = 0; x < w; x++)
if (colorIndexArray.pixels[x + y * w])
b[x / 8] |= (unsigned char)(0x80 >> (x % 8));
CopyMemory(outputImage + stride * y, b, stride);
}