// Last updated 2010/08/02 16:20
// This is derived from a PHP script at:
// http://eclecticdjs.com/mike/tutorials/php/imagemagick/imagickpixeliterator/3D_landscape.php
#include <windows.h>
#include <wand/magick_wand.h>
#include <time.h>
void test_wand(LPTSTR lpCmdLine)
{
MagickWand *image = NULL, *canvas = NULL;
DrawingWand *line = NULL;
PixelWand *pw = NULL;
int w,h;
int r,g,b,grey,offset;
int start_y,end_y;
int x,y;
int line_height;
char *url,*file;
MagickWandGenesis();
// input image
// The input image is at: "http://eclecticdjs.com/mike/temp/ball/fract6.jpg"
url = "fract6.jpg";
// output image
file = "3d_fractal.jpg";
image = NewMagickWand();
pw = NewPixelWand();
MagickReadImage(image,url);
// scale it down
w = (int) MagickGetImageWidth(image);
h = (int) MagickGetImageHeight(image);
PixelSetColor(pw,"transparent");
if(MagickShearImage(image,pw,45,0) == MagickFalse)
MessageBox(NULL,"B - Shear failed","",MB_OK);
w = (int) MagickGetImageWidth(image);
h = (int) MagickGetImageHeight(image);
// scale it to make it look like it is laying down
if(MagickScaleImage(image,w,h/2) == MagickFalse)
MessageBox(NULL,"C - Scale failed","",MB_OK);
// Get image stats
w = (int) MagickGetImageWidth(image);
h = (int) MagickGetImageHeight(image);
// Make a blank canvas to draw on
canvas = NewMagickWand();
// Use a colour from the input image
MagickGetImagePixelColor(image,0,0,pw);
MagickNewImage(canvas,w,h*2,pw);
offset = h;
// The original drawing method was to go along each row from top to bottom so that
// a line in the "front" (which is one lower down the picture) will be drawn over
// one behind it.
// The problem with this method is that every line is drawn even if it will be covered
// up by a line "in front" of it later on.
// The method used here goes up each column from left to right and only draws a line if
// it is longer than everything drawn so far in this column and will therefore be visible.
// With the new drawing method this takes 13 secs - the previous method took 59 secs
// loop through all points in image
for(x=0;x<w;x++) {
// The PHP version created, used and destroyed the drawingwand inside
// the inner loop but it is about 25% faster to do only the DrawLine
// inside the loop
line = NewDrawingWand();
line_height = 0;
for(y=h-1;y>=0;y--) {
// get (r,g,b) and grey value
if(MagickGetImagePixelColor(image,x,y,pw) == MagickFalse)continue;
// 255* adjusts the rgb values to Q8 even if the IM being used is Q16
r = (int) (255*PixelGetRed(pw));
g = (int) (255*PixelGetGreen(pw));
b = (int) (255*PixelGetBlue(pw));
// Calculate grayscale - a divisor of 10-25 seems to work well.
// grey = (r+g+b)/25;
grey = (r+g+b)/15;
// grey = (r+g+b)/10;
// Only draw a line if it will show "above" what's already been done
if(line_height == 0 || line_height < grey) {
DrawSetFillColor(line,pw);
DrawSetStrokeColor(line,pw);
// Draw the part of the line that is visible
start_y = y+offset - line_height;
end_y = y-grey+offset;
DrawLine(line,x,start_y,x,end_y);
line_height = grey;
}
line_height--;
}
// Draw the lines on the image
MagickDrawImage(canvas,line);
DestroyDrawingWand(line);
}
MagickScaleImage(canvas,w-h,h*2);
// write canvas
MagickWriteImage(canvas,file);
// clean up
DestroyMagickWand(canvas);
DestroyMagickWand(image);
DestroyPixelWand(pw);
MagickWandTerminus();
}