crop.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <memdraw.h>
  5. enum
  6. {
  7. None,
  8. Inset, /* move border in or out uniformly */
  9. Insetxy, /* move border in or out; different parameters for x and y */
  10. Set, /* set rectangle to absolute values */
  11. Blank, /* cut off blank region according to color value */
  12. /* Blank is not actually set as a mode; it can be combined with others */
  13. };
  14. void
  15. usage(void)
  16. {
  17. fprint(2, "usage: crop [-b rgb] [-c rgb] [-i ±inset | -r R | -x ±inset | -y ±inset] [-t tx ty] [imagefile]\n");
  18. fprint(2, "\twhere R is a rectangle: minx miny maxx maxy\n");
  19. fprint(2, "\twhere rgb is a color: red green blue\n");
  20. exits("usage");
  21. }
  22. int
  23. getint(char *s)
  24. {
  25. if(s == nil)
  26. usage();
  27. if(*s == '+')
  28. return atoi(s+1);
  29. if(*s == '-')
  30. return -atoi(s+1);
  31. return atoi(s);
  32. }
  33. Rectangle
  34. crop(Memimage *m, ulong c)
  35. {
  36. Memimage *n;
  37. int x, y, bpl, wpl;
  38. int left, right, top, bottom;
  39. ulong *buf;
  40. left = m->r.max.x;
  41. right = m->r.min.x;
  42. top = m->r.max.y;
  43. bottom = m->r.min.y;
  44. n = nil;
  45. if(m->chan != RGBA32){
  46. /* convert type for simplicity */
  47. n = allocmemimage(m->r, RGBA32);
  48. if(n == nil)
  49. sysfatal("can't allocate temporary image: %r");
  50. memimagedraw(n, n->r, m, m->r.min, nil, ZP, S);
  51. m = n;
  52. }
  53. wpl = wordsperline(m->r, m->depth);
  54. bpl = wpl*sizeof(ulong);
  55. buf = malloc(bpl);
  56. if(buf == nil)
  57. sysfatal("can't allocate buffer: %r");
  58. for(y=m->r.min.y; y<m->r.max.y; y++){
  59. x = unloadmemimage(m, Rect(m->r.min.x, y, m->r.max.x, y+1), (uchar*)buf, bpl);
  60. if(x != bpl)
  61. sysfatal("unloadmemimage");
  62. for(x=0; x<wpl; x++)
  63. if(buf[x] != c){
  64. if(x < left)
  65. left = x;
  66. if(x > right)
  67. right = x;
  68. if(y < top)
  69. top = y;
  70. bottom = y;
  71. }
  72. }
  73. if(n != nil)
  74. freememimage(n);
  75. return Rect(left, top, right+1, bottom+1);
  76. }
  77. void
  78. main(int argc, char *argv[])
  79. {
  80. int fd, mode, red, green, blue;
  81. Rectangle r, rparam;
  82. Point t;
  83. Memimage *m, *new;
  84. char *file;
  85. ulong bg, cropval;
  86. long dw;
  87. memimageinit();
  88. mode = None;
  89. bg = 0;
  90. cropval = 0;
  91. t = ZP;
  92. memset(&rparam, 0, sizeof rparam);
  93. ARGBEGIN{
  94. case 'b':
  95. if(bg != 0)
  96. usage();
  97. red = getint(ARGF())&0xFF;
  98. green = getint(ARGF())&0xFF;
  99. blue = getint(ARGF())&0xFF;
  100. bg = (red<<24)|(green<<16)|(blue<<8)|0xFF;
  101. break;
  102. case 'c':
  103. if(cropval != 0)
  104. usage();
  105. red = getint(ARGF())&0xFF;
  106. green = getint(ARGF())&0xFF;
  107. blue = getint(ARGF())&0xFF;
  108. cropval = (red<<24)|(green<<16)|(blue<<8)|0xFF;
  109. break;
  110. case 'i':
  111. if(mode != None)
  112. usage();
  113. mode = Inset;
  114. rparam.min.x = getint(ARGF());
  115. break;
  116. case 'x':
  117. if(mode != None && mode != Insetxy)
  118. usage();
  119. mode = Insetxy;
  120. rparam.min.x = getint(ARGF());
  121. break;
  122. case 'y':
  123. if(mode != None && mode != Insetxy)
  124. usage();
  125. mode = Insetxy;
  126. rparam.min.y = getint(ARGF());
  127. break;
  128. case 'r':
  129. if(mode != None)
  130. usage();
  131. mode = Set;
  132. rparam.min.x = getint(ARGF());
  133. rparam.min.y = getint(ARGF());
  134. rparam.max.x = getint(ARGF());
  135. rparam.max.y = getint(ARGF());
  136. break;
  137. case 't':
  138. t.x = getint(ARGF());
  139. t.y = getint(ARGF());
  140. break;
  141. default:
  142. usage();
  143. }ARGEND
  144. if(mode == None && cropval == 0 && eqpt(ZP, t))
  145. usage();
  146. file = "<stdin>";
  147. fd = 0;
  148. if(argc > 1)
  149. usage();
  150. else if(argc == 1){
  151. file = argv[0];
  152. fd = open(file, OREAD);
  153. if(fd < 0)
  154. sysfatal("can't open %s: %r", file);
  155. }
  156. m = readmemimage(fd);
  157. if(m == nil)
  158. sysfatal("can't read %s: %r", file);
  159. r = m->r;
  160. if(cropval != 0){
  161. r = crop(m, cropval);
  162. m->clipr = r;
  163. }
  164. switch(mode){
  165. case None:
  166. break;
  167. case Inset:
  168. r = insetrect(r, rparam.min.x);
  169. break;
  170. case Insetxy:
  171. r.min.x += rparam.min.x;
  172. r.max.x -= rparam.min.x;
  173. r.min.y += rparam.min.y;
  174. r.max.y -= rparam.min.y;
  175. break;
  176. case Set:
  177. r = rparam;
  178. break;
  179. }
  180. new = allocmemimage(r, m->chan);
  181. if(new == nil)
  182. sysfatal("can't allocate new image: %r");
  183. if(bg != 0)
  184. memfillcolor(new, bg);
  185. else
  186. memfillcolor(new, 0x000000FF);
  187. memimagedraw(new, m->clipr, m, m->clipr.min, nil, ZP, S);
  188. dw = byteaddr(new, ZP) - byteaddr(new, t);
  189. new->r = rectaddpt(new->r, t);
  190. new->zero += dw;
  191. if(writememimage(1, new) < 0)
  192. sysfatal("write error on output: %r");
  193. exits(nil);
  194. }