pikl 0.2.8 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/History.txt +9 -0
  2. data/License.txt +0 -0
  3. data/Manifest.txt +17 -17
  4. data/README.txt +0 -0
  5. data/config/hoe.rb +9 -6
  6. data/config/requirements.rb +0 -0
  7. data/ext/pikl/extconf.rb +0 -0
  8. data/ext/pikl/pikl.h +617 -465
  9. data/ext/pikl/pikl_affine.c +38 -91
  10. data/ext/pikl/pikl_affine.h +0 -0
  11. data/ext/pikl/pikl_bitmap.c +0 -0
  12. data/ext/pikl/pikl_bitmap.h +0 -0
  13. data/ext/pikl/pikl_blur.c +4 -8
  14. data/ext/pikl/pikl_blur.h +0 -0
  15. data/ext/pikl/pikl_camera.c +218 -0
  16. data/ext/pikl/{pikl_effect3.h → pikl_camera.h} +2 -2
  17. data/ext/pikl/pikl_composite.c +175 -0
  18. data/ext/pikl/pikl_composite.h +12 -0
  19. data/ext/pikl/pikl_decrease.c +110 -45
  20. data/ext/pikl/pikl_decrease.h +0 -7
  21. data/ext/pikl/pikl_divide.c +116 -0
  22. data/ext/pikl/pikl_divide.h +11 -0
  23. data/ext/pikl/pikl_effect.c +583 -151
  24. data/ext/pikl/pikl_effect.h +32 -6
  25. data/ext/pikl/pikl_enhance.c +274 -0
  26. data/ext/pikl/pikl_enhance.h +20 -0
  27. data/ext/pikl/pikl_io.c +174 -23
  28. data/ext/pikl/pikl_io.h +0 -0
  29. data/ext/pikl/pikl_jpeg.c +0 -0
  30. data/ext/pikl/pikl_jpeg.h +0 -0
  31. data/ext/pikl/pikl_pattern.c +383 -357
  32. data/ext/pikl/pikl_pattern.h +0 -0
  33. data/ext/pikl/pikl_pixel.c +173 -0
  34. data/ext/pikl/{pikl_trim.h → pikl_pixel.h} +2 -2
  35. data/ext/pikl/pikl_png.c +0 -0
  36. data/ext/pikl/pikl_png.h +0 -0
  37. data/ext/pikl/pikl_private.h +12 -5
  38. data/ext/pikl/pikl_resize.c +0 -0
  39. data/ext/pikl/pikl_resize.h +0 -0
  40. data/ext/pikl/pikl_rotate.c +409 -51
  41. data/ext/pikl/pikl_rotate.h +8 -0
  42. data/ext/pikl/pikl_scrap.c +263 -483
  43. data/ext/pikl/pikl_scrap.h +0 -0
  44. data/ext/pikl/pikl_special.c +168 -0
  45. data/ext/pikl/{pikl_effect4.h → pikl_special.h} +2 -2
  46. data/ext/pikl/pikl_voronoi.c +320 -0
  47. data/ext/pikl/pikl_voronoi.h +37 -0
  48. data/lib/pikl.rb +4 -2
  49. data/lib/pikl/color.rb +47 -0
  50. data/lib/pikl/const.rb +106 -22
  51. data/lib/pikl/errors.rb +0 -0
  52. data/lib/pikl/ext.rb +115 -8
  53. data/lib/pikl/filter.rb +371 -0
  54. data/lib/pikl/image.rb +124 -117
  55. data/lib/pikl/version.rb +2 -2
  56. data/setup.rb +0 -0
  57. data/test/sample.jpg +0 -0
  58. data/test/test_helper.rb +0 -0
  59. data/test/test_pikl_image.rb +0 -14
  60. data/test/test_pikl_image2.rb +541 -0
  61. metadata +35 -23
  62. data/ext/pikl/decrease/fsdither.h +0 -554
  63. data/ext/pikl/decrease/median.c +0 -1179
  64. data/ext/pikl/decrease/median.h +0 -7
  65. data/ext/pikl/decrease/neuquan5.c +0 -563
  66. data/ext/pikl/decrease/neuquant.h +0 -62
  67. data/ext/pikl/decrease/wu.c +0 -447
  68. data/ext/pikl/decrease/wu.h +0 -7
  69. data/ext/pikl/pikl_effect2.c +0 -240
  70. data/ext/pikl/pikl_effect2.h +0 -55
  71. data/ext/pikl/pikl_effect3.c +0 -266
  72. data/ext/pikl/pikl_effect4.c +0 -495
  73. data/ext/pikl/pikl_rotate2.c +0 -312
  74. data/ext/pikl/pikl_rotate2.h +0 -19
  75. data/ext/pikl/pikl_trim.c +0 -28
File without changes
File without changes
File without changes
@@ -1,15 +1,27 @@
1
1
  #include "pikl_pattern.h"
2
2
 
3
+ static int tile_rectangle(PKLImage pkl, int msx, int msy, unsigned char level);
4
+ static int tile_pattern(PKLImage pkl, PKL_TILE_TYPE type, int pw, int ph, unsigned char level);
5
+ static int tile_pattern_draw(PKLImage pkl, double *wd, int pw, int ph, unsigned char level);
6
+ static int tile_brick(PKLImage pkl, int msx, int msy, unsigned char level);
7
+
8
+ static void pattern_hexagon(int ph, double *wd, double ww, double hh);
9
+ static void pattern_diamond(int ph, double *wd, double ww, double hh);
10
+ static void pattern_circle(int ph, double *wd, double ww, double hh);
11
+ static void pattern_brick(int ph, double *wd, double ww, double hh);
12
+
3
13
  static int pkl_pattern_draw_line(PKLImage pkl, double *wd, int pw, int ph);
4
14
  static int pkl_pattern_draw_average(PKLImage pkl, double *wd, int pw, int ph);
5
15
 
6
16
  //=============================================================================
7
- // pkl_pattern_hexagon
17
+ // pkl_pattern
8
18
  //=============================================================================
9
- PKLExport int pkl_pattern_hexagon(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE type)
19
+ PKLExport int pkl_pattern(PKLImage pkl, int pw, int ph, PKL_PATTERN_TYPE mode, PKL_PAINT_TYPE type)
10
20
  {
11
21
  double ww, hh, *wd;
12
- int i, result;
22
+ int result;
23
+
24
+ if(pw<1 || ph<1) return(1);
13
25
 
14
26
  wd = malloc(sizeof(double)*ph);
15
27
  if(!wd) return(1);
@@ -17,21 +29,22 @@ PKLExport int pkl_pattern_hexagon(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE t
17
29
  ww = (double)pw;
18
30
  hh = (double)ph;
19
31
 
20
- /* パターン座標を構築する */
21
- for(i=0; i<ph; i++){
22
- if((double)i < hh/6.0){
23
- wd[i] = ww * (double)i*6.0/hh;
24
- }else
25
- if((double)i < hh/2.0){
26
- wd[i] = ww;
27
- }else
28
- if((double)i < hh*2.0/3.0){
29
- wd[i] = ww*4.0 - ww*(double)i*6.0/hh;
30
- }else{
31
- wd[i] = 0.0;
32
- }
32
+ /* パターン座標の構築 */
33
+ switch(mode){
34
+ case PKL_PATTERN_DIAMOND:
35
+ pattern_diamond(ph, wd, ww, hh);
36
+ break;
37
+ case PKL_PATTERN_CIRCLE:
38
+ pattern_circle(ph, wd, ww, hh);
39
+ break;
40
+ case PKL_PATTERN_BRICK:
41
+ pattern_brick(ph, wd, ww, hh);
42
+ break;
43
+ case PKL_PATTERN_HEXAGON:
44
+ default:
45
+ pattern_hexagon(ph, wd, ww, hh);
33
46
  }
34
-
47
+
35
48
  /* 塗りタイプ別の処理 */
36
49
  switch(type){
37
50
  case PKL_PAINT_AVE:
@@ -47,20 +60,32 @@ PKLExport int pkl_pattern_hexagon(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE t
47
60
  }
48
61
 
49
62
  //=============================================================================
50
- // pkl_pattern_diamond
63
+ // pattern_hexagon
51
64
  //=============================================================================
52
- PKLExport int pkl_pattern_diamond(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE type)
65
+ void pattern_hexagon(int ph, double *wd, double ww, double hh)
53
66
  {
54
- double ww, hh, *wd;
55
- int i, result;
56
-
57
- wd = malloc(sizeof(double)*ph);
58
- if(!wd) return(1);
59
-
60
- ww = (double)pw;
61
- hh = (double)ph;
62
-
63
- /* パターン座標を構築する */
67
+ int i;
68
+ for(i=0; i<ph; i++){
69
+ if((double)i < hh/6.0){
70
+ wd[i] = ww * (double)i*6.0/hh;
71
+ }else
72
+ if((double)i < hh/2.0){
73
+ wd[i] = ww;
74
+ }else
75
+ if((double)i < hh*2.0/3.0){
76
+ wd[i] = ww*4.0 - ww*(double)i*6.0/hh;
77
+ }else{
78
+ wd[i] = 0.0;
79
+ }
80
+ }
81
+ }
82
+
83
+ //=============================================================================
84
+ // pattern_diamond
85
+ //=============================================================================
86
+ void pattern_diamond(int ph, double *wd, double ww, double hh)
87
+ {
88
+ int i;
64
89
  for(i=0; i<ph; i++){
65
90
  if((double)i < hh/2.0){
66
91
  wd[i] = ww*(double)i*2.0/hh;
@@ -68,36 +93,14 @@ PKLExport int pkl_pattern_diamond(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE t
68
93
  wd[i] = ww*2.0 - ww*(double)i*2.0/hh;
69
94
  }
70
95
  }
71
-
72
- /* 塗りタイプ別の処理 */
73
- switch(type){
74
- case PKL_PAINT_AVE:
75
- result = pkl_pattern_draw_average(pkl, wd, pw, ph);
76
- break;
77
- case PKL_PAINT_LINE:
78
- default:
79
- result = pkl_pattern_draw_line(pkl, wd, pw, ph);
80
- }
81
-
82
- free(wd);
83
- return(result);
84
96
  }
85
97
 
86
98
  //=============================================================================
87
- // pkl_pattern_circle
99
+ // pattern_circle
88
100
  //=============================================================================
89
- PKLExport int pkl_pattern_circle(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE type)
101
+ void pattern_circle(int ph, double *wd, double ww, double hh)
90
102
  {
91
- double ww, hh, *wd;
92
- int i, result;
93
-
94
- wd = malloc(sizeof(double)*ph);
95
- if(!wd) return(1);
96
-
97
- ww = (double)pw;
98
- hh = (double)ph;
99
-
100
- /* パターン座標を構築する */
103
+ int i;
101
104
  for(i=0; i<ph; i++){
102
105
  if((double)i < hh/2.0){
103
106
  wd[i] = ww*(double)i*2.0/hh - (ww/8.0)*sin((double)i*4.0/hh*M_PI);
@@ -105,36 +108,14 @@ PKLExport int pkl_pattern_circle(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE ty
105
108
  wd[i] = ww*2.0 - ww*(double)i*2.0/hh + (ww/8.0)*sin((double)(i-hh/2.0)*4.0/hh*M_PI);
106
109
  }
107
110
  }
108
-
109
- /* 塗りタイプ別の処理 */
110
- switch(type){
111
- case PKL_PAINT_AVE:
112
- result = pkl_pattern_draw_average(pkl, wd, pw, ph);
113
- break;
114
- case PKL_PAINT_LINE:
115
- default:
116
- result = pkl_pattern_draw_line(pkl, wd, pw, ph);
117
- }
118
-
119
- free(wd);
120
- return(result);
121
111
  }
122
112
 
123
113
  //=============================================================================
124
- // pkl_pattern_brick
114
+ // pattern_brick
125
115
  //=============================================================================
126
- PKLExport int pkl_pattern_brick(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE type)
116
+ void pattern_brick(int ph, double *wd, double ww, double hh)
127
117
  {
128
- double ww, hh, *wd;
129
- int i, result;
130
-
131
- wd = malloc(sizeof(double)*ph);
132
- if(!wd) return(1);
133
-
134
- ww = (double)pw;
135
- hh = (double)ph;
136
-
137
- /* パターン座標を構築する */
118
+ int i;
138
119
  for(i=0; i<ph; i++){
139
120
  if((double)i < hh/2.0){
140
121
  wd[i] = ww;
@@ -142,25 +123,12 @@ PKLExport int pkl_pattern_brick(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE typ
142
123
  wd[i] = 0.0;
143
124
  }
144
125
  }
145
-
146
- /* 塗りタイプ別の処理 */
147
- switch(type){
148
- case PKL_PAINT_AVE:
149
- result = pkl_pattern_draw_average(pkl, wd, pw, ph);
150
- break;
151
- case PKL_PAINT_LINE:
152
- default:
153
- result = pkl_pattern_draw_line(pkl, wd, pw, ph);
154
- }
155
-
156
- free(wd);
157
- return(result);
158
126
  }
159
127
 
160
128
  //=============================================================================
161
129
  // pkl_pattern_draw_line
162
130
  //=============================================================================
163
- static int pkl_pattern_draw_line(PKLImage pkl, double *wd, int pw, int ph)
131
+ int pkl_pattern_draw_line(PKLImage pkl, double *wd, int pw, int ph)
164
132
  {
165
133
  unsigned char clipcolor[PKL_CHANNEL], *p;
166
134
  int i, j, s, idx, k, color[PKL_CHANNEL];
@@ -215,7 +183,7 @@ static int pkl_pattern_draw_line(PKLImage pkl, double *wd, int pw, int ph)
215
183
  //=============================================================================
216
184
  // pkl_pattern_draw_average
217
185
  //=============================================================================
218
- static int pkl_pattern_draw_average(PKLImage pkl, double *wd, int pw, int ph)
186
+ int pkl_pattern_draw_average(PKLImage pkl, double *wd, int pw, int ph)
219
187
  {
220
188
  unsigned char clipcolor[PKL_CHANNEL], *p;
221
189
  int i, j, s, t, k, color[PKL_CHANNEL];
@@ -282,330 +250,388 @@ static int pkl_pattern_draw_average(PKLImage pkl, double *wd, int pw, int ph)
282
250
  }
283
251
 
284
252
  //=============================================================================
285
- // voronoi_type1 datatype
253
+ // pkl_tile
286
254
  //=============================================================================
287
- struct VoronoiPoint {
288
- int x, y;
289
- long color[PKL_CHANNEL];
290
- unsigned char ave[PKL_CHANNEL];
291
- int count;
292
- };
255
+ PKLExport int pkl_tile(PKLImage pkl, PKL_TILE_TYPE type, int msx, int msy, unsigned char level)
256
+ {
257
+ if(msx<=0 || msx>pkl->width || msy<=0 || msy>pkl->height)
258
+ return(1);
259
+
260
+ switch(type){
261
+ case PKL_TILE_RECT:
262
+ return tile_rectangle(pkl, msx, msy, level);
263
+ case PKL_TILE_HEXAGON:
264
+ case PKL_TILE_DIAMOND:
265
+ case PKL_TILE_CIRCLE:
266
+ return tile_pattern(pkl, type, msx, msy, level);
267
+ case PKL_TILE_BRICK:
268
+ return tile_brick(pkl, msx, msy, level);
269
+ }
270
+ return(1);
271
+ }
293
272
 
294
273
  //=============================================================================
295
- // voronoi_type1_query
274
+ // tile_brick
296
275
  //=============================================================================
297
- static void voronoi_type1_query(PKLImage pkl, struct VoronoiPoint *vptr, int *id, int zone, int xzone, int yzone)
276
+ static int tile_brick(PKLImage pkl, int msx, int msy, unsigned char level)
298
277
  {
299
- struct VoronoiPoint *p;
300
- int i, j, k, tx, ty, xx, yy, minIx, minIy;
301
- double d, mind;
302
-
303
- //母点を生成
304
- srand48(1);
305
- p = vptr;
306
- for(i=0; i<yzone; i++){
307
- for(j=0; j<xzone; j++){
308
- tx = j * zone + lrand48()%zone;
309
- ty = i * zone + lrand48()%zone;
310
- p->x = tx>=pkl->width ? pkl->width-1 : tx;
311
- p->y = ty>=pkl->height ? pkl->height-1 : ty;
312
- p++;
313
- }
314
- }
315
-
316
- for(i=0; i<pkl->height; i++){
317
- yy = i/zone;
318
- for(j=0; j<pkl->width; j++){
319
- xx = j/zone;
320
- mind=10000000;
321
- minIx=minIy=0;
278
+ unsigned char *wrk, *p;
279
+ int mpx, mpy; //モザイクの大きさ
280
+ int mlx, mly; //画像の分割数
281
+ int i, j, k, sx, sy, ex, ey, px, py, count, offset;
282
+ long color[PKL_CHANNEL];
283
+
284
+ wrk = malloc(pkl->width*pkl->height*pkl->channel);
285
+ if(!wrk) return(1);
286
+ memset(wrk, 0, pkl->width*pkl->height*pkl->channel);
287
+
288
+ mpx = (msx<1) ? 1 : (msx>=pkl->width) ? pkl->width-1 : msx;
289
+ mpy = (msy<1) ? 1 : (msy>=pkl->height) ? pkl->height-1 : msy;
290
+ mlx = (pkl->width+mpx-1)/mpx;
291
+ mly = (pkl->height+mpy-1)/mpy;
292
+
293
+ for(i=0; i<=mly; i++){
294
+ offset = (i%2) ? 0 : mpx/2;
295
+ for(j=0; j<=mlx; j++){
296
+ sx = j*mpx - offset;
297
+ sx = sx<0 ? 0 : sx;
298
+ sy = i*mpy;
299
+ ex = sx+mpx>pkl->width ? pkl->width : sx+mpx;
300
+ ey = sy+mpy>pkl->height ? pkl->height : sy+mpy;
322
301
 
323
- //カレントピクセルに最も近い母点を探す
324
- for(ty=yy-1; ty<=yy+1; ty++){
325
- if(ty<0 || ty>yzone-1) continue;
326
- for(tx=xx-1; tx<=xx+1; tx++){
327
- if(tx<0 || tx>xzone-1) continue;
328
- d = (vptr[ty*xzone+tx].x-j)*(vptr[ty*xzone+tx].x-j) +
329
- (vptr[ty*xzone+tx].y-i)*(vptr[ty*xzone+tx].y-i);
330
- if(d < mind){
331
- mind = d;
332
- minIx = tx;
333
- minIy = ty;
334
- }
302
+ //1セルの総和算出
303
+ count=0;
304
+ memset(color, 0, sizeof(color));
305
+ for(py=sy; py<ey; py++){
306
+ for(px=sx; px<ex; px++){
307
+ count++;
308
+ for(k=0; k<pkl->channel; k++)
309
+ color[k] += pkl->image[(py*pkl->width+px)*pkl->channel+k];
335
310
  }
336
311
  }
312
+ if(!count) continue;
337
313
 
314
+ //セルの平均色を算出して、セル内のピクセルに適用
338
315
  for(k=0; k<pkl->channel; k++)
339
- vptr[minIy*xzone+minIx].color[k] += pkl->image[(i*pkl->width+j)*pkl->channel+k];
340
- vptr[minIy*xzone+minIx].count++;
341
-
342
- //各ピクセルのボロノイIDをセット
343
- id[i*pkl->width+j] = minIy*xzone+minIx;
316
+ color[k] = PKL_COLOR_CLIP(color[k]/count);
317
+ for(py=sy; py<ey; py++){
318
+ for(px=sx; px<ex; px++){
319
+ for(k=0; k<pkl->channel; k++)
320
+ wrk[(py*pkl->width+px)*pkl->channel+k] = color[k];
321
+ }
322
+ }
323
+
324
+ //平均色で塗り終わったら枠線を描く
325
+ //横方向
326
+ for(px=sx; px<ex; px++){
327
+ p = &wrk[(sy*pkl->width+px)*pkl->channel];
328
+ for(k=0; k<pkl->channel; k++,p++)
329
+ *p = PKL_MIN(0xff, *p+level);
330
+
331
+ p = &wrk[((ey-1)*pkl->width+px)*pkl->channel];
332
+ for(k=0; k<pkl->channel; k++,p++)
333
+ *p = PKL_MAX(0, *p-level);
334
+ }
335
+ //縦方向
336
+ for(py=sy; py<ey; py++){
337
+ p = &wrk[(py*pkl->width+sx)*pkl->channel];
338
+ for(k=0; k<pkl->channel; k++,p++)
339
+ *p = PKL_MIN(0xff, *p+level);
340
+
341
+ p = &wrk[(py*pkl->width+ex-1)*pkl->channel];
342
+ for(k=0; k<pkl->channel; k++,p++)
343
+ *p = PKL_MAX(0, *p-level);
344
+ }
345
+
344
346
  }
345
347
  }
348
+
349
+ free(pkl->image);
350
+ pkl->image = wrk;
351
+ return(0);
346
352
  }
347
353
 
348
354
  //=============================================================================
349
- // pkl_voronoi_type1
355
+ // tile_rectangle
350
356
  //=============================================================================
351
- PKLExport int pkl_voronoi_type1(PKLImage pkl, int zone, int bordercolor, int test)
357
+ static int tile_rectangle(PKLImage pkl, int msx, int msy, unsigned char level)
352
358
  {
353
- struct VoronoiPoint *vptr, *p;
354
- int xzone, yzone, *id;
355
- int i, j, k, tx, ty;
356
- unsigned char border[PKL_CHANNEL];
357
-
358
-
359
- if(zone < 2) return(1);
360
- if(zone>=pkl->width || zone>=pkl->height) return(1);
361
- xzone = pkl->width/zone;
362
- if((pkl->width%zone) != 0) xzone++;
363
- yzone = pkl->height/zone;
364
- if((pkl->height%zone) != 0) yzone++;
365
-
366
- for(i=0; i<pkl->channel; i++)
367
- border[i] = (bordercolor>>((pkl->channel-i)*8) & 0xFF);
368
-
369
- //ボロノイ管理データ
370
- vptr = malloc(sizeof(struct VoronoiPoint) * xzone*yzone);
371
- memset(vptr, 0, sizeof(struct VoronoiPoint) * xzone*yzone);
372
-
373
- //各座標のボロノイIDを格納するデータ
374
- id = malloc(sizeof(int) * pkl->width*pkl->height);
375
-
376
- //ボロノイ管理データを作る
377
- voronoi_type1_query(pkl, vptr, id, zone, xzone, yzone);
378
-
379
- if(test){
380
- //分割シュミレーション(母点を置く)
381
- memset(pkl->image, 0xff, pkl->width*pkl->height*pkl->channel);
382
- for(i=0; i<xzone*yzone; i++)
383
- memcpy(&pkl->image[(vptr[i].y*pkl->width+vptr[i].x)*pkl->channel], border, pkl->channel);
384
- }else{
385
- //各ボロノイポイントの平均色算出
386
- for(ty=0; ty<yzone; ty++){
387
- for(tx=0; tx<xzone; tx++){
388
- if(vptr[ty*xzone+tx].count == 0) continue;
389
- p = &vptr[ty*xzone+tx];
390
- for(k=0; k<pkl->channel; k++)
391
- p->ave[k] = PKL_COLOR_CLIP(p->color[k]/p->count);
392
- }
359
+ unsigned char *p;
360
+ int i, j, k;
361
+
362
+ //モザイク化
363
+ if(pkl_mosaic(pkl, msx, msy)) return(1);
364
+
365
+ //横方向(light)
366
+ for(i=0; i<pkl->height; i+=msy){
367
+ for(j=0; j<pkl->width; j++){
368
+ p = &pkl->image[(i*pkl->width+j)*pkl->channel];
369
+ for(k=0; k<pkl->channel; k++,p++)
370
+ *p = PKL_MIN(0xff, *p+level);
393
371
  }
394
- //色を設定
395
- for(i=0; i<pkl->height; i++)
396
- for(j=0; j<pkl->width; j++)
397
- memcpy(&pkl->image[(i*pkl->width+j)*pkl->channel], vptr[id[i*pkl->width+j]].ave, pkl->channel);
398
372
  }
399
-
400
- //境界線を引く
401
- if(bordercolor!=-1){
402
- int currentId, hit=0;
403
- for(j=0; j<pkl->height; j++){
404
- for(i=0; i<pkl->width; i++){
405
- hit=0;
406
- currentId = id[j*pkl->width+i];
407
- if(i-1>=0 && currentId!=id[j*pkl->width+i-1]) hit++;
408
- if(i+1<pkl->width && currentId!=id[j*pkl->width+i+1]) hit++;
409
- if(j-1>=0 && currentId!=id[(j-1)*pkl->width+i+1]) hit++;
410
- if(j+1<pkl->height && currentId!=id[(j+1)*pkl->width+i+1]) hit++;
411
- if(hit)
412
- memcpy(&pkl->image[(j*pkl->width+i)*pkl->channel], border, pkl->channel);
413
- }
373
+
374
+ //横方向(dark)
375
+ for(i=msy-1; i<pkl->height; i+=msy){
376
+ for(j=0; j<pkl->width; j++){
377
+ p = &pkl->image[(i*pkl->width+j)*pkl->channel];
378
+ for(k=0; k<pkl->channel; k++,p++)
379
+ *p = PKL_MAX(0, *p-level);
414
380
  }
415
381
  }
416
- free(id);
417
- free(vptr);
418
- return(0);
419
- }
420
382
 
421
- //=============================================================================
422
- // voronoi_type2 datatype
423
- //=============================================================================
424
- //ボロノイの母点管理用(1つの母点から隣接する母点の個数)
425
- #define VORONOI_CNT 10 //根拠はない
383
+ //縦方向(light)
384
+ for(i=0; i<pkl->height; i++){
385
+ for(j=0; j<pkl->width; j+=msx){
386
+ p = &pkl->image[(i*pkl->width+j)*pkl->channel];
387
+ for(k=0; k<pkl->channel; k++,p++)
388
+ *p = PKL_MIN(0xff, *p+level);
389
+ }
390
+ }
391
+
392
+ //縦方向(dark)
393
+ for(i=0; i<pkl->height; i++){
394
+ for(j=msx-1; j<pkl->width; j+=msx){
395
+ p = &pkl->image[(i*pkl->width+j)*pkl->channel];
396
+ for(k=0; k<pkl->channel; k++,p++)
397
+ *p = PKL_MAX(0, *p-level);
398
+ }
399
+ }
426
400
 
427
- struct VORONOI {
428
- int x, y; //母点座標
429
- int id; //管理用ID
430
- long color[PKL_CHANNEL]; //ターゲット領域の色累積領域
431
- int count; //累積ピクセル数
432
- int next[VORONOI_CNT]; //隣接する母点のID
433
- };
401
+ return(0);
402
+ }
434
403
 
435
404
  //=============================================================================
436
- // vcompare
405
+ // tile_pattern
437
406
  //=============================================================================
438
- static int vcompare(const void *a, const void *b)
407
+ static int tile_pattern(PKLImage pkl, PKL_TILE_TYPE type, int pw, int ph, unsigned char level)
439
408
  {
440
- struct VORONOI *t1 = (struct VORONOI *)a;
441
- struct VORONOI *t2 = (struct VORONOI *)b;
409
+ double ww, hh, *wd;
410
+ int result=1;
411
+
412
+ wd = malloc(sizeof(double)*ph);
413
+ if(!wd) return(1);
414
+
415
+ ww = (double)pw;
416
+ hh = (double)ph;
442
417
 
443
- if(t1->y == t2->y)
444
- return(t1->x - t2->x);
445
- return(t1->y - t2->y);
418
+ /* パターン座標の構築 */
419
+ switch(type){
420
+ case PKL_TILE_HEXAGON:
421
+ pattern_hexagon(ph, wd, ww, hh); break;
422
+ case PKL_TILE_DIAMOND:
423
+ pattern_diamond(ph, wd, ww, hh); break;
424
+ case PKL_TILE_CIRCLE:
425
+ pattern_circle(ph, wd, ww, hh); break;
426
+ default:
427
+ ;;
428
+ }
429
+
430
+ //パターンで塗りつぶしてから枠を描く
431
+ if(!pkl_pattern_draw_average(pkl, wd, pw, ph))
432
+ result = tile_pattern_draw(pkl, wd, pw, ph, level);
433
+ free(wd);
434
+ return(result);
446
435
  }
447
436
 
448
437
  //=============================================================================
449
- // voronoi_setid
438
+ // tile_pattern_draw
450
439
  //=============================================================================
451
- static void voronoi_setid(int *ary, int id)
440
+ static int tile_pattern_draw(PKLImage pkl, double *wd, int pw, int ph, unsigned char level)
452
441
  {
453
- int i;
442
+ unsigned char *p;
443
+ int i, j, t, k, pos;
444
+ int ys, idx, ptn=0;
445
+ double ww, hh, rm;
454
446
 
455
- for(i=0; i<VORONOI_CNT; i++){
456
- if(ary[i] == -1){
457
- ary[i] = id;
458
- return;
447
+ ww = (double)pw;
448
+ hh = (double)ph;
449
+
450
+ for(j=0; j<pkl->width+pw; j+=pw){
451
+ ptn = !ptn;
452
+ ys = (ptn) ? 0 : (-ph/2);
453
+ for(i=ys; i<pkl->height; i+=ph){
454
+ rm=wd[0];
455
+
456
+ for(t=i; t<i+ph; t++){
457
+ if(t<0 || t>=pkl->height) continue;
458
+ idx = t % ph;
459
+ rm = ptn ? wd[idx] : ww-wd[idx];
460
+
461
+ //first=light
462
+ pos = j - rm;
463
+ if(pos>=0 && pos<pkl->width){
464
+ p = &pkl->image[(t*pkl->width+pos)*pkl->channel];
465
+ for(k=0; k<pkl->channel; k++,p++)
466
+ *p = PKL_MIN(0xff, *p+level);
467
+ }
468
+
469
+ //last=dark
470
+ pos = j + rm - 1;
471
+ if(pos>=0 && pos<pkl->width){
472
+ p = &pkl->image[(t*pkl->width+pos)*pkl->channel];
473
+ for(k=0; k<pkl->channel; k++,p++)
474
+ *p = PKL_MAX(0, *p-level);
475
+ }
476
+ }
459
477
  }
460
478
  }
479
+ return(0);
461
480
  }
462
481
 
482
+
463
483
  //=============================================================================
464
- // voronoi_type2_query
484
+ // pkl_mosaic
465
485
  //=============================================================================
466
- static void voronoi_type2_query(PKLImage pkl, struct VORONOI *kp, int *ip, int count)
486
+ PKLExport int pkl_mosaic(PKLImage pkl, int msx, int msy)
467
487
  {
468
- int i, j, k, min_id, pre_id;
469
- double d, dx, dy, min_d;
470
-
471
- //母点をランダムに生成する
472
- srand48((long)count);
473
- for(i=0; i<count; i++){
474
- kp[i].x = lrand48() % pkl->width;
475
- kp[i].y = lrand48() % pkl->height;
476
- kp[i].id = i;
477
- }
478
-
479
- //生成した母点座標を左上から右下に向かってソートする
480
- qsort(kp, count, sizeof(struct VORONOI), vcompare);
481
-
482
- min_id = 0; //最初の母点ID
483
- pre_id = 0; //前ピクセルの母点ID
484
-
485
- //各母点の最近傍の母点を探索する
486
- for(j=0; j<pkl->height; j++){
487
- for(i=0; i<pkl->width; i++){
488
- // 前ピクセルの母点との距離を求める
489
- dx = kp[pre_id].x-i;
490
- dy = kp[pre_id].y-j;
491
- min_d = sqrt(dx*dx+dy*dy);
488
+ unsigned char *wrk;
489
+ int mpx, mpy; //モザイクの大きさ
490
+ int mlx, mly; //画像の分割数
491
+ int i, j, k, sx, sy, ex, ey, px, py, mm;
492
+ long color[PKL_CHANNEL];
493
+
494
+ wrk = malloc(pkl->width*pkl->height*pkl->channel);
495
+ if(!wrk) return(1);
496
+ memset(wrk, 0, pkl->width*pkl->height*pkl->channel);
497
+
498
+ mpx = (msx<1) ? 1 : (msx>=pkl->width) ? pkl->width-1 : msx;
499
+ mpy = (msy<1) ? 1 : (msy>=pkl->height) ? pkl->height-1 : msy;
500
+ mlx = (pkl->width+mpx-1)/mpx;
501
+ mly = (pkl->height+mpy-1)/mpy;
502
+
503
+ for(i=0; i<=mly; i++){
504
+ for(j=0; j<=mlx; j++){
505
+ sx = j*mpx;
506
+ sy = i*mpy;
507
+ ex = sx+mpx>pkl->width ? pkl->width : sx+mpx;
508
+ ey = sy+mpy>pkl->height ? pkl->height : sy+mpy;
492
509
 
493
- //現在のピクセルの右上により近い母点があるか検索
494
- for(k=pre_id-1; k>=0 && (kp[k].y>=j-min_d); k--){
495
- if(kp[k].x >= i && kp[k].x <= i+min_d){
496
- dx = kp[k].x-i;
497
- dy = kp[k].y-j;
498
- d = sqrt(dx*dx+dy*dy);
499
- if(d<min_d){
500
- min_id=k;
501
- min_d=d;
502
- }
510
+ //1セルの総和算出
511
+ mm=0;
512
+ memset(color, 0, sizeof(color));
513
+ for(py=sy; py<ey; py++){
514
+ for(px=sx; px<ex; px++){
515
+ mm++;
516
+ for(k=0; k<pkl->channel; k++)
517
+ color[k] += pkl->image[(py*pkl->width+px)*pkl->channel+k];
503
518
  }
504
519
  }
505
- //現在のピクセルの右下により近い母点があるか検索
506
- for(k=pre_id+1; k<count && (kp[k].y<=j+min_d); k++){
507
- if(kp[k].x >= i && kp[k].x <= i+min_d){
508
- dx = kp[k].x-i;
509
- dy = kp[k].y-j;
510
- d = sqrt(dx*dx+dy*dy);
511
- if(d<min_d){
512
- min_id=k;
513
- min_d=d;
514
- }
520
+ if(!mm) continue;
521
+
522
+ //セルの平均色を算出して、セル内のピクセルに適用
523
+ for(k=0; k<pkl->channel; k++)
524
+ color[k] = PKL_COLOR_CLIP(color[k]/mm);
525
+ for(py=sy; py<ey; py++){
526
+ for(px=sx; px<ex; px++){
527
+ for(k=0; k<pkl->channel; k++)
528
+ wrk[(py*pkl->width+px)*pkl->channel+k] = color[k];
515
529
  }
516
530
  }
517
- //最も近くにある母点のIDを設定する
518
- if(pre_id != min_id){
519
- voronoi_setid(kp[pre_id].next, min_id);
520
- voronoi_setid(kp[min_id].next, pre_id);
531
+ }
532
+ }
533
+
534
+ free(pkl->image);
535
+ pkl->image = wrk;
536
+ return(0);
537
+ }
538
+
539
+ //=============================================================================
540
+ // pkl_pixelate
541
+ //=============================================================================
542
+ PKLExport int pkl_pixelate(PKLImage pkl, int ms)
543
+ {
544
+ unsigned char *wrk;
545
+ int mpx, mpy; //モザイクの大きさ
546
+ int mlx, mly; //画像の分割数
547
+ int i, j, k, sx, sy, ex, ey, px, py, mm;
548
+ long color[PKL_CHANNEL];
549
+ int total;
550
+ unsigned char p;
551
+
552
+ wrk = malloc(pkl->width*pkl->height*pkl->channel);
553
+ if(!wrk) return(1);
554
+
555
+ mpx = (ms<1) ? 1 : (ms>=pkl->width) ? pkl->width-1 : ms;
556
+ mpy = (ms<1) ? 1 : (ms>=pkl->height) ? pkl->height-1 : ms;
557
+ mlx = (pkl->width+mpx-1)/mpx;
558
+ mly = (pkl->height+mpy-1)/mpy;
559
+
560
+ for(i=0; i<=mly; i++){
561
+ for(j=0; j<=mlx; j++){
562
+ sx = j*mpx;
563
+ sy = i*mpy;
564
+ ex = sx+mpx>pkl->width ? pkl->width : sx+mpx;
565
+ ey = sy+mpy>pkl->height ? pkl->height : sy+mpy;
566
+
567
+ //1セルの総和算出
568
+ mm=0;
569
+ memset(color, 0, sizeof(color));
570
+ for(py=sy; py<ey; py++){
571
+ for(px=sx; px<ex; px++){
572
+ mm++;
573
+ for(k=0; k<pkl->channel; k++)
574
+ color[k] += pkl->image[(py*pkl->width+px)*pkl->channel+k];
575
+ }
521
576
  }
577
+ if(!mm) continue;
522
578
 
523
- //現在の座標のIDに決定したボロノイ管理IDを設定する
524
- ip[j*pkl->width+i] = min_id;
525
- pre_id = min_id;
579
+ //セルの平均色を算出
580
+ for(k=0; k<pkl->channel; k++)
581
+ color[k] = PKL_COLOR_CLIP(color[k]/mm);
582
+
583
+ total=0;
584
+ for(k=0; k<pkl->channel; k++)
585
+ total += color[k];
586
+ total /=pkl->channel;
587
+ p = total<128 ? 0 : 255;
588
+
589
+ for(py=sy; py<ey; py++){
590
+ for(px=sx; px<ex; px++){
591
+ for(k=0; k<pkl->channel; k++)
592
+ wrk[(py*pkl->width+px)*pkl->channel+k] = p;
593
+ }
594
+ }
526
595
  }
527
596
  }
597
+
598
+ free(pkl->image);
599
+ pkl->image = wrk;
600
+ return(0);
528
601
  }
529
602
 
530
603
  //=============================================================================
531
- // pkl_voronoi_type2
604
+ // pkl_grid
532
605
  //=============================================================================
533
- PKLExport int pkl_voronoi_type2(PKLImage pkl, int count, int bordercolor, int test)
606
+ PKLExport int pkl_grid(PKLImage pkl, int msx, int msy, int color)
534
607
  {
535
- struct VORONOI *kp;
536
- int i, j, k, *ip;
537
- unsigned char border[PKL_CHANNEL];
538
-
539
- //母点数の閾値
540
- if(count < 10) return(1);
541
-
542
- for(i=0; i<pkl->channel; i++)
543
- border[i] = (bordercolor>>((pkl->channel-i)*8) & 0xFF);
544
-
545
- //各座標の母点IDを格納する領域
546
- ip = malloc(sizeof(int) * pkl->width * pkl->height);
547
- memset(ip, -1, sizeof(int) * pkl->width * pkl->height);
548
-
549
- //母点管理領域(母点数分用意)
550
- kp = malloc(sizeof(struct VORONOI) * count);
551
- memset(kp, 0, sizeof(struct VORONOI) * count);
552
- for(i=0; i<count; i++)
553
- memset(kp[i].next, -1, sizeof(int)*VORONOI_CNT);
554
-
555
- //ボロノイ管理データを作る
556
- voronoi_type2_query(pkl, kp, ip, count);
557
-
558
- if(test){
559
- //分割シュミレーション(母点を置く)
560
- memset(pkl->image, 0xff, pkl->width*pkl->height*pkl->channel);
561
- for(i=0; i<count; i++)
562
- memcpy(&pkl->image[(kp[i].y*pkl->width+kp[i].x)*pkl->channel], border, pkl->channel);
563
- }else{
564
- //ボロノイ分割されたので、各セルの平均色を算出するためにセルの色を累積する
565
- for(j=0; j<pkl->height; j++) {
566
- for(i=0; i<pkl->width; i++) {
567
- //ipを参照することで、現在の座標がどのIDに所属するかわかる
568
- if(ip[j*pkl->width+i] == -1) continue;
569
- //IDごとに色を累積する
570
- kp[ ip[j*pkl->width+i] ].count++;
571
- for(k=0; k<pkl->channel; k++)
572
- kp[ ip[j*pkl->width+i] ].color[k] += pkl->image[(j*pkl->width+i)*pkl->channel+k];
608
+ unsigned char *p;
609
+ int i, j, k, mpx, mpy;
610
+
611
+ //一旦モザイク化
612
+ if(pkl_mosaic(pkl, msx, msy)) return(1);
613
+
614
+ mpx = (msx<1) ? 1 : (msx>=pkl->width) ? pkl->width-1 : msx;
615
+ mpy = (msy<1) ? 1 : (msy>=pkl->height) ? pkl->height-1 : msy;
616
+
617
+ for(i=0; i<pkl->height-1; i++){
618
+ if(i%mpy==0){
619
+ for(j=0; j<pkl->width; j++){
620
+ p = &pkl->image[(i*pkl->width+j)*pkl->channel];
621
+ for(k=0; k<pkl->channel; k++){
622
+ *p = PKL_COLOR_CLIP(*p+color);
623
+ p++;
624
+ }
573
625
  }
574
626
  }
575
-
576
- //各セルの平均色を作る
577
- for(i=0; i<count; i++){
627
+ for(j=mpx; j<pkl->width; j+=mpx){
628
+ p = &pkl->image[(i*pkl->width+j)*pkl->channel];
578
629
  for(k=0; k<pkl->channel; k++){
579
- if(kp[i].count!=0)
580
- kp[i].color[k] = PKL_COLOR_CLIP(kp[i].color[k]/kp[i].count);
630
+ *p = PKL_COLOR_CLIP(*p+color);
631
+ p++;
581
632
  }
582
633
  }
583
-
584
- //色を置く
585
- for(j=0; j<pkl->height; j++)
586
- for(i=0; i<pkl->width; i++)
587
- for(k=0; k<pkl->channel; k++)
588
- pkl->image[(j*pkl->width+i)*pkl->channel+k] = kp[ ip[j*pkl->width+i] ].color[k];
589
634
  }
590
635
 
591
- //境界線を引く
592
- if(bordercolor!=-1){
593
- int currentId, hit=0;
594
- for(j=0; j<pkl->height; j++){
595
- for(i=0; i<pkl->width; i++){
596
- hit=0;
597
- currentId = ip[j*pkl->width+i];
598
- if(i-1>=0 && currentId!=ip[j*pkl->width+i-1]) hit++;
599
- if(i+1<pkl->width && currentId!=ip[j*pkl->width+i+1]) hit++;
600
- if(j-1>=0 && currentId!=ip[(j-1)*pkl->width+i+1]) hit++;
601
- if(j+1<pkl->height && currentId!=ip[(j+1)*pkl->width+i+1]) hit++;
602
- if(hit)
603
- memcpy(&pkl->image[(j*pkl->width+i)*pkl->channel], border, pkl->channel);
604
- }
605
- }
606
- }
607
-
608
- free(kp);
609
- free(ip);
610
636
  return(0);
611
637
  }