On Sun, 2004-10-17 at 08:52, Fernando Sancho wrote:
> Hi all.
> 
> I'm new to the list. I have joined because I need help.
> 
> I'm making a gimp-python scipt to create cross stitch patterns from an
> image. Reading list's archives i've founded this
> http://www.mail-archive.com/[EMAIL PROTECTED]/msg01127.html
> 
> I don't know if Carol has completed his idea. By now, i'm evaluating
> how much work can make gimp by itself.
> 
> The feature that i can't find in gimp is to map an image with a custom
> palette (DMC Floss colors). Gimp only allows me to convert from RGB to
> Indexed mode, but it doesn't allow to choose a custom pallete with
> more than 256 colours, and doesn't allow to choose the maximum number
> of colours.
> 
> Any help?

The good news is that there is already a script-fu script to do this. 
The bad news is that you can't use a palette with more than 256 colors,
because the script quantizes the original image's color information by
converting it to indexed, which allows only 8 bits worth of color
information.

I have attached the script - note that the default values aren't very
good.  Cross-stitch seems to need at least a larger brush (Circle 03)
and longer stitches (9 pixels per stitch seemed to work).  Keep trying
until you get what you want.

Be warned - use of this script may leave your original image in an
unrecoverable state - better always work on a copy.

HTH
-- 
Jeff

;;;
;;;  xstitch.scm - cross stitch, knitting, or nedlepoint pattern
;;;  generator.  Take a photo and make in into something you can stitch.
;;;
;;;
;;;  Jeff Trefftzs <[EMAIL PROTECTED]>

;;; This program is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 2 of the License, or
;;; (at your option) any later version.
;;; 
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;; 
;;; You should have received a copy of the GNU General Public License
;;; along with this program; if not, write to the Free Software
;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;;;  This version uses a suggestion from GSR to speed things up.
;;;  By using a mask for the stitches instead of doing each one separately
;;;  we get a huge speedup.  

;;;  TODO:  Get smart about brush size; optimize the mask generation
;;;  to pick up as many rows as have been done up to now for the select
;;;  and move.

;;;  Helper function to draw the stitches according to style selection

(define (script-fu-xstitch-draw-stitches inChannel
					 inWidth
					 inPixels
					 inStyle)
  (let*
      (
       (brushparms (gimp-brushes-get-brush-data "")) ; brush details
       (brushwidth (nth 4 brushparms))
       (brushheight (nth 5 brushparms))
       (xoffset (/ brushwidth 2))
       (yoffset (/ brushheight 2))
       (y 0)
       (parray (cons-array 4 'double)) ; strokes here
       )

    ;; Draw one row of stitches for the mask

    (set! x 0)
    (while (< x inWidth)

	   ;; This sets up the parray to show needlepoint

	   (cond
	    ((= inStyle 0)		; Needlepoint?
	     
	     (aset parray 0 (+ x xoffset))
	     (aset parray 1 (- (+ y inPixels) yoffset))
	     
	     (aset parray 2 (- (+ x inPixels) xoffset))
	     (aset parray 3 (+ y yoffset))
	     
	     (gimp-paintbrush inChannel
			      0	; Fade out
			      (length parray)
			      parray
			      CONTINUOUS
			      0)
	     )
	    
	    ;; Cross Stitch here

	    ((= inStyle 1)		; Cross Stitch
	     (aset parray 0 (+ x xoffset))
	     (aset parray 1 (- (+ y inPixels) yoffset))
	     
	     (aset parray 2 (- (+ x inPixels) xoffset))
	     (aset parray 3 (+ y yoffset))
	     
	     (gimp-paintbrush inChannel
			      0	; Fade out
			      (length parray)
			      parray
			      CONTINUOUS
			      0)
	     
	     ;; Set up for the other line - reverse y coords

	     (aset parray 1 (aref parray 3))
	     (aset parray 3 (- (+ y inPixels) yoffset))

	     (gimp-paintbrush inChannel
			      0	; Fade out
			      (length parray)
			      parray
			      CONTINUOUS
			      0)
	     )

	    ;; Knitting here

	    ((= inStyle 2)		; Knitting
	     (aset parray 0 (+ x xoffset))
	     (aset parray 1 (- (+ y inPixels) yoffset)) ; lower left
	     (aset parray 2 (+ x (/ inPixels 2))) ; halfway across
	     (aset parray 3 (+ y yoffset))	; top

	     (gimp-paintbrush inChannel
			      0	; Fade out
			      (length parray)
			      parray
			      CONTINUOUS
			      0)
	     (aset parray 0 (aref parray 2)) ; halfway across
	     (aset parray 1 (aref parray 3)) ; and at top
	     (aset parray 2 (- (+ x inPixels) xoffset)) ; right edge
	     (aset parray 3 (- (+ y inPixels) xoffset)) ; up from bottom

	     (gimp-paintbrush inChannel
			      0	; Fade out
			      (length parray)
			      parray
			      CONTINUOUS
			      0)
	     )
	    )				; end cond

	   (set! x (+ x inPixels))
	   )
    )
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Main Stitch Pattern Definition Function
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (script-fu-xstitch inImage inLayer
			   inBrush	; the brush to use
			   inPixPerStitch ; pixels per stitch
			   inColors	; number of colors to use
			   inPalette	; palette to select from
			   inBG	; Background/Canvas color
			   inStyle	; Needlepoint, Xstitch, Knit
			   inSgauge	; stitches per inch
			   inRgauge	; rows per inch
			   )
  (let* (
	 (width (car (gimp-image-width inImage)))
	 (height (car (gimp-image-height inImage)))
	 (pixels inPixPerStitch)
	 (oldfg (car (gimp-palette-get-foreground)))
	 (oldbg (car (gimp-palette-get-background)))
	 (oldbrush (gimp-brushes-get-brush)) ; get all info on old brush
	 (yscale (/ inRgauge inSgauge))	; how much to stretch for knitting
	 (newheight (* height yscale))
	 )

    (;;	gimp-undo-push-group-start => gimp-image-undo-group-start
gimp-image-undo-group-start inImage)

    (gimp-palette-set-background inBG)	; selected background color

    ;; While needlepoint and cross-stitch use a square grid, knitting stitches
    ;; are usually more rectangular.  Typically there are more rows/inch than
    ;; there are stitches/inch. (Substitute metric units if you prefer them).
    ;; But the pixelization plug-in assumes a square grid, so we have to 
    ;; stretch the image in the direction of the smaller steps.

    (if (not (= inSgauge inRgauge))
	(gimp-image-scale inImage width newheight)
	)

    ;; Now pixelize the image

    (plug-in-pixelize RUN-NONINTERACTIVE inImage inLayer pixels)

    ;; Convert it to indexed

    (;;	gimp-convert-indexed => gimp-image-convert-indexed
gimp-image-convert-indexed inImage
			  0		; No dithering, since we want pixelized
			  MAKE-PALETTE	; create our own palette to start
			  inColors	; using specified no of colors
			  FALSE		; No alpha dither
			  FALSE		; Remove unused colors
			  "NONE")	; Ignored this time

    ;;  The image now has a restricted set of colors in it.  That won't
    ;;  change if we convert it back to RGB, so we do that next.  Then
    ;;  we convert it back to indexed, this time using the destination
    ;;  palette.  This is the poor man's map to closest colors in palette
    ;;  x. Think of this step as a placeholder where we wait for a 
    ;;  better way to match colors from a palette potentially > 256 colors.

    (;;	gimp-convert-rgb => gimp-image-convert-rgb
gimp-image-convert-rgb inImage)

    ;;  And convert it back using the desired palette.

    (;;	gimp-convert-indexed => gimp-image-convert-indexed
gimp-image-convert-indexed inImage
			  0		; still no dithering
			  CUSTOM-PALETTE
			  inColors
			  FALSE
			  FALSE
			  inPalette)

    ;; Convert back to RGB again for further manipulations

    (;;	gimp-convert-rgb => gimp-image-convert-rgb
gimp-image-convert-rgb inImage)
    
    ;;  Now let's try to rewrite each little block with a diagonal
    ;;  line representing the stitch in the right color.  Will we
    ;;  need a background color, too?

    (let* (
	   ;; New variables for use in the stitch painting loop

	   (maskchannel
	    (car
	     (gimp-channel-new
	      inImage
	      width
	      newheight
	      "Stitch Mask"
	      50			; 50% opaque
	      '(255 255 0))))

	   (stitchlayer
	    (car
	     (gimp-layer-new inImage
			     width
			     newheight
			     (car (gimp-image-base-type inImage))
			     "Stitch Layer"
			     100 ; opaque
			     NORMAL-MODE)))

	   (stitchmask
	    (car
	     (gimp-layer-create-mask stitchlayer
				     WHITE-MASK)))

	   )

      ;; Initialize the stitch layer

      (gimp-layer-add-alpha stitchlayer)
      (gimp-image-add-layer inImage stitchlayer 0)
      (gimp-drawable-fill stitchlayer BG-IMAGE-FILL)

      (gimp-palette-set-foreground '(255 255 255)) ; white
      (gimp-image-add-channel inImage maskchannel 0) ; add the channel
      (gimp-drawable-fill maskchannel FG-IMAGE-FILL) ; and make it white


      ;; Now add a layer mask to the stitch layer.  This mask will
      ;; allow the underlying colors to show through, while outlining
      ;; the stitches themselves with the background color.

      (;;	gimp-image-add-layer-mask => gimp-layer-add-mask
gimp-layer-add-mask stitchlayer stitchmask)
      
      ;; FIX ME!  Relate brush size to pixels, relate stroke length to
      ;; pixels, add error checking.  Stroke should start inside the box,
      ;; finish inside the box, too.  For cross-stitch, draw two strokes
      ;; in the form of an X.

      (gimp-brushes-set-brush (car inBrush)) ; use selected brush

      ;; Now draw a row of stitches across the maskchannel

      (gimp-palette-set-foreground '(0 0 0)) ; black
      (gimp-image-set-active-channel inImage maskchannel)

      ;; Call the stitch drawing routine to get the right kind of stitch.

      (script-fu-xstitch-draw-stitches maskchannel width pixels inStyle)
      
      ;; Now copy that row down the height of the image

      (set! y pixels)		; next row
      (while (< y newheight)

	     (gimp-rect-select inImage 0 0 width y
			       REPLACE FALSE 0) ; select some pixels
	     (gimp-edit-copy maskchannel)	; copy the selection
	     (gimp-selection-translate inImage 0 y) ; shift down
	     (gimp-floating-sel-anchor
	      (car
	       (gimp-edit-paste maskchannel TRUE))) ; and paste back

	     (set! y (+ y y))		; move down by as much as we did
	     )
      ;; Now copy the maskchannel into the layermask.

      (gimp-selection-all inImage)	; select the whole thing
      (gimp-edit-copy maskchannel)	; copy to clipboard
      (gimp-floating-sel-anchor
       (car
	(gimp-edit-paste stitchmask TRUE))) ; paste into the layer mask

      (;;	gimp-channel-set-visible => gimp-drawable-set-visible
gimp-drawable-set-visible maskchannel FALSE) ; invisible

      ;; Finally convert it back to indexed again.  Play with this
      ;; some more -- maybe all this back and forth from rgb to indexed
      ;; can be avoided.

      (;;	gimp-convert-indexed => gimp-image-convert-indexed
gimp-image-convert-indexed inImage
			    0		; still no dithering
			    CUSTOM-PALETTE
			    inColors
			    FALSE
			    FALSE
			    inPalette)

      )					; end inner let

    ;; If we were knitting, the image must be rescaled to orig
    ;; dimensions

    (if (not (= inSgauge inRgauge))
	(gimp-image-scale inImage width height) ; back to old size
	)
    
    ;; Finished!  Now clean up and exit.

    (gimp-selection-none inImage)	; release the selection
;    (gimp-image-set-active-layer inImage inLayer) ; back to orig layer
    (gimp-palette-set-foreground oldfg)	; restore palette colors
    (gimp-palette-set-background oldbg)
    (gimp-brushes-set-brush (car oldbrush)) ; restore brush
    (;;	gimp-undo-push-group-end => gimp-image-undo-group-end
gimp-image-undo-group-end inImage)	; turn undo back on
    (gimp-displays-flush)		; and show the image
    )					; end outer let*
  )

(script-fu-register
 "script-fu-xstitch"
 _"<Image>/Script-Fu/Alchemy/Cross Stitch ..."
 "Converts an image into a cross stitch pattern.
The lower layer has the pattern, using just the number
of colors you selected from the specified palette.  

Note:  Do NOT select a palette with > 256 colors.  It
will crash the GIMP.

The upper layer gives a preview of the finished work,
drawing the threads with the selected brush, shaping
the stitches to conform to the style of work:  needlepoint,
cross-stitch, knitting.

Select the brush to be smaller than the pixels per stitch
parameter for best results."
 "Jeff Trefftzs"
 "Copyright 2002, Jeff Trefftzs"
 "ENTER DATE HERE"
 "RGB* GRAY* INDEXED*"
 SF-IMAGE "The Image" 0
 SF-DRAWABLE "The Layer" 0
 SF-BRUSH "Brush to draw stitches" '("Circle (01)" 100 25 0)
 SF-ADJUSTMENT "Pixels per Stitch" '(4 1 999999 1 10  0 1)
 SF-ADJUSTMENT "Number of Colors" '(32 1 256 1 10 0 1)
 SF-STRING "Palette" "Bears"
 SF-COLOR "Background" '(0 0 0)		; black, usually
 SF-OPTION "Stitch Style" '("Needlepoint" "Cross-Stitch" "Knitting")
 SF-ADJUSTMENT "Stitch Gauge - Stitches per Inch" '(14 0.25 128 .1 1 4 1)
 SF-ADJUSTMENT "Row Gauge - Rows per Inch" '(14 0.25 128 .1 1 4 1)
 )
_______________________________________________
Gimp-user mailing list
[EMAIL PROTECTED]
http://lists.xcf.berkeley.edu/mailman/listinfo/gimp-user

Reply via email to