func main() { imagick.Initialize() defer imagick.Terminate() mw := imagick.NewMagickWand() defer mw.Destroy() lw := imagick.NewMagickWand() defer lw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() // Create the initial 640x480 transparent canvas pw.SetColor("none") mw.NewImage(640, 480, pw) pw.SetColor("white") dw.SetFillColor(pw) dw.RoundRectangle(15, 15, 624, 464, 15, 15) mw.DrawImage(dw) lw.ReadImage("logo:") // Note that MagickSetImageCompose is usually only used for the MagickMontageImage // function and isn't used or needed by MagickCompositeImage mw.CompositeImage(lw, imagick.COMPOSITE_OP_SRC_IN, 0, 0) /* Write the new image */ mw.WriteImage("mask_result.png") }
// Text effect 7 - Polar distortion func textEffect7() { imagick.Initialize() defer imagick.Terminate() // This one uses d_args[0] mw := imagick.NewMagickWand() defer mw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() // Create a 320x200 transparent canvas pw.SetColor("none") mw.NewImage(320, 200, pw) // Set up a 72 point font dw.SetFont("Verdana-Bold-Italic") dw.SetFontSize(72) // Now draw the text dw.Annotation(25, 65, "Magick") // Draw the image on to the mw mw.DrawImage(dw) d_args[0] = 0.0 // DON'T FORGET to set the correct number of arguments here mw.DistortImage(imagick.DISTORTION_POLAR, d_args, true) //mw.ResetImagePage("") // Trim the image again mw.TrimImage(0) // Add the border pw.SetColor("none") mw.BorderImage(pw, 10, 10) // and write it mw.WriteImage("text_polar.png") }
// Text effect 2 - tiled text using the builtin checkerboard pattern // Anthony's Tiled Font effect func textEffect2() { imagick.Initialize() defer imagick.Terminate() mw := imagick.NewMagickWand() defer mw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() setTilePattern(dw, "#check", "pattern:checkerboard") pw.SetColor("lightblue") // Create a new transparent image mw.NewImage(320, 100, pw) // Set up a 72 point font dw.SetFont("Verdana-Bold-Italic") dw.SetFontSize(72) // Now draw the text dw.Annotation(28, 68, "Magick") // Draw the image on to the mw mw.DrawImage(dw) // Trim the image mw.TrimImage(0) // Add a transparent border pw.SetColor("lightblue") mw.BorderImage(pw, 5, 5) // and write it mw.WriteImage("text_pattern.png") }
// Text effect 4 - bevelled font http://www.imagemagick.org/Usage/fonts/#bevel func textEffect4() { imagick.Initialize() defer imagick.Terminate() mw := imagick.NewMagickWand() defer mw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() // Create a 320x100 canvas pw.SetColor("gray") mw.NewImage(320, 100, pw) // Set up a 72 point font dw.SetFont("Verdana-Bold-Italic") dw.SetFontSize(72) // Set up a 72 point white font pw.SetColor("white") dw.SetFillColor(pw) // Now draw the text dw.Annotation(25, 65, "Magick") // Draw the image on to the mw mw.DrawImage(dw) // the "gray" parameter must be true to get the effect shown on Anthony's page mw.ShadeImage(true, 140, 60) pw.SetColor("yellow") dw.SetFillColor(pw) cpw := imagick.NewPixelWand() defer cpw.Destroy() cpw.SetColor("gold") mw.ColorizeImage(pw, cpw) // and write it mw.WriteImage("text_bevel.png") }
// Text effect 3 - arc font (similar to http://www.imagemagick.org/Usage/fonts/#arc) func textEffect3() { imagick.Initialize() defer imagick.Terminate() mw := imagick.NewMagickWand() defer mw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() // Create a 320x100 lightblue canvas pw.SetColor("lightblue") mw.NewImage(320, 100, pw) // Set up a 72 point font dw.SetFont("Verdana-Bold-Italic") dw.SetFontSize(72) // Now draw the text dw.Annotation(25, 65, "Magick") // Draw the image on to the mw mw.DrawImage(dw) mw.DistortImage(imagick.DISTORTION_ARC, dargs, false) // Trim the image mw.TrimImage(0) // Add the border pw.SetColor("lightblue") mw.BorderImage(pw, 10, 10) // and write it mw.WriteImage("text_arc.png") }
// Text effect 5 and 6 - Plain text and then Barrel distortion func textEffect5And6() { imagick.Initialize() defer imagick.Terminate() // This one uses d_args mw := imagick.NewMagickWand() defer mw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() // Create a 320x100 transparent canvas pw.SetColor("none") mw.NewImage(320, 100, pw) // Set up a 72 point font dw.SetFont("Verdana-Bold-Italic") dw.SetFontSize(72) // Now draw the text dw.Annotation(25, 65, "Magick") // Draw the image on to the mw mw.DrawImage(dw) mw.WriteImage("text_plain.png") // Trim the image mw.TrimImage(0) // Add the border pw.SetColor("none") mw.BorderImage(pw, 10, 10) //mw.SetImageMatte(true) //mw.SetImageVirtualPixelMethod(TransparentVirtualPixelMethod) // d_args[0] = 0.1;d_args[1] = -0.25;d_args[2] = -0.25; [3] += .1 // The first value should be positive. If it is negative the image is *really* distorted d_args[0] = 0.0 d_args[1] = 0.0 d_args[2] = 0.5 // d_args[3] should normally be chosen such the sum of all 4 values is 1 // so that the result is the same size as the original // You can override the sum with a different value // If the sum is greater than 1 the resulting image will be smaller than the original d_args[3] = 1 - (d_args[0] + d_args[1] + d_args[2]) // Make the result image smaller so that it isn't as likely // to overflow the edges // d_args[3] += 0.1 // 0.0,0.0,0.5,0.5,0.0,0.0,-0.5,1.9 d_args[3] = 0.5 d_args[4] = 0.0 d_args[5] = 0.0 d_args[6] = -0.5 d_args[7] = 1.9 // DON'T FORGET to set the correct number of arguments here mw.DistortImage(imagick.DISTORTION_BARREL, d_args, true) //mw.ResetImagePage("") // Trim the image again mw.TrimImage(0) // Add the border pw.SetColor("none") mw.BorderImage(pw, 10, 10) // and write it mw.WriteImage("text_barrel.png") }
func main() { imagick.Initialize() defer imagick.Terminate() // Current coordinates of text var dx, dy float64 // Width of a space in current font/size var sx float64 mw := imagick.NewMagickWand() dw := imagick.NewDrawingWand() // Set the size of the image mw.SetSize(300, 100) //mw.SetImageAlphaChannel(imagick.CHANNEL_ALPHA) mw.ReadImage("xc:white") // DO NOT SET GRAVITY - it makes text placement more complicated // (unless it does exactly what you wanted anyway). // Start near the left edge dx = 10 // If we know the largest font we're using, we can set the y coordinate // fairly accurately. In this case it is the 72 point Times font, so to // place the text such that the largest almost touches the top of the image // we just add the text height to the descender to give the coordinate for // our baseline. // In this case the largest is the 72 point Times-New-Roman so I'll use that // to compute the baseline dw.SetFontSize(72) dw.SetFont("Times-New-Roman") fm := mw.QueryFontMetrics(dw, "M") dy = fm.CharacterHeight + fm.Descender // Note that we must free up the fontmetric array once we're done with it // this draw_setfont(mw, dw, "Arial", 48, "#40FF80", &sx) draw_metrics(mw, dw, &dx, dy, sx, "this") // is // A NULL signals to draw_setfont that the font stays the same draw_setfont(mw, dw, "", 24, "#8040BF", &sx) draw_metrics(mw, dw, &dx, dy, sx, "is") // my draw_setfont(mw, dw, "Times-New-Roman", 18, "#BF00BF", &sx) draw_metrics(mw, dw, &dx, dy, sx, "my") // text draw_setfont(mw, dw, "", 72, "#0F0FBF", &sx) draw_metrics(mw, dw, &dx, dy, sx, "text") mw.DrawImage(dw) // Now write the magickwand image mw.WriteImage("metric1.gif") }
// Text effect 1 - shadow effect using MagickShadowImage // NOTE - if an image has a transparent background, adding a border of any colour other // than "none" will remove all the transparency and replace it with the border's colour func textEffect1() { imagick.Initialize() defer imagick.Terminate() mw := imagick.NewMagickWand() defer mw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() pw.SetColor("none") // Create a new transparent image mw.NewImage(350, 100, pw) // Set up a 72 point white font pw.SetColor("white") dw.SetFillColor(pw) dw.SetFont("Verdana-Bold-Italic") dw.SetFontSize(72) // Add a black outline to the text pw.SetColor("black") dw.SetStrokeColor(pw) // Turn antialias on - not sure this makes a difference dw.SetTextAntialias(true) // Now draw the text dw.Annotation(25, 65, "Magick") // Draw the image on to the mw mw.DrawImage(dw) // Trim the image down to include only the text mw.TrimImage(0) // equivalent to the command line +repage mw.ResetImagePage("") // Make a copy of the text image cw := mw.Clone() // Set the background colour to blue for the shadow pw.SetColor("blue") mw.SetImageBackgroundColor(pw) // Opacity is a real number indicating (apparently) percentage mw.ShadowImage(70, 4, 5, 5) // Composite the text on top of the shadow mw.CompositeImage(cw, imagick.COMPOSITE_OP_OVER, 5, 5) cw.Destroy() cw = imagick.NewMagickWand() defer cw.Destroy() // Create a new image the same size as the text image and put a solid colour // as its background pw.SetColor("rgb(125,215,255)") cw.NewImage(mw.GetImageWidth(), mw.GetImageHeight(), pw) // Now composite the shadowed text over the plain background cw.CompositeImage(mw, imagick.COMPOSITE_OP_OVER, 0, 0) // and write the result cw.WriteImage("text_shadow.png") }
func useDraw() { imagick.Initialize() defer imagick.Terminate() /* Create a wand */ mw := imagick.NewMagickWand() defer mw.Destroy() /* Read the input image */ mw.ReadImage("logo:") fill := imagick.NewPixelWand() defer fill.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() // Set the fill to "red" or you can do the same thing with this: fill.SetColor("red") dw.SetFillColor(fill) // Uses the current Fill as the colour of the point at 200,100 dw.Point(200, 100) mw.DrawImage(dw) /* write it */ mw.WriteImage("logo_pixel_drawingwand.gif") }
// Text effect 8 - Shepard's distortion func textEffect8() { imagick.Initialize() defer imagick.Terminate() // This one uses d_args[0] mw := imagick.NewMagickWand() defer mw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() // Create a 320x200 transparent canvas pw.SetColor("none") mw.NewImage(640, 480, pw) // Set up a 72 point font dw.SetFont("Verdana-Bold-Italic") dw.SetFontSize(72) // Now draw the text dw.Annotation(50, 240, "Magick Rocks") // Draw the image on to the mw mw.DrawImage(dw) d_args[0] = 150.0 d_args[1] = 190.0 d_args[2] = 100.0 d_args[3] = 290.0 d_args[4] = 500.0 d_args[5] = 200.0 d_args[6] = 430.0 d_args[7] = 130.0 // DON'T FORGET to set the correct number of arguments here mw.DistortImage(imagick.DISTORTION_SHEPARDS, d_args, true) // Trim the image mw.TrimImage(0) // Add the border pw.SetColor("none") mw.BorderImage(pw, 10, 10) // and write it mw.WriteImage("text_shepards.png") }
func main() { imagick.Initialize() defer imagick.Terminate() /* First step is to create the gel shape: convert -size 100x60 xc:none \ -fill red -draw 'circle 25,30 10,30' \ -draw 'circle 75,30 90,30' \ -draw 'rectangle 25,15 75,45' \ gel_shape.png */ /* Create a wand */ mw := imagick.NewMagickWand() pw := imagick.NewPixelWand() dw := imagick.NewDrawingWand() mw.SetSize(100, 60) mw.ReadImage("xc:none") pw.SetColor("red") dw.SetFillColor(pw) dw.Circle(25, 30, 10, 30) dw.Circle(75, 30, 90, 30) dw.Rectangle(25, 15, 75, 45) // Now we draw the Drawing wand on to the Magick Wand mw.DrawImage(dw) mw.WriteImage("gel_shape.png") dw.Destroy() pw.Destroy() mw.Destroy() /* Next step is to create the gel highlight: convert gel_shape.png \ \( +clone -fx A +matte -blur 0x12 -shade 110x0 -normalize \ -sigmoidal-contrast 16,60% -evaluate multiply .5 \ -roll +5+10 +clone -compose Screen -composite \) \ -compose In -composite gel_highlight.png */ mw = imagick.NewMagickWand() mw.ReadImage("gel_shape.png") mwc := mw.Clone() mwf, err := mwc.FxImage("A") if err != nil { panic(err) } mwf.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_DEACTIVATE) mwf.BlurImage(0, 12) mwf.ShadeImage(true, 110, 0) mwf.NormalizeImage() // The last argument is specified as a percentage on the command line // but is specified to the function as a percentage of the QuantumRange mwf.SigmoidalContrastImage(true, 16, 0.6*imagick.QUANTUM_RANGE) mwf.EvaluateImage(imagick.EVAL_OP_MULTIPLY, 0.5) mwf.RollImage(5, 10) mwc.Destroy() // The +clone operation copies the original but only so that // it can be used in the following composite operation, so we don't // actually need to do a clone, just reference the original image. mwf.CompositeImage(mw, imagick.COMPOSITE_OP_SCREEN, 0, 0) mw.CompositeImage(mwf, imagick.COMPOSITE_OP_IN, 0, 0) mw.WriteImage("gel_highlight.png") mw.Destroy() mwc.Destroy() mwf.Destroy() // Now create the gel border /* convert gel_highlight.png \ \( +clone -fx A +matte -blur 0x2 -shade 0x90 -normalize \ -blur 0x2 -negate -evaluate multiply .4 -negate -roll -.5-1 \ +clone -compose Multiply -composite \) \ -compose In -composite gel_border.png */ mw = imagick.NewMagickWand() mw.ReadImage("gel_highlight.png") mwc = mw.Clone() mwf, err = mwc.FxImage("A") if err != nil { panic(err) } mwf.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_DEACTIVATE) mwf.BlurImage(0, 2) mwf.ShadeImage(true, 0, 90) mwf.NormalizeImage() mwf.BlurImage(0, 2) mwf.NegateImage(false) mwf.EvaluateImage(imagick.EVAL_OP_MULTIPLY, 0.4) mwf.NegateImage(false) mwf.RollImage(-1, -1) mwf.CompositeImage(mw, imagick.COMPOSITE_OP_MULTIPLY, 0, 0) mw.CompositeImage(mwf, imagick.COMPOSITE_OP_IN, 0, 0) mw.WriteImage("gel_border.png") mw.Destroy() mwc.Destroy() mwf.Destroy() // and finally the text and shadow effect /* convert gel_border.png \ -font Candice -pointsize 24 -fill white -stroke black \ -gravity Center -annotate 0 "Gel" -trim -repage 0x0+4+4 \ \( +clone -background navy -shadow 80x4+4+4 \) +swap \ -background none -flatten gel_button.png */ mw = imagick.NewMagickWand() dw = imagick.NewDrawingWand() pw = imagick.NewPixelWand() mw.ReadImage("gel_border.png") dw.SetFont("Lucida-Handwriting-Italic") dw.SetFontSize(24) pw.SetColor("white") dw.SetFillColor(pw) pw.SetColor("black") dw.SetStrokeColor(pw) dw.SetGravity(imagick.GRAVITY_CENTER) // It is important to notice here that MagickAnnotateImage renders the text on // to the MagickWand, NOT the DrawingWand. It only uses the DrawingWand for font // and colour information etc. mw.AnnotateImage(dw, 0, 0, 0, "Gel") mw.TrimImage(0) mw.ResetImagePage("0x0+4+4") mwc = mw.Clone() pw.SetColor("navy") mwc.SetImageBackgroundColor(pw) mwc.ShadowImage(80, 4, 4, 4) mwf = imagick.NewMagickWand() mwf.AddImage(mwc) mwf.AddImage(mw) mw.Destroy() mwc.Destroy() pw.SetColor("none") mwf.SetImageBackgroundColor(pw) mw = mwf.MergeImageLayers(imagick.IMAGE_LAYER_FLATTEN) mw.WriteImage("gel_button.png") mw.Destroy() mwc.Destroy() mwf.Destroy() dw.Destroy() pw.Destroy() }
func main() { imagick.Initialize() defer imagick.Terminate() mw := imagick.NewMagickWand() defer mw.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() if err := mw.SetSize(170, 100); err != nil { panic(err) } if err := mw.ReadImage("xc:black"); err != nil { panic(err) } pw.SetColor("white") dw.SetFillColor(pw) dw.Circle(50, 50, 13, 50) dw.Circle(120, 50, 157, 50) dw.Rectangle(50, 13, 120, 87) pw.SetColor("black") dw.SetFillColor(pw) dw.Circle(50, 50, 25, 50) dw.Circle(120, 50, 145, 50) dw.Rectangle(50, 25, 120, 75) pw.SetColor("white") dw.SetFillColor(pw) dw.Circle(60, 50, 40, 50) dw.Circle(110, 50, 130, 50) dw.Rectangle(60, 30, 110, 70) // Now we draw the Drawing wand on to the Magick Wand if err := mw.DrawImage(dw); err != nil { panic(err) } if err := mw.GaussianBlurImage(1, 1); err != nil { panic(err) } // Turn the matte of == +matte if err := mw.SetImageMatte(false); err != nil { panic(err) } if err := mw.WriteImage("logo_mask.png"); err != nil { panic(err) } mw.Destroy() dw.Destroy() pw.Destroy() mw = imagick.NewMagickWand() pw = imagick.NewPixelWand() dw = imagick.NewDrawingWand() mwc := imagick.NewMagickWand() defer mwc.Destroy() mw.ReadImage("logo_mask.png") pw.SetColor("red") dw.SetFillColor(pw) dw.Color(0, 0, imagick.PAINT_METHOD_RESET) mw.DrawImage(dw) mwc.ReadImage("logo_mask.png") mwc.SetImageMatte(false) mw.CompositeImage(mwc, imagick.COMPOSITE_OP_COPY_OPACITY, 0, 0) // Annotate gets all the font information from the drawingwand // but draws the text on the magickwand // Get the first available "*Sans*" font fonts := mw.QueryFonts("*Sans*") dw.SetFont(fonts[0]) dw.SetFontSize(36) pw.SetColor("white") dw.SetFillColor(pw) pw.SetColor("black") dw.SetStrokeColor(pw) dw.SetGravity(imagick.GRAVITY_CENTER) mw.AnnotateImage(dw, 0, 0, 0, "Ant") mw.WriteImage("logo_ant.png") mwc.Destroy() mw.Destroy() mw = imagick.NewMagickWand() if err := mw.ReadImage("logo_ant.png"); err != nil { panic(err) } mwf, err := mw.FxImage("A") if err != nil { panic(err) } defer mwf.Destroy() //mw.SetImageMatte(false) // +matte is the same as -alpha off mwf.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_DEACTIVATE) mwf.BlurImage(0, 6) mwf.ShadeImage(true, 110, 30) mwf.NormalizeImage() // ant.png -compose Overlay -composite mwc = imagick.NewMagickWand() mwc.ReadImage("logo_ant.png") mwf.CompositeImage(mwc, imagick.COMPOSITE_OP_OVERLAY, 0, 0) mwc.Destroy() // ant.png -matte -compose Dst_In -composite mwc = imagick.NewMagickWand() mwc.ReadImage("logo_ant.png") // -matte is the same as -alpha on // I don't understand why the -matte in the command line // does NOT operate on the image just read in (logo_ant.png in mwc) // but on the image before it in the list // It would appear that the -matte affects each wand currently in the // command list because applying it to both wands gives the same result mwf.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_SET) mwf.CompositeImage(mwc, imagick.COMPOSITE_OP_DST_IN, 0, 0) mwf.WriteImage("logo_ant_3D.png") mw.Destroy() mwc.Destroy() mwf.Destroy() /* Now for the shadow convert ant_3D.png \( +clone -background navy -shadow 80x4+6+6 \) +swap \ -background none -layers merge +repage ant_3D_shadowed.png */ mw = imagick.NewMagickWand() mw.ReadImage("logo_ant_3D.png") mwc = mw.Clone() pw.SetColor("navy") mwc.SetImageBackgroundColor(pw) mwc.ShadowImage(80, 4, 6, 6) // at this point // mw = ant_3D.png // mwc = +clone -background navy -shadow 80x4+6+6 // To do the +swap I create a new blank MagickWand and then // put mwc and mw into it. ImageMagick probably doesn't do it // this way but it works here and that's good enough for me! mwf = imagick.NewMagickWand() mwf.AddImage(mwc) mwf.AddImage(mw) mwc.Destroy() pw.SetColor("none") mwf.SetImageBackgroundColor(pw) mwc = mwf.MergeImageLayers(imagick.IMAGE_LAYER_MERGE) mwc.WriteImage("logo_shadow_3D.png") mw.Destroy() mwc.Destroy() mwf.Destroy() /* and now for the fancy background convert ant_3D_shadowed.png \ \( +clone +repage +matte -fx 'rand()' -shade 120x30 \ -fill grey70 -colorize 60 \ -fill lavender -tint 100 \) -insert 0 \ -flatten ant_3D_bg.jpg */ mw = imagick.NewMagickWand() mw.ReadImage("logo_shadow_3D.png") mwc = mw.Clone() // +repage mwc.ResetImagePage("") // +matte is the same as -alpha off mwc.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_DEACTIVATE) mwf, err = mwc.FxImage("rand()") if err != nil { panic(err) } mwf.ShadeImage(true, 120, 30) pw.SetColor("grey70") // It seems that this must be a separate pixelwand for Colorize to work! pwo := imagick.NewPixelWand() defer pwo.Destroy() // AHA .. this is how to do a 60% colorize pwo.SetColor("rgb(60%,60%,60%)") mwf.ColorizeImage(pw, pwo) pw.SetColor("lavender") // and this is a 100% tint pwo.SetColor("rgb(100%,100%,100%)") mwf.TintImage(pw, pwo) mwc.Destroy() mwc = imagick.NewMagickWand() mwc.AddImage(mwf) mwc.AddImage(mw) mwf = mwc.MergeImageLayers(imagick.IMAGE_LAYER_FLATTEN) if err := mwf.DisplayImage(os.Getenv("DYSPLAY")); err != nil { panic(err) } }
func main() { imagick.Initialize() defer imagick.Terminate() image := imagick.NewMagickWand() defer image.Destroy() pw := imagick.NewPixelWand() defer pw.Destroy() image.ReadImage("fract6.jpg") // scale it down w := image.GetImageWidth() h := image.GetImageHeight() pw.SetColor("transparent") if err := image.ShearImage(pw, 45, 0); err != nil { panic(err) } w = image.GetImageWidth() h = image.GetImageHeight() // scale it to make it look like it is laying down if err := image.ScaleImage(w, h/2); err != nil { panic(err) } // Get image stats w = image.GetImageWidth() h = image.GetImageHeight() // Make a blank canvas to draw on canvas := imagick.NewMagickWand() defer canvas.Destroy() // Use a colour from the input image pw, err := image.GetImagePixelColor(0, 0) if err != nil { panic(err) } canvas.NewImage(w, h*2, pw) offset := int(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 < int(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 := imagick.NewDrawingWand() line_height := 0 for y := int(h) - 1; y >= 0; y-- { // get (r,g,b) and grey value pw, err := image.GetImagePixelColor(int(x), int(y)) if err != nil { continue } // 255* adjusts the rgb values to Q8 even if the IM being used is Q16 r := (int)(255 * pw.GetRed()) g := (int)(255 * pw.GetGreen()) b := (int)(255 * pw.GetBlue()) // 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 { line.SetFillColor(pw) line.SetStrokeColor(pw) // Draw the part of the line that is visible start_y := y + offset - line_height end_y := y - grey + offset line.Line(float64(x), float64(start_y), float64(x), float64(end_y)) line_height = grey } line_height-- } // Draw the lines on the image canvas.DrawImage(line) line.Destroy() } canvas.ScaleImage(w-h, h*2) // write canvas canvas.WriteImage("3d_fractal.jpg") }
func main() { imagick.Initialize() defer imagick.Terminate() mw := imagick.NewMagickWand() defer mw.Destroy() dw := imagick.NewDrawingWand() defer dw.Destroy() cw := imagick.NewPixelWand() diameter := uint(640) radius := float64(diameter / 2) cw.SetColor("white") mw.NewImage(diameter, diameter, cw) dw.SetStrokeOpacity(1) // circle and rectangle dw.PushDrawingWand() // Hmmmm. Very weird. rgb(0,0,1) draws a black line around the edge // of the circle as it should. But rgb(0,0,0) or black don't. // AND if I remove the PixelSetColor then it draws a white boundary // around the rectangle (and presumably around the circle too) cw.SetColor("rgb(0,0,1)") dw.SetStrokeColor(cw) dw.SetStrokeWidth(4) dw.SetStrokeAntialias(true) cw.SetColor("red") //dw.SetStrokeOpacity(1) dw.SetFillColor(cw) dw.Circle(radius, radius, radius, radius*2) dw.Rectangle(50, 13, 120, 87) dw.PopDrawingWand() // rounded rectangle dw.PushDrawingWand() points := []imagick.PointInfo{ {378.1, 81.72}, {381.1, 79.56}, {384.3, 78.12}, {387.6, 77.33}, {391.1, 77.11}, {394.6, 77.62}, {397.8, 78.77}, {400.9, 80.57}, {403.6, 83.02}, {523.9, 216.8}, {526.2, 219.7}, {527.6, 223}, {528.4, 226.4}, {528.6, 229.8}, {528, 233.3}, {526.9, 236.5}, {525.1, 239.5}, {522.6, 242.2}, {495.9, 266.3}, {493, 268.5}, {489.7, 269.9}, {486.4, 270.8}, {482.9, 270.9}, {479.5, 270.4}, {476.2, 269.3}, {473.2, 267.5}, {470.4, 265}, {350, 131.2}, {347.8, 128.3}, {346.4, 125.1}, {345.6, 121.7}, {345.4, 118.2}, {346, 114.8}, {347.1, 111.5}, {348.9, 108.5}, {351.4, 105.8}, {378.1, 81.72}, } dw.SetStrokeAntialias(true) dw.SetStrokeWidth(2.016) dw.SetStrokeLineCap(imagick.LINE_CAP_ROUND) dw.SetStrokeLineJoin(imagick.LINE_JOIN_ROUND) dw.SetStrokeDashArray(make([]float64, 0)) cw.SetColor("rgb(0,0,128)") // If strokecolor is removed completely then the circle is not there dw.SetStrokeColor(cw) // But now I've added strokeopacity - 1=circle there 0=circle not there // If opacity is 1 the black edge around the rectangle is visible dw.SetStrokeOpacity(1) // No effect // dw.SetFillRule(imagick.FILL_EVEN_ODD) // this doesn't affect the circle cw.SetColor("#c2c280") dw.SetFillColor(cw) // 1=circle there 0=circle there but rectangle fill disappears // dw.SetFillOpacity(0) dw.Polygon(points) dw.SetStrokeOpacity(1) dw.PopDrawingWand() // yellow polygon dw.PushDrawingWand() points = []imagick.PointInfo{ {540, 288}, {561.6, 216}, {547.2, 43.2}, {280.8, 36}, {302.4, 194.4}, {331.2, 64.8}, {504, 64.8}, {475.2, 115.2}, {525.6, 93.6}, {496.8, 158.4}, {532.8, 136.8}, {518.4, 180}, {540, 172.8}, {540, 223.2}, {540, 288}, } dw.SetStrokeAntialias(true) dw.SetStrokeWidth(5.976) dw.SetStrokeLineCap(imagick.LINE_CAP_ROUND) dw.SetStrokeLineJoin(imagick.LINE_JOIN_ROUND) dw.SetStrokeDashArray([]float64{}) cw.SetColor("#4000c2") dw.SetStrokeColor(cw) dw.SetFillRule(imagick.FILL_EVEN_ODD) cw.SetColor("#ffff00") dw.SetFillColor(cw) dw.Polygon(points) dw.PopDrawingWand() // rotated and translated ellipse // The DrawEllipse function only draws the ellipse with // the major and minor axes orthogonally aligned. This also // applies to some of the other functions such as DrawRectangle. // If you want an ellipse that has the major axis rotated, you // have to rotate the coordinate system before the ellipse is // drawn. And you'll also want the ellipse somewhere on the // image rather than at the top left (where the 0,0 origin is // located) so before drawing the ellipse we move the origin to // wherever we want the centre of the ellipse to be and then // rotate the coordinate system by the angle of rotation we wish // to apply to the ellipse and *then* we draw the ellipse. // NOTE that doing all this within PushDrawingWand()/PopDrawingWand() // means that the coordinate system will be restored after // the PopDrawingWand dw.PushDrawingWand() cw.SetColor("rgb(0,0,1)") dw.SetStrokeColor(cw) dw.SetStrokeWidth(2) dw.SetStrokeAntialias(true) cw.SetColor("orange") //dw.DrawSetStrokeOpacity(1) dw.SetFillColor(cw) // Be careful of the order in which you meddle with the // coordinate system! Rotating and then translating is // not the same as translating then rotating dw.Translate(radius/2, 3*radius/2) dw.Rotate(-30) dw.Ellipse(0, 0, radius/8, 3*radius/8, 0, 360) dw.PopDrawingWand() // A line from the centre of the circle // to the top left edge of the image dw.Line(0, 0, radius, radius) mw.DrawImage(dw) mw.WriteImage("chart_test.jpg") }