crop.c 4.5 KB

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