|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionLook at the picture above. It looks like an ordinary picture of bad quality. But if you select the image (with the mouse or press Ctrl-A), the image will change. There is no script or something else which changes the picture. Cool, isn't it? I have written a Windows application which can be used to generate such magic images. You just have to select the front and the back (the hidden one) image and the program will generate the magic image. You also can adjust contrast and opacity to improve the appearance.
The small but powerful application consists of a web browser control that displays the result image, and the panel on the right where you can adjust the parameters. Open the 'New Image' dialog in the main menu to specify the output image and the two input images and hit the 'Generate' button. Additionally, you can adjust contrast and opacity. Hit the 'Refresh' button to re-generate the magic image. How to generate 'Magic' imagesFor better understanding, I will give a short description of how to build such images with Adobe PhotoShop, before I will start to explain the code.
You can test it by opening the picture in Microsoft Internet Explorer and hit Ctrl-A to select all. About the codeAll the work is done in the This function iterates through all pixels on the hidden image and inverts every pixel that matches the pattern above. To invert a pixel, we simply have to subtract the color value from 255. For further information on Image Processing, see Christian Graus's articles on Image Processing. The following code operation matches steps 2-9 of How to generate 'Magic' images. ...
// lock the bits
BitmapData bmData =
bHidden.LockBits( new Rectangle(0, 0, bHidden.Width, bHidden.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte * p = (byte *)(void *)Scan0;
int nOffset = stride - bHidden.Width*3;
for ( int y=0; y<bHidden.Height; ++y)
{
for ( int x=0; x<bHidden.Width; ++x )
{
// every pixel that matches the pattern will be inverted
if ( (x+y) % 2 == 0 )
{
// invert color blue, green, red
for ( int i=0; i<3; i++ )
p[i] = (byte)(255-p[i]);
}
...
p += 3;
}
p += nOffset;
}
}
bHidden.UnlockBits(bmData);
...
Now, we have to change the contrast of the picture. (Step 10 of How to generate 'Magic' images). ...
// initialize contrast values
if (nContrast < -100) return null;
if (nContrast > 100) return null;
double pixel = 0, contrast = (100.0+nContrast)/100.0;
contrast *= contrast;
// lock the bits
BitmapData bmData =
bHidden.LockBits( new Rectangle(0, 0, bHidden.Width, bHidden.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte * p = (byte *)(void *)Scan0;
int nOffset = stride - bHidden.Width*3;
for ( int y=0; y<bHidden.Height; ++y)
{
for ( int x=0; x<bHidden.Width; ++x )
{
...
// we will change the contrast for every pixel ( blue, green, red )
for ( int i=0; i<3; i++ )
{
pixel = p[i]/255.0;
pixel -= 0.5;
pixel *= contrast;
pixel += 0.5;
pixel *= 255;
if (pixel < 0) pixel = 0;
if (pixel > 255) pixel = 255;
p[i] = (byte) pixel;
}
p += 3;
}
p += nOffset;
}
}
bHidden.UnlockBits(bmData);
...
Finally, we have to add the front image and change the opacity of the front image. (Step 11-13 of How to generate 'Magic' images.) ...
// the following code draws the front image over
// the hidden image using the alpha blending effect
Graphics g = Graphics.FromImage( bHidden );
float[][] ptsArray ={ new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, opacity, 0},
new float[] {0, 0, 0, 0, 1}};
ColorMatrix clrMatrix = new ColorMatrix( ptsArray );
ImageAttributes imgAttributes = new ImageAttributes();
imgAttributes.SetColorMatrix( clrMatrix,
ColorMatrixFlag.Default, ColorAdjustType.Bitmap );
g.DrawImage( bFront, new Rectangle( 0, 0, bFront.Width, bFront.Height ), 0, 0,
bFront.Width, bFront.Height, GraphicsUnit.Pixel, imgAttributes );
// return the result image
Bitmap bResult = new Bitmap( bHidden.Width, bHidden.Height );
bResult = (Bitmap)bHidden.Clone();
return bResult;
...
Here is the whole public Bitmap GenerateMagicImage(Bitmap bHidden,
Bitmap bFront, sbyte nContrast, float opacity )
{
// initialize contrast values
if (nContrast < -100) return null;
if (nContrast > 100) return null;
double pixel = 0, contrast = (100.0+nContrast)/100.0;
contrast *= contrast;
// lock the bits
BitmapData bmData =
bHidden.LockBits( new Rectangle(0, 0, bHidden.Width, bHidden.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte * p = (byte *)(void *)Scan0;
int nOffset = stride - bHidden.Width*3;
for(int y=0; y<bHidden.Height; ++y)
{
for(int x=0; x<bHidden.Width; ++x )
{
// every pixel that matches the pattern will be inverted
if ( (x+y) % 2 == 0 )
{
// invert color blue, green, red
for ( int i=0; i<3; i++ )
p[i] = (byte)(255-p[i]);
}
// we will change the contrast
// for every pixel ( blue, green, red )
for ( int i=0; i<3; i++ )
{
pixel = p[i]/255.0;
pixel -= 0.5;
pixel *= contrast;
pixel += 0.5;
pixel *= 255;
if (pixel < 0) pixel = 0;
if (pixel > 255) pixel = 255;
p[i] = (byte) pixel;
}
p += 3;
}
p += nOffset;
}
}
bHidden.UnlockBits(bmData);
// the following code draws the front image over the hidden
// image using the alpha blending effect
Graphics g = Graphics.FromImage( bHidden );
float[][] ptsArray ={ new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, opacity, 0},
new float[] {0, 0, 0, 0, 1}};
ColorMatrix clrMatrix = new ColorMatrix( ptsArray );
ImageAttributes imgAttributes = new ImageAttributes();
imgAttributes.SetColorMatrix( clrMatrix,
ColorMatrixFlag.Default, ColorAdjustType.Bitmap );
g.DrawImage( bFront,
new Rectangle( 0, 0, bFront.Width, bFront.Height ), 0, 0,
bFront.Width, bFront.Height,
GraphicsUnit.Pixel, imgAttributes );
// return the result image
Bitmap bResult = new Bitmap( bHidden.Width, bHidden.Height );
bResult = (Bitmap)bHidden.Clone();
return bResult;
}
The selecting and unselecting of the image is done using the // execute the select all command for the web browser control
Object o = new Object();
SHDocVw.OLECMDID SelectAllCommand = SHDocVw.OLECMDID.OLECMDID_SELECTALL;
SHDocVw.OLECMDEXECOPT exeOpt = SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT;
preview.ExecWB(SelectAllCommand, exeOpt, ref o, ref o);
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||