Browse code

Initial commit

Dario Rodriguez authored on 28/10/2020 22:49:01
Showing 9 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+Some image utilities that serve as an alternative to imagemagick; these are able to work with larger images
0 2
new file mode 100755
... ...
@@ -0,0 +1,76 @@
1
+#!/usr/bin/pike
2
+/*
3
+ * collage.pike
4
+ *
5
+ * Makes a poster-sized collage of all the photos on the specified directory
6
+ *
7
+ * History:
8
+ *      28/06/2019 Creation
9
+ *
10
+ * Author: Dario Rodriguez dario@softhome.net
11
+ * This program is distributed under the terms of the GNU GPL v2.1+
12
+ */
13
+
14
+int
15
+main(int argc, array(string) argv)
16
+{
17
+        int a4w,a4h;
18
+        string resfilename;
19
+        int imgw,imgh;
20
+        int dpi=300;
21
+        int pw,ph;
22
+        int framethickness;
23
+        int total;
24
+        Image.Image img,photo,frame;
25
+        if(argc<5 || (argc>1 && argv[1]=="--help")) {
26
+                Stdio.werror("Syntax:  "+argv[0]+" <width_in_a4pages> <height_in_a4_pages> <resimage.png> <photodir> [<photodir2> [...]]\n");
27
+                Stdio.werror("Example: "+argv[0]+" 4 2 . result.png\n");
28
+                return(1);
29
+        }
30
+        a4w=(int)argv[1];
31
+        a4h=(int)argv[2];
32
+        resfilename=argv[3];
33
+        // A4 is 8.27in � 11.69in (equivalent to 210mm � 297mm)
34
+        imgw=(a4w*dpi*827)/100;
35
+        imgh=(a4h*dpi*1169)/100;
36
+        // we want to fit approx. 4 photos in a a4, we calc the photo size
37
+        pw=dpi*827*(a4w+a4h)/(100*16);
38
+        ph=dpi*1169*(a4w+a4h)/(100*16);
39
+        framethickness=pw/20;
40
+        // resulting image
41
+        img=Image.Image(imgw,imgh);
42
+        // Put a nice bg
43
+// TODO
44
+        // add each photo
45
+        total=0;
46
+        foreach(argv[4..sizeof(argv)-1],string photodir) {
47
+                foreach(get_dir(photodir),string e) {
48
+                        if(sizeof(e)<4 || !(e[sizeof(e)-4..sizeof(e)]==".png" || e[sizeof(e)-4..sizeof(e)]==".jpg")) {
49
+                                write("* (Ignoring "+e+")\n");
50
+                                continue;
51
+                        }
52
+                        write("* Loading "+e+"...\n");
53
+                        photo=Image.load(photodir+"/"+e);
54
+                        write("* Resizing...\n");
55
+                        if(photo->xsize()>photo->ysize()) { /* landscape */
56
+                                photo=photo->scale(2*pw,2*photo->ysize()*pw/photo->xsize());
57
+                        } else { /* portrait */
58
+                                photo=photo->scale(2*photo->xsize()*ph/photo->ysize(),2*ph);
59
+                        }
60
+                        write("* Drawing frame...\n");
61
+                        frame=Image.Image(photo->xsize()+2*(2+framethickness),photo->ysize()+2*(2+framethickness),0,0,0);
62
+                        frame->box(2,2,frame->xsize()-1-2,frame->ysize()-1-2,255,255,255);
63
+                        frame->box(2*(1+framethickness),2*(1+framethickness),frame->xsize()-1-2*(1+framethickness),frame->ysize()-1-2*(1+framethickness),127,127,127);
64
+                        frame->paste(photo,2+framethickness,2+framethickness);
65
+                        // WARNING TODO: rotate, paste using layers
66
+                        frame=frame->scale(frame->xsize()/2,frame->ysize()/2);
67
+                        img->paste(frame,random(img->xsize()+photo->xsize())-photo->xsize()/2,random(img->ysize()+photo->ysize())-photo->ysize()/2);
68
+                        total++;
69
+                }
70
+        }
71
+        // write result
72
+        write("* Writing "+resfilename+"...\n");
73
+        Stdio.write_file(resfilename,Image.PNG.encode(img));
74
+        write("Composed "+total+" photos into "+resfilename+". Process finished.\n");
75
+
76
+}
0 77
new file mode 100755
... ...
@@ -0,0 +1,44 @@
1
+#!/usr/bin/pike
2
+/*
3
+ * cropper.pike
4
+ *
5
+ * Crom a NxM+i+j pngs into another png
6
+ *
7
+ * History:
8
+ *      28/09/2020 Creation from tiler.pike
9
+ *
10
+ * Author: Dario Rodriguez dario@softhome.net
11
+ * This program is distributed under the terms of the GNU GPL v2.1+
12
+ */
13
+
14
+int
15
+main(int argc, array(string) argv)
16
+{
17
+	int xsize,ysize,xoff,yoff;
18
+        string infilename;
19
+        string destfilename;
20
+        Image.Image result;
21
+        if(argc<4 || (argc>1 && argv[1]=="--help")) {
22
+                Stdio.werror("Syntax:  "+argv[0]+" <crop_expression> <infile.png> <outfile.png>\n");
23
+                Stdio.werror("Example: "+argv[0]+" 200x300+50+20 file.png dest.png\n");
24
+                Stdio.werror("Example result: dest.png\n");
25
+                return(1);
26
+        }
27
+        write("* Cropping to "+argv[1]+"\n");
28
+	xsize=ysize=xoff=yoff;
29
+	xsize=(int) (argv[1]/"x")[0];
30
+	if(sizeof(argv[1]/"x")>1)
31
+		ysize=(int) (((argv[1]/"x")[1])/"+")[0];
32
+	if(sizeof(argv[1]/"+")>1)
33
+		xoff=(int) (argv[1]/"+")[1];
34
+	if(sizeof(argv[1]/"+")>2)
35
+		yoff=(int) (argv[1]/"+")[2];
36
+        infilename=argv[2];
37
+        destfilename=argv[3];
38
+	result=Image.load(infilename)->copy(xoff,yoff,xoff+xsize-1,yoff+ysize-1,255,255,255);
39
+	write("* Writing "+destfilename+"...\n");
40
+        Stdio.write_file(destfilename,Image.PNG.encode(result));
41
+	write("* Finished successfully\n");
42
+        return(0);
43
+}
44
+
0 45
new file mode 100755
... ...
@@ -0,0 +1,93 @@
1
+#!/usr/bin/pike
2
+/*
3
+ * jpgscanclean.pike
4
+ *
5
+ *  Utility to clean the background of scanned pages (req. RGB page)
6
+ *
7
+ * Author: Dario Rodriguez dario@softhome.net
8
+ * The program is licensed under the terms of the MIT/X license.
9
+ */
10
+
11
+int bgthreshold=64; // from 0 to 255
12
+int amplitude=15; // from 1 to 255
13
+
14
+int
15
+main(int argc, array(string) argv)
16
+{
17
+	Image.Image in,out,inhsv,indistance;
18
+	string infile,outfile;
19
+        if(argc!=3 || argv[argc-1]=="--help") {
20
+                write("Syntax: "+argv[0]+" infile.jpg outfile.png\n");
21
+                return(1);
22
+        }
23
+	write(argv[1]+" -> "+argv[2]+"\n");
24
+	write("* Generating intermediate representations...");
25
+	infile=argv[1];
26
+	outfile=argv[2];
27
+	in=Image.load(infile);
28
+	inhsv=in->copy()->rgb_to_hsv();
29
+	indistance=in->copy()->distancesq(255,255,255);
30
+	out=Image.Image(in.xsize(),in.ysize());
31
+	// Guess the most used bg color
32
+	write("done.\n* Guessing most used bg hue...");
33
+	array(int) hues=allocate(256);
34
+	int x,y;
35
+	int h,n,selh,seln,j;
36
+	int c;
37
+	for(y=0;y<in.ysize();y++) {
38
+		for(x=0;x<in.xsize();x++) {
39
+			c=indistance.getpixel(x,y)[0];
40
+			if(c<bgthreshold) {
41
+				// possible bg
42
+				c=inhsv.getpixel(x,y)[0];
43
+				hues[c]++;				
44
+			}
45
+		}
46
+		if(!(y%1000))
47
+			write(".");
48
+	}
49
+	for(selh=0,seln=0,h=0;h<256;h++) {
50
+		for(n=0,j=-amplitude;j<amplitude;j++) {
51
+			n+=hues[(h+256+j)%256];
52
+		}
53
+		if(n>seln) {
54
+			seln=n;
55
+			selh=h;
56
+		}
57
+	}
58
+	write(""+selh);
59
+	// Clean image
60
+	write(".\n* Cleaning image...");
61
+	int d;
62
+	for(y=0;y<in.ysize();y++) {
63
+		for(x=0;x<in.xsize();x++) {
64
+			c=indistance.getpixel(x,y)[0];
65
+			h=inhsv.getpixel(x,y)[0];
66
+			// calc. hue distance to bg hue wrapping on the color wheel
67
+			if(h<selh) {
68
+				if((selh-h)<(h+256-selh))
69
+					d=selh-h;
70
+				else
71
+					d=h+256-selh;
72
+			} else {
73
+				if((h-selh)<(selh+256-h))
74
+					d=h-selh;
75
+				else
76
+					d=selh+256-h;
77
+			}
78
+			// heuristics
79
+			if(c<bgthreshold && d<bgthreshold) {
80
+				out.setpixel(x,y,255,255,255);
81
+			} else {
82
+				array(int) rgb=in.getpixel(x,y);
83
+				out.setpixel(x,y,rgb[0],rgb[1],rgb[2]);
84
+			}
85
+		}
86
+		if(!(y%1000))
87
+			write(".");
88
+	}
89
+	// Write result
90
+	write("done.\n* Writing result to disk...");
91
+	Stdio.write_file(outfile,Image.PNG.encode(out));
92
+	write("done.\n* Process finished.\n");
93
+}
0 94
new file mode 100755
... ...
@@ -0,0 +1,82 @@
1
+#!/usr/bin/pike
2
+/*
3
+ * paster.pike
4
+ *
5
+ * Resize a png into another png
6
+ *
7
+ * History:
8
+ *      28/09/2020 Creation from resizer.pike
9
+ *
10
+ * Author: Dario Rodriguez dario@softhome.net
11
+ * This program is distributed under the terms of the GNU GPL v2.1+
12
+ */
13
+
14
+int
15
+main(int argc, array(string) argv)
16
+{
17
+	int i;
18
+	string geom;
19
+	mapping imagemapping;
20
+	int xsize,ysize;
21
+        int xoff,yoff;
22
+	string destfilename;
23
+	Image.Image image,alpha;
24
+	array(Image.Layer) layers=({});
25
+	Image.Layer l;
26
+        if(argc<4 || (argc%2)!=0 || (argc>1 && argv[1]=="--help")) {
27
+                Stdio.werror("Syntax:  "+argv[0]+" <geom1> { <file1.png> | <htmlcolor1> } [<geom2> { <file2.png> | <htmlcolor2> } [...]] <outfile.png>\n");
28
+                Stdio.werror("Example: "+argv[0]+" 200x300+0+0 bg.png 150x0+25+25 image.png 100x1+0+0 \"#ff0000\" dest.png\n");
29
+                Stdio.werror("Example result: dest.png\n");
30
+                return(1);
31
+        }
32
+	destfilename=argv[argc-1];
33
+	write("* Loading images...\n");
34
+	for(i=1;(i+1)<argc;i+=2) {
35
+		geom=argv[i];
36
+		if(sizeof(argv[i+1])>1 && argv[i+1][0]=='#') {
37
+			string htmlcolor=argv[i+1];
38
+			int r,g,b,a;
39
+			a=0;
40
+			htmlcolor-="#";
41
+			sscanf(htmlcolor[0..1],"%x",r);
42
+        		sscanf(htmlcolor[2..3],"%x",g);
43
+        		sscanf(htmlcolor[4..5],"%x",b);
44
+        		if(sizeof(htmlcolor)>6)
45
+                		sscanf(htmlcolor[6..7],"%x",a);
46
+write("r:"+r+" g:"+g+" b:"+b+" a:"+a+"\n");
47
+			image=Image.Image(1,1,r,g,b);
48
+			imagemapping=([ "image":image, "alpha":Image.Image(1,1,255-a,255-a,255-a) ]);
49
+		} else {
50
+			imagemapping=Image._load(argv[i+1]);
51
+		}
52
+		xsize=ysize=xoff=yoff=0;
53
+		xsize=(int) (geom/"x")[0];
54
+        	if(sizeof(geom/"x")>1)
55
+                	ysize=(int) (((geom/"x")[1])/"+")[0];
56
+        	if(sizeof(geom/"+")>1)
57
+                	xoff=(int) (geom/"+")[1];
58
+        	if(sizeof(geom/"+")>2)
59
+                	yoff=(int) (geom/"+")[2];
60
+		image=imagemapping["image"];
61
+		alpha=imagemapping["alpha"];
62
+		xsize=(xsize!=0)?xsize:(ysize==0)?image->xsize():ysize*image->xsize()/image->ysize();
63
+		ysize=(ysize!=0)?ysize:(xsize==0)?image->ysize():xsize*image->ysize()/image->xsize();
64
+		if(xsize!=image->xsize() || ysize!=image->ysize()) {
65
+			image=image->scale(xsize,ysize);
66
+			if(!intp(alpha))
67
+				alpha=alpha->scale(xsize,ysize);
68
+		}
69
+		if(intp(alpha))
70
+			alpha=Image.Image(xsize,ysize)->clear(0,0,0);
71
+		l=Image.Layer(image,alpha,"normal");
72
+		l->set_offset(xoff,yoff);
73
+		layers+=({l});
74
+	}
75
+	l=Image.lay(layers);
76
+	l->set_offset(0,0);
77
+	write("* Writing "+destfilename+"...\n");
78
+	Stdio.write_file(destfilename,Image.PNG.encode(l->image(),(["alpha":l->alpha()])));
79
+	write("* Finished successfully\n");
80
+        return(0);
81
+}
82
+
0 83
new file mode 100755
... ...
@@ -0,0 +1,54 @@
1
+#!/usr/bin/pike
2
+/*
3
+ * resizer.pike
4
+ *
5
+ * Resize a png into another png
6
+ *
7
+ * History:
8
+ *      28/09/2020 Creation from cropper.pike
9
+ *
10
+ * Author: Dario Rodriguez dario@softhome.net
11
+ * This program is distributed under the terms of the GNU GPL v2.1+
12
+ */
13
+
14
+int
15
+main(int argc, array(string) argv)
16
+{
17
+	int xsize,ysize;
18
+        string infilename;
19
+        string destfilename;
20
+	mapping orig;
21
+        Image.Image image,alpha,result;
22
+        if(argc<4 || (argc>1 && argv[1]=="--help")) {
23
+                Stdio.werror("Syntax:  "+argv[0]+" <newwidthxnewheight> <infile.png> <outfile.png>\n");
24
+                Stdio.werror("Example: "+argv[0]+" 200x300 file.png dest.png\n");
25
+                Stdio.werror("Example: "+argv[0]+" 200x0 file.png dest.png\n");
26
+                Stdio.werror("Example: "+argv[0]+" 0x300 file.png dest.png\n");
27
+                Stdio.werror("Example result: dest.png\n");
28
+                return(1);
29
+        }
30
+	xsize=ysize=0;
31
+	xsize=(int) (argv[1]/"x")[0];
32
+	if(sizeof(argv[1]/"x")>1)
33
+		ysize=(int) (((argv[1]/"x")[1])/"+")[0];
34
+        infilename=argv[2];
35
+        destfilename=argv[3];
36
+	write("* Loading "+infilename+"\n");
37
+	orig=Image._load(infilename);
38
+	image=orig["image"];
39
+	alpha=orig["alpha"];
40
+	xsize=(xsize!=0)?xsize:(ysize==0)?image->xsize():ysize*image->xsize()/image->ysize();
41
+	ysize=(ysize!=0)?ysize:(xsize==0)?image->ysize():xsize*image->ysize()/image->xsize();
42
+        write("* Resizing from "+image->xsize()+"x"+image->ysize()+" to "+xsize+"x"+ysize+"\n");
43
+	image=image->scale(xsize,ysize);
44
+	if(!intp(alpha))
45
+		alpha=alpha->scale(xsize,ysize);
46
+	write("* Writing "+destfilename+"...\n");
47
+	if(intp(alpha))
48
+        	Stdio.write_file(destfilename,Image.PNG.encode(image));
49
+	else
50
+		Stdio.write_file(destfilename,Image.PNG.encode(image,(["alpha":alpha])));
51
+	write("* Finished successfully\n");
52
+        return(0);
53
+}
54
+
0 55
new file mode 100755
... ...
@@ -0,0 +1,50 @@
1
+#!/usr/bin/pike
2
+/*
3
+ * slicer.pike
4
+ *
5
+ * Slices a png in NxM different pngs
6
+ *
7
+ * History:
8
+ *      28/06/2019 Creation
9
+ *
10
+ * Author: Dario Rodriguez dario@softhome.net
11
+ * This program is distributed under the terms of the GNU GPL v2.1+
12
+ */
13
+
14
+int
15
+main(int argc, array(string) argv)
16
+{
17
+        int a4w,a4h;
18
+        int px,py;
19
+        string origfilename;
20
+        string resprefix;
21
+        int x,y,total;
22
+        Image.Image img,cropped;
23
+        string outfilename;
24
+        if(argc<4 || (argc>1 && argv[1]=="--help")) {
25
+                Stdio.werror("Syntax:  "+argv[0]+" <width_in_a4pages> <height_in_a4_pages> <origimage.png>\n");
26
+                Stdio.werror("Example: "+argv[0]+" 4 2 orig.png\n");
27
+                Stdio.werror("Example result: orig_0001.png ... orig_0008.png\n");
28
+                return(1);
29
+        }
30
+        a4w=(int)argv[1];
31
+        a4h=(int)argv[2];
32
+        origfilename=argv[3];
33
+        resprefix=(origfilename/".png")[0];
34
+        write("* Loading "+origfilename+"...\n");
35
+        img=Image.load(origfilename);
36
+        px=img->xsize()/a4w;
37
+        py=img->ysize()/a4h;
38
+        for(total=0,y=0;y<a4h;y++) {
39
+                for(x=0;x<a4w;x++) {
40
+                        total++;
41
+                        cropped=img->copy(x*px,y*py,(x+1)*px-1,(y+1)*py-1,255,255,255);
42
+                        outfilename=sprintf("%s_%05d.png",resprefix,total);
43
+                        write("* Writing "+outfilename+"...\n");
44
+                        Stdio.write_file(outfilename,Image.PNG.encode(cropped));
45
+                }
46
+        }
47
+        write(""+total+" slices written. Process finished.\n");
48
+        return(0);
49
+}
50
+
0 51
new file mode 100755
... ...
@@ -0,0 +1,62 @@
1
+#!/usr/bin/pike
2
+/*
3
+ * tiler.pike
4
+ *
5
+ * Tiles NxM different pngs into a single png
6
+ *
7
+ * History:
8
+ *       1/07/2019 Creation
9
+ *	 5/11/2019 Fix erroneous 1-pixel border around every tile
10
+ *
11
+ * Author: Dario Rodriguez dario@softhome.net
12
+ * This program is distributed under the terms of the GNU GPL v2.1+
13
+ */
14
+
15
+int
16
+main(int argc, array(string) argv)
17
+{
18
+        int a4w,a4h;
19
+	int maxx,maxy;
20
+        int px,py;
21
+        string destfilename;
22
+        int total;
23
+        Image.Image img,result;
24
+        if(argc<4 || (argc>1 && argv[1]=="--help")) {
25
+                Stdio.werror("Syntax:  "+argv[0]+" <width_in_tiles> <height_in_tiles> <file1.png> [<file2.png> [...]] <destfile.png>\n");
26
+                Stdio.werror("Example: "+argv[0]+" 3 2 file1.png file2.png file3.png file4.png file5.png file6.png dest.png\n");
27
+                Stdio.werror("Example result: dest.png\n");
28
+                return(1);
29
+        }
30
+        a4w=(int)argv[1];
31
+        a4h=(int)argv[2];
32
+        destfilename=argv[sizeof(argv)-1];
33
+	array(string) infiles=argv[3..sizeof(argv)-2];
34
+	maxx=maxy=1;
35
+	write("* Calculating tile size\n");
36
+	foreach(infiles, string f) {
37
+		img=Image.load(f);
38
+		if(img->xsize()>maxx)
39
+			maxx=img->xsize();
40
+		if(img->ysize()>maxy)
41
+			maxy=img->ysize();
42
+	}
43
+	result=Image.Image(maxx*a4w,maxy*a4h,255,255,255);
44
+	px=py=0;
45
+	total=0;
46
+	foreach(infiles, string f) {
47
+        	write("* Processing "+f+"...\n");
48
+		img=Image.load(f);
49
+		result->paste(img,px*(maxx),py*(maxy));
50
+		px++;
51
+		if(px>=a4w) {
52
+			px=0;
53
+			py++;
54
+		}
55
+		total++;
56
+	}
57
+        write("* Writing "+destfilename+"...\n");
58
+        Stdio.write_file(destfilename,Image.PNG.encode(result));
59
+        write("tiled "+total+" images into "+destfilename+". Process finished.\n");
60
+        return(0);
61
+}
62
+
0 63
new file mode 100755
... ...
@@ -0,0 +1,56 @@
1
+#!/usr/bin/pike
2
+/*
3
+ * ttfwriter.pike
4
+ *
5
+ * Create a png with some text using the specified ttf font.
6
+ *
7
+ * History:
8
+ *      27/10/2020 Creation from cropper.pike
9
+ *
10
+ * Author: Dario Rodriguez dario@softhome.net
11
+ * This program is distributed under the terms of the GNU GPL v2.1+
12
+ */
13
+
14
+int
15
+main(int argc, array(string) argv)
16
+{
17
+	string fontname;
18
+	int fontsize;
19
+	string htmlcolor;
20
+        string text;
21
+        string destfilename;
22
+        Image.Image textimage;
23
+	Image.Image colorimage;
24
+	mapping(string:int) color;
25
+        if(argc<5 || (argc>1 && argv[1]=="--help")) {
26
+                Stdio.werror("Syntax:  "+argv[0]+" <font.ttf> <fontsize> <htmlcolor> <text> <outfile.png>\n");
27
+                Stdio.werror("Example: "+argv[0]+" font.ttf 16 \"#000000\" \"Text\" dest.png\n");
28
+                Stdio.werror("Example with alpha: "+argv[0]+" font.ttf 16 \"#000000a0\" \"Text\" dest.png\n");
29
+                return(1);
30
+        }
31
+	fontname=argv[1];
32
+	fontsize=(int)argv[2];
33
+	htmlcolor=argv[3];
34
+	text=argv[4];
35
+	destfilename=argv[5];
36
+        write("* Loading font "+fontname+"...\n");
37
+	Image.Fonts.set_font_dirs( ({"."}) );
38
+	Image.Fonts.Font font=Image.Fonts.Font(fontname,fontsize);
39
+	write("* Parsing color...\n");
40
+	int r,g,b,a=0;
41
+	htmlcolor-="#";
42
+	sscanf(htmlcolor[0..1],"%x",r);
43
+	sscanf(htmlcolor[2..3],"%x",g);
44
+	sscanf(htmlcolor[4..5],"%x",b);
45
+	if(sizeof(htmlcolor)>6)
46
+		sscanf(htmlcolor[6..7],"%x",a);
47
+	color=(["r":r,"g":g,"b":b,"a":a]);
48
+	write("* Rendering text...\n");
49
+	textimage=font->write(text)*((255.0-color["a"])/255.0);
50
+	colorimage=Image.Image(textimage->xsize(),textimage->ysize())->clear(color["r"],color["g"],color["b"]);
51
+	write("* Writing "+destfilename+"...\n");
52
+        Stdio.write_file(destfilename,Image.PNG.encode(colorimage,(["alpha":textimage])));
53
+	write("* Finished successfully\n");
54
+        return(0);
55
+}
56
+