I have a 32bpp bitmap image which has an alpha channel with values ranging from 0-255. I am trying to display this in a window using win32 APIs (snippet of code I am using to display is appended).
I was reading the documentation and it turns out that for blending, in the case where I want to use per-pixel values, windows uses the following formula:
Dst.Red = Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Blue + (1 - Src.Alpha) * Dst.Blue
This is weird. I would have expected it to use:
Dst.Red = Src.Alpha*Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Alpha*Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Alpha*Src.Blue + (1 - Src.Alpha) * Dst.Blue
because that is what creates the overlay effect (translucency).
Is my expectation correct? If yes, why is windows doing the blending in this manner? What am I missing here?
snippet of code I am using to paint the Layered Window:
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
POINT ptOrigin = { 0, 0 };
SIZE windowSize = { 300, 300 };
POINT ptZero = { 0, 0 };
UpdateLayeredWindow(m_sThis->m_hWnd, dc, &ptOrigin, &windowSize,
hdc, &ptZero, RGB(255, 255, 255), &bf, ULW_ALPHA);
From the documentation:
Note that the APIs use premultiplied alpha, which means that the red,
green and blue channel values in the bitmap must be premultiplied with
the alpha channel value. For example, if the alpha channel value is x,
the red, green and blue channels must be multiplied by x and divided
by 0xff prior to the call.
So, you are right, but you have to do it by hand before.
Related
I know already why it gives that error code-wise.
Problem is, I started using the library itself today and following the tutorial I found this.
I installed the "ImageMagick-7.0.9-1-Q16-x64-dll" version of the library, and tried to find the shortest code that gave that error, which is:
#include <Magick++.h>
int main(){
Magick::Quantum result = Magick::Color("black");
}
Given the tutorial(following one), a method that converts from Magick::Color to Magic::Quantum should exist
// Example of using an image pixel cache
Image my_image("640x480", "white"); // we'll use the 'my_image' object in this example
my_image.modifyImage(); // Ensure that there is only one reference to
// underlying image; if this is not done, then the
// image pixels *may* remain unmodified. [???]
Pixels my_pixel_cache(my_image); // allocate an image pixel cache associated with my_image
Quantum* pixels; // 'pixels' is a pointer to a Quantum array
// define the view area that will be accessed via the image pixel cache
int start_x = 10, start_y = 20, size_x = 200, size_y = 100;
// return a pointer to the pixels of the defined pixel cache
pixels = my_pixel_cache.get(start_x, start_y, size_x, size_y);
// set the color of the first pixel from the pixel cache to black (x=10, y=20 on my_image)
*pixels = Color("black");
// set to green the pixel 200 from the pixel cache:
// this pixel is located at x=0, y=1 in the pixel cache (x=10, y=21 on my_image)
*(pixels+200) = Color("green");
// now that the operations on my_pixel_cache have been finalized
// ensure that the pixel cache is transferred back to my_image
my_pixel_cache.sync();
which gives that error ( no suitable conversion function from "Magick::Color" to "MagickCore::Quantum" exists ) at the following lines
*pixels = Color("black");
*(pixels+200) = Color("green");
I believe you are confusing a data-type with a structure. The pixels represents a continuous list of Quantum parts.
Assuming that we're working with RGB colorspace. You would need to set each color part.
Color black("black");
*(pixels + 0) = black.quantumRed();
*(pixels + 1) = black.quantumGreen();
*(pixels + 2) = black.quantumBlue();
To set the 200th pixel, you would need to multiply the offset by the parts-per-pixel count.
Color green("green");
int offset = 199 * 3; // First pixel starts at 0, and 3 parts (Red, Green, Blue)
*(pixels + offset + 0) = green.quantumRed();
*(pixels + offset + 1) = green.quantumGreen();
*(pixels + offset + 2) = green.quantumBlue();
I have a problem with displaying alpha transparency using GTK and Cairo. I try to display this image 1
If I do the alpha blending my self, everything works.
If I pass the alpha values directly to Cairo, the shadow seems to render fine, but the glow effect is corrupted.
Is this a bug in Cairo 1.14.2, or am I missing something?
//Need deprecated API to get background color
GdkColor color = gtk_widget_get_style(widget)->bg[GTK_STATE_NORMAL];
Pixel color_blend
{
uint8_t(255*color.red/65535.0f)
,uint8_t(255*color.green/65535.0f)
,uint8_t(255*color.blue/65535.0f)
,255
};
while(ptr!=ptr_end)
{
// TODO: Interpolate
auto row_src=size_t(row*factor);
auto col_src=size_t(col*factor);
auto alpha=ptr_src[row_src*width_in + col_src].v3/255.0f;
*ptr=
{
// Using manual alpha blend works
uint8_t(alpha*ptr_src[row_src*width_in + col_src].v2 + (1-alpha)*color_blend.v2)
,uint8_t(alpha*ptr_src[row_src*width_in + col_src].v1 + (1-alpha)*color_blend.v1)
,uint8_t(alpha*ptr_src[row_src*width_in + col_src].v0 + (1-alpha)*color_blend.v0)
,255
/* This appears to be broken
ptr_src[row_src*width_in + col_src].v2
,ptr_src[row_src*width_in + col_src].v1
,ptr_src[row_src*width_in + col_src].v0
,ptr_src[row_src*width_in + col_src].v3*/
};
++col;
if(col==width_out)
{
col=0;
++row;
}
++ptr;
}
I push the pixels using
auto surface=cairo_image_surface_create_for_data((uint8_t*)pixels.begin(),CAIRO_FORMAT_ARGB32,width_out,height_out,width_out*sizeof(Pixel));
cairo_set_source_surface(cr, surface, 0.5*(width-width_out), 0.0);
cairo_paint(cr);
cairo_surface_destroy(surface);
Explicitly setting the operator to CAIRO_OPERATOR_OVER does not help, the result is still the same.
As you mention in your comment above, your pixel values are wrong. You need to use pre-multiplied alpha. Coming back to my example from the question (and ignoring endianness), fully red with 50% transparency is 0x7f << 24 | 0x7f in Cairo. Pixels with invalid values (some color component is larger than the alpha value) produce undefined results and your 0xff << 24 | 0x7f falls into this category.
See http://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t:
Pre-multiplied alpha is used. (That is, 50% transparent red is
0x80800000, not 0x80ff0000.)
P.S.: In my opinion, the correct way to access pixel data is via a uint32_t and shifting, e.g. uint32_t pixel = (r << 24) | (g << 16) | (b << 8) | a;. That way you don't have to worry about endianness at all.
P.P.S.: For OVER and a fully-opaque target, the formula Cairo uses simplifies to source_color + target_color * (1 - source_alpha) while your code uses source_color * source_alpha + target_color * (1 - source_alpha). See http://www.cairographics.org/operators/. These two formulas clearly are not equivalent.
Edit: Ok, perhaps they are equivalent when using pre-multiplie alpha. Sorry for the confusion there.
I'm working with an older C++ application and I need to draw text centered and rotated on an hDC. I've got the centered & rotated part working but the font that gets written to the Image is smaller than I'm expecting. If you take an Image and edit it or a word document and add a line of of Text "COPY" in font size 128 it fills up most of the width of the page. With my code it only covers about 1/3 of the page. What am I missing or doing wrong?
UINT nOptions = 0;//DT_CENTER;
RECT rect = {0,0, BITMAPWIDTH(&WatermarkHandle), BITMAPHEIGHT(&WatermarkHandle)}; //{0,0,FileInfo.Width, FileInfo.Height};
SetMapMode(hdcWatermark, MM_TEXT);
LOGFONT lf;
memset(&lf, 0, sizeof(lf));
lstrcpy(lf.lfFaceName, &sWatermarkFontName[0]);
lf.lfHeight = -MulDiv(lWatermarkFontSize, GetDeviceCaps(hdcWatermark, LOGPIXELSY), 72);
lf.lfEscapement = lWatermarkAngle * 10;
lf.lfOrientation = lf.lfEscapement;
lf.lfClipPrecision = CLIP_LH_ANGLES;// || CLIP_TT_ALWAYS;
lf.lfWeight = FW_THIN;
SetTextColor(hdcWatermark, black);
DrawRotatedText(hdcWatermark, &sWatermarkText[0], &rect, lf, lWatermarkAngle, nOptions);
void DrawRotatedText(HDC hdc, char *str, LPRECT rect, LOGFONT lf, double angle, UINT nOptions)
{
// convert angle to radian
double pi = 3.141592654;
double radian = (angle / 180 * pi);
HFONT hFontText = CreateFontIndirect(&lf);
HFONT hOldFontText = (HFONT)SelectObject(hdc, hFontText);
SIZE TextSize;
GetTextExtentPoint32(hdc, str, strlen(str), &TextSize);
// get the center of a not-rotated text
POINT center;
center.x = TextSize.cx / 2;
center.y = TextSize.cy / 2;
POINT rcenter;
rcenter.x = long(cos(radian) * center.x - sin(radian) * center.y);
rcenter.y = long(sin(radian) * center.x + cos(radian) * center.y);
// finally draw the text and move it to the center of the rectangle
SetTextAlign(hdc, TA_BASELINE);
SetBkMode(hdc, TRANSPARENT);
long lx = rect->left + ((rect->right - rect->left) / 2) - rcenter.x;
long ly = rect->top + ((rect->bottom - rect->top) / 2) + rcenter.y;
SetGraphicsMode(hdc,GM_ADVANCED);
ExtTextOut(hdc, lx, ly, nOptions, rect, str, strlen(str), NULL);
DeleteObject(hFontText);
SelectObject(hdc, hOldFontText);
return;
}
It all depends on what you mean by a "page".
A point is a physical unit of measure, just like an inch or a millimeter. In most modern contexts it's equal to 1/72 of an inch.
A page in Word corresponds to an actual piece of paper with physical dimensions. After subtracting out the margins it might be 6 inches wide, or 432 points. This will be zoomed by an amount to fill the screen.
Sizing a screen is a little more nebulous, since monitor sizes and resolutions may differ. Long ago Windows standardized on 96 pixels per inch for a default, as this was close enough to the typical monitor connected to a Windows system. This means a 1920x1080 monitor is considered by Windows to be 20 inches wide, or 1440 points, no matter how physically large it is.
In Word's case the screen is 432 points wide, while your program considers it to be 1440 points wide. This is very close to the 1/3 ratio you report. If you set Word to an exact 100% zoom the rendered text should be identical because the page will shrink.
The answer is to do as Word does, and zoom in by making everything 3x larger.
Edit: In your case it seems you want to emulate what Word is doing and show a facsimile of a page. That makes it even easier.
The formula given by Microsoft was from a time when floating point arithmetic was slow and avoided whenever possible. That's not the case today. The equivalent is:
lfHeight = -(int)(points * dpi / 72);
The question is what to use for dpi? You can calculate it directly! Since you know the size of the page you're displaying and the width of the window in pixels, it's a simple division:
double dpi = pixelWidth / (double)inches;
If you need to know what the effective zoom is, that's also a simple division: zoom = dpi / GetDeviceCaps(hdc, LOGPIXELSY).
I need to create a colorbar like THIS
I use a scaled array of floats between 0 and 1.
Now I want to compute the RGB color from this float. How to do it? Want to write it in C/c++ so I think I need 2 functions.
The first function to build the colorbar with one parameter like STEPSIZE and the second function need the value and must just return the array index of the colorbar.
I couldn't find it on google, so please help me.
What you are referring to here is the 100% EBU Color Bars (named after the standards body, the European Broadcasting Union). This is not the same as the full SMPTE RP 219-2002 color bars, which have other features including gradients and the PLUGE (Picture Line-Up Generation Equipment), described in the Wikipedia article on Color Bars.
The EBU Color Bars consist of 8 vertical bars of equal width. They are defined in the same way for both SD and HD formats. In the RGB color space, they alternate each of the red, green and blue channels at different rates (much like counting in binary) from 0 to 100% intensity. Counting down from white, in normalised RGB form (appearing left to right):
1, 1, 1: White
1, 1, 0: Yellow
0, 1, 1: Cyan
0, 1, 0: Green
1, 0, 1: Magenta
1, 0, 0: Red
0, 0, 1: Blue
0, 0, 0: Black
So the blue channel alternates every column, the red channel after two columns, and the green after four columns. This arrangement has the useful property that the luminance (Y in YCb'Cr' colour space) results in a downward stepping plot.
To render using 8-bit RGB (most commonly found in desktop systems), simply multiply the above values by 255. The EBU bars come in 75% and 100% variants, based on the intensity of the white column. The SMPTE color bars typically use 75% levels as a reference.
Here is some simple C code to generate 100% EBU color bars and save the result as a PGM file:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
// PAL dimensions
static const unsigned kWidth = 720;
static const unsigned kHeight = 576;
typedef struct
{
uint8_t r;
uint8_t g;
uint8_t b;
} RGB;
int main(int argc, char* argv[])
{
const RGB BAR_COLOUR[8] =
{
{ 255, 255, 255 }, // 100% White
{ 255, 255, 0 }, // Yellow
{ 0, 255, 255 }, // Cyan
{ 0, 255, 0 }, // Green
{ 255, 0, 255 }, // Magenta
{ 255, 0, 0 }, // Red
{ 0, 0, 255 }, // Blue
{ 0, 0, 0 }, // Black
};
// Allocate frame buffer
size_t frameBytes = kWidth*kHeight*sizeof(RGB);
RGB* frame = malloc(frameBytes);
unsigned columnWidth = kWidth / 8;
// Generate complete frame
for (unsigned y = 0; y < kHeight; y++)
{
for (unsigned x = 0; x < kWidth; x++)
{
unsigned col_idx = x / columnWidth;
frame[y*kWidth+x] = BAR_COLOUR[col_idx];
}
}
// Save as PPM
FILE* fout = fopen("ebu_bars.ppm", "wb");
fprintf(fout, "P6\n%u %u\n255\n", kWidth, kHeight);
fwrite(frame, frameBytes, 1, fout);
fclose(fout);
free(frame);
return 0;
}
This should be readily adaptable to any other language. There's probably no need for using float unless you're implementing this on a GPU (in which case the algorithm would be quite different). There is much scope for optimization here; the code is written for clarity, not speed.
Note that while it is possible to generate a perfect digital representation of the color bars in a computer, this will not be safe for broadcast. The transitions between "perfect" color bars would require infinitely high bandwidth to accurately represent. So if the test image is to be transmitted via analog broadcast equipment, it must be bandwidth-limited by a low-pass filter (eg. ~4.3MHz for PAL). This is why you notice the "fuzzy" boundaries in between each column; these contain intermediate values between the pure colors.
Also note that it is not possible to accurately represent the SMPTE color bars in the RGB color space. This is because certain critical values are specified in the YCb'Cr' color space (notably in the PLUGE region) which are outside the gamut of RGB (either SD or HD). You can create something that approximates the values (eg. a very dark blue) but they are not correct. So unless you are representing the test frame in YCb'Cr', stick to EBU bars only (the upper 2/3).
RGB uses bytes, so assuming your array of floats is something like
float scaledColor[3]; // 0 = R, etc., all 0.0 < scaledColor[x] < 1.0
then you can do:
unsigned char r = (unsigned char)(255 * scaledColor[0]);
unsigned char g = (unsigned char)(255 * scaledColor[1]);
unsigned char b = (unsigned char)(255 * scaledColor[2]);
This will of course only work if the values in the floats are really in the range from 0.0 to 1.0.
The simplest solution:
const unsigned char* getColour(float x) /* 0 <= x < 1 */
{
static const unsigned char bar[][3] = {
{255,255,255},
{255,255,0},
// ... fill in all the colours ...
{0,0,0}
};
return bar[(int)(x*sizeof(bar))];
}
Then you can use it to generate bars of any width.
My google-fu turned up that you want the upper third of a SMPTE color bar pattern.
Wikipedia says:
In order from left to right, the colors are gray, yellow, cyan, green,
magenta, red, and blue.
So the easiest way is to simply hard code the respective RGB color codes if you only need those. The article also mentions how those colors can be generated but this seems a lot more difficult and isn't really worth the effort for seven colors.
I have a pointer to an 32bit argb image's pixel data and a 32bit xrgb image's pixel data. How can I composite the argb on top of xrgb image while making use of the alpha component?
Visual Studio 2008 C++
Edit:
Is there a quicker (faster processing) way to do the compositing than this:
float alpha = (float)Overlay[3] / 255;
float oneLessAlpha = 1 - alpha;
Destination[2] = (Overlay[2] * alpha + Background[2] * oneLessAlpha);
Destination[1] = (Overlay[1] * alpha + Background[1] * oneLessAlpha);
Destination[0] = (Overlay[0] * alpha + Background[0] * oneLessAlpha);
This depends on what you are trying to achieve. You can assume your second image to have an alpha of 255 everywhere, then compose each pixel by linear interpolation / alpha blending (assuming float values in [0,1], adjust accordingly):
out(x,y) = argb(x,y).rgb * argb(x,y).a + xrgb(x,y).rgb * (1.-argb(x.y).a)
This way, all pixel with no transparency from your argb image will be always displayed "atop", while pixels with full transparency are invisible and replaced by those from the xrgb pixels. All pixels inbetween are linearly blended.
Presumably by XRGB you mean a bitmap with four bytes per pixel, but what would be the alpha channel left at some constant value.
An obvious starting point would be to draw the XRGB bitmap first, and the RGBA bitmap second. When you draw the second, enable blending (glEnable(GL_BLEND);) and set your blend function with glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);. This way the blending depends only on the alpha channel in the source (the RGBA) and ignores any in the destination (the XRGB bitmap that's already been drawn).
Edit: Oops -- somehow I thought I saw some reference to OpenGL, but rereading (and noting the comment) no such thing is there. Doing the job without OpenGL isn't terribly difficult, just generally slower. Let's call the pixels from the two input bitmaps S and D, and the corresponding pixel in the result C. In this case we can compute each pixel in C as:
Cr = Sr * Sa + Dr * (1-Sa)
Cg = Sg * Sa + Dg * (1-Sa)
Cb = Sb * Sa + Db * (1-Sa)
This assumes that you normalize (at least) the A channel to the range of 0..1, and that the ARGB bitmap is S and the XRGB is D.
Here's some code that should work more or less (didn't test it, no compiler on this machine...).
DWORD* pSrc; // Pointer to current row of ARGB bitmap
DWORD* pDst; // Pointer to current row of XRGB bitmap
...
BYTE* src_r = GetRValue(*pSrc);
BYTE* src_g = GetGValue(*pSrc);
BYTE* src_b = GetBvalue(*pSrc);
BYTE* src_a = *pSrc >> 24;
BYTE* dst_r = GetRValue(*pDst);
BYTE* dst_g = GetGValue(*pDst);
BYTE* dst_b = GetBvalue(*pDst);
BYTE* dst_a = 255 - src_a;
*pDst = RGB(((src_r * src_a) + (dst_r * dst_a)) >> 8,
((src_g * src_a) + (dst_g * dst_a)) >> 8,
((src_b * src_a) + (dst_b * dst_a)) >> 8);