Jump to content

Hitomezashi Stitch - 1/9/2022


Recommended Posts

This plugin basically generates Hitomezashi Stitch. Code is based on the spreadsheet found in this place - https://aperiodical.com/2020/12/mobile-numbers-hitomezashi-stitching/

 

The plugin itself is very simple, and speaks for itself. No instruction or clarification needed other than it's under Texture.

 

Download Link : Hitomezashi.zip

 

Preview:

unknown.png

Source Code:

Spoiler
// Name: Hitomezashi Stitch
// Submenu: Texture
// Author: Reptorian
// Title: Hitomezashi Stitch
// Version: 1
// Desc: Generates pattern based on Hitomezashi algorithm.
// Keywords: Hitomezashi, Pattern
// URL: https://forums.getpaint.net/profile/85868-reptillian/
// Help:
#region UICode
IntSliderControl pixel_size = 20; // [1,100] Pixel Size
DoubleSliderControl init_border_size = 10; // [0,100] Border Size (%)
ColorWheelControl color_a = ColorBgra.FromBgr(0, 0, 0); // [PrimaryColor] Color A
ColorWheelControl color_b = ColorBgra.FromBgr(255, 255, 255); // [SecondaryColor] Color B
ColorWheelControl border_color = ColorBgra.FromBgr(169, 169, 169); // [DarkGray] {!init_border_size} Border Color
ReseedButtonControl seed = 0; // Reseed
#endregion

int length_w,length_h,enlarged_w,enlarged_h,old_pixel_size;
bool initialized,rebuild;
Random myRandomA,myRandomB;
Random Init = new Random();
int new_seed;
int[] vx;
int[] vy;
int[,] surface;

List<(int,int)>  Equilavance = new List<(int,int)>{(0,0)};


void PreRender(Surface dst, Surface src)
{

    if (!initialized){
        length_w=(int)(Math.Ceiling(((double)(src.Width)/pixel_size)));
        length_h=(int)(Math.Ceiling(((double)(src.Height)/pixel_size)));
        enlarged_w = length_w * pixel_size;
        enlarged_h = length_h * pixel_size;
        enlarged_w = ( enlarged_w - src.Width ) / 2;
        enlarged_h = ( enlarged_h - src.Height ) / 2;
        myRandomA = new Random(Init.Next());
        myRandomB = new Random(Init.Next());
        vx = new int[length_w];
        vy = new int[length_h];
        surface = new int[length_w,length_h];
        surface[0,0]=0;
        old_pixel_size=pixel_size;
        Equilavance.Clear();
    }

    if (old_pixel_size != pixel_size){
        length_w=(int)(Math.Ceiling(((double)(src.Width)/pixel_size)));
        length_h=(int)(Math.Ceiling(((double)(src.Height)/pixel_size)));
        enlarged_w = length_w * pixel_size;
        enlarged_h = length_h * pixel_size;
        enlarged_w = ( enlarged_w - src.Width ) / 2;
        enlarged_h = ( enlarged_h - src.Height ) / 2;
        myRandomA = new Random(Init.Next());
        myRandomB = new Random(Init.Next());
        vx = new int[length_w];
        vy = new int[length_h];
        surface = new int[length_w,length_h];
        surface[0,0]=0;
        rebuild = true;
        old_pixel_size = pixel_size;
    }

    if (!initialized||rebuild||(new_seed != seed)){
        myRandomA = new Random(Init.Next());
        myRandomB = new Random(Init.Next());
        for (int x = 0 ; x < length_w ; x++){
            vx[x]=myRandomA.Next()%2;
        }
        for (int y = 0 ; y < length_h ; y++){
            vy[y]=myRandomB.Next()%2;
        }

        for (int y = 1 ; y < length_h ; y++){
            surface[0,y]=(surface[0,y-1]+vy[y-1])%2;
        }

        for(int y = 0 ; y < length_h ; y++){
            for (int x = 1 ; x < length_w ; x++){
                surface[x,y]=(vx[x-1]+surface[x-1,y]+y+2)%2;
            }
        }
    }

    new_seed=seed;
    initialized = true;
    rebuild = false;
}

// Here is the main multi-threaded render function
// The dst canvas is broken up into rectangles and
// your job is to write to each pixel of that rectangle
void Render(Surface dst, Surface src, Rectangle rect)
{
    int val;
    int border_size=(int)((double)(pixel_size*init_border_size/100));
    if (border_size==pixel_size){border_size--;}
    bool use_border=border_size>0;
    double border_base=(double)(border_size)/2;
    int start_border=(int)(Math.Ceiling((double)(border_size)));
    int end_border=pixel_size-(int)(Math.Floor((double)(border_size)));

    int lx,ly;
    int mx=length_w-1;
    int my=length_h-1;

    int off_xl,off_xr,off_yt,off_yb,px,py;

    // Step through each row of the current rectangle
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        // Step through each pixel on the current row of the rectangle
        for (int x = rect.Left; x < rect.Right; x++)
        {
            lx=((x+enlarged_w)/pixel_size)%length_w;
            ly=((y+enlarged_h)/pixel_size)%length_h;
            val = surface[lx,ly];

            if (val==1){dst[x,y] = color_a;}
            else{ dst[x,y] = color_b;}

            if (use_border){

                px=(x+enlarged_w)%pixel_size;
                py=(y+enlarged_h)%pixel_size;

                off_xl=surface[Math.Min(Math.Max(0,lx-1),mx),ly];
                off_xr=surface[Math.Min(Math.Max(0,lx+1),mx),ly];
                off_yt=surface[lx,Math.Min(Math.Max(0,ly+1),my)];
                off_yb=surface[lx,Math.Min(Math.Max(0,ly-1),my)];

                if (val != off_xl){
                    if(px<start_border){dst[x,y]=border_color;continue;}
                }
                if (val != off_xr){
                    if(px>end_border){dst[x,y]=border_color;continue;}
                }
                if (val != off_yb){
                    if(py<start_border){dst[x,y]=border_color;continue;}
                }
                if (val != off_yt){
                    if(py>end_border){dst[x,y]=border_color;continue;}
                }

            }
        }
    }
}

 

 

EDIT as of 1/8/2022 - Added Border Option

EDIT as of 1/9/2022 - Optimization by adding "continue;".

Edited by Reptillian
  • Like 1
  • Upvote 1

G'MIC Filter Developer

Link to comment
Share on other sites

  • Reptillian changed the title to Hitomezashi Stitch - 1/8/2022
Posted (edited)

New update, I added border option. I will admit that my solution for this isn't really the best. But it'll do with the limitations I have.

 

This is what I created:

 

unknown.png

Edited by Reptillian
  • Like 3

G'MIC Filter Developer

Link to comment
Share on other sites

  • Reptillian changed the title to Hitomezashi Stitch - 1/9/2022

Very cool plugin @Reptillian!  The border option really helps.  Thank you for this plugin...much appreciated!  💖

 

hitomezashistitch_01.png   with border

 

hitomezashistitch_02.png   with your emboss/relief+ plugin and convolutions. Actually looks like stitching!

 

 

  • Like 1
Link to comment
Share on other sites

Love this plugin @Reptillian. Thanks for sharing it. I created an image with just the plugin and then on the second one applied the Galaxy Transformation plugin for a different look. Enjoying that plugin in too :)

 

qLIUIj.png    qLIXgJ.png

  • Like 1

Click HERE to see my Pictorium of images I have worked on.

 

lMbNWe.png

You were once wild here. Don't let them tame you.

 ~ Isadora Duncan

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...