Advertisement
Guest User

Untitled

a guest
Sep 23rd, 2017
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 53.62 KB | None | 0 0
  1. import java.awt.*;
  2. import java.net.URL;
  3. import java.util.Stack;
  4. import java.awt.Point;
  5. import java.io.*;
  6. /**
  7. * A class that represents a picture. This class inherits from SimplePicture
  8. * and allows the student to add functionality and picture effects.
  9. *
  10. * @author Barb Ericson (ericson@cc.gatech.edu)
  11. * (Copyright Georgia Institute of Technology 2004)
  12. * @author Modified by Colleen Lewis (colleenl@berkeley.edu),
  13. * Jonathan Kotker (jo_ko_berkeley@berkeley.edu),
  14. * Kaushik Iyer (kiyer@berkeley.edu), George Wang (georgewang@berkeley.edu),
  15. * and David Zeng (davidzeng@berkeley.edu), for use in CS61BL, the data
  16. * structures course at University of California, Berkeley.
  17. */
  18. public class Picture extends SimplePicture
  19. {
  20.  
  21. /////////////////////////// Static Variables //////////////////////////////
  22.  
  23. // Different axes available to flip a picture.
  24. public static final int HORIZONTAL = 1;
  25. public static final int VERTICAL = 2;
  26. public static final int FORWARD_DIAGONAL = 3;
  27. public static final int BACKWARD_DIAGONAL = 4;
  28.  
  29. // Different Picture objects for the bitmaps used in ASCII art conversion.
  30. private static Picture BMP_AMPERSAND;
  31. private static Picture BMP_APOSTROPHE;
  32. private static Picture BMP_AT;
  33. private static Picture BMP_BAR;
  34. private static Picture BMP_COLON;
  35. private static Picture BMP_DOLLAR;
  36. private static Picture BMP_DOT;
  37. private static Picture BMP_EXCLAMATION;
  38. private static Picture BMP_GRAVE;
  39. private static Picture BMP_HASH;
  40. private static Picture BMP_PERCENT;
  41. private static Picture BMP_SEMICOLON;
  42. private static Picture BMP_SPACE;
  43.  
  44. //////////////////////////// Constructors /////////////////////////////////
  45.  
  46. /**
  47. * A constructor that takes no arguments.
  48. */
  49. public Picture () {
  50. super();
  51. }
  52.  
  53. /**
  54. * Creates a Picture from the file name provided.
  55. *
  56. * @param fileName The name of the file to create the picture from.
  57. */
  58. public Picture(String fileName) {
  59. // Let the parent class handle this fileName.
  60. super(fileName);
  61. }
  62.  
  63. /**
  64. * Creates a Picture from the width and height provided.
  65. *
  66. * @param width the width of the desired picture.
  67. * @param height the height of the desired picture.
  68. */
  69. public Picture(int width, int height) {
  70. // Let the parent class handle this width and height.
  71. super(width, height);
  72. }
  73.  
  74. /**
  75. * Creates a copy of the Picture provided.
  76. *
  77. * @param pictureToCopy Picture to be copied.
  78. */
  79. public Picture(Picture pictureToCopy) {
  80. // Let the parent class do the copying.
  81. super(pictureToCopy);
  82. }
  83.  
  84. /**
  85. * Creates a copy of the SimplePicture provided.
  86. *
  87. * @param pictureToCopy SimplePicture to be copied.
  88. */
  89. public Picture(SimplePicture pictureToCopy) {
  90. // Let the parent class do the copying.
  91. super(pictureToCopy);
  92. }
  93.  
  94. /////////////////////////////// Methods ///////////////////////////////////
  95.  
  96. /**
  97. * @return A string with information about the picture, such as
  98. * filename, height, and width.
  99. */
  100. public String toString() {
  101. String output = "Picture, filename = " + this.getFileName() + "," +
  102. " height = " + this.getHeight() + ", width = " + this.getWidth();
  103. return output;
  104. }
  105.  
  106. /////////////////////// PROJECT 1 BEGINS HERE /////////////////////////////
  107.  
  108. /* Each of the methods below is constructive: in other words, each of
  109. * the methods below generates a new Picture, without permanently
  110. * modifying the original Picture. */
  111.  
  112. //////////////////////////////// Level 1 //////////////////////////////////
  113.  
  114. /**
  115. * Converts the Picture into grayscale. Since any variation of gray
  116. * is obtained by setting the red, green, and blue components to the same
  117. * value, a Picture can be converted into its grayscale component
  118. * by setting the red, green, and blue components of each pixel in the
  119. * new picture to the same value: the average of the red, green, and blue
  120. * components of the same pixel in the original.
  121. *
  122. * @return A new Picture that is the grayscale version of this Picture.
  123. */
  124. public Picture grayscale() {
  125. Picture newPicture = new Picture(this);
  126.  
  127. int pictureHeight = this.getHeight();
  128. int pictureWidth = this.getWidth();
  129.  
  130. for(int x = 0; x < pictureWidth; x++) {
  131. for(int y = 0; y < pictureHeight; y++) {
  132. newPicture.setPixelToGray(x, y);
  133. }
  134. }
  135. return newPicture;
  136. }
  137.  
  138. /**
  139. * Helper method for grayscale() to set a pixel at (x, y) to be gray.
  140. *
  141. * @param x The x-coordinate of the pixel to be set to gray.
  142. * @param y The y-coordinate of the pixel to be set to gray.
  143. */
  144. private void setPixelToGray(int x, int y) {
  145. Pixel currentPixel = this.getPixel(x, y);
  146.  
  147. //Set the RGB value of colors to the average of the colors.
  148. int average = currentPixel.getAverage();
  149. currentPixel.setRed(average);
  150. currentPixel.setGreen(average);
  151. currentPixel.setBlue(average);
  152. }
  153.  
  154.  
  155.  
  156.  
  157. /**
  158. * Test method for setPixelToGray. This method is called by
  159. * the JUnit file through the public method Picture.helpersWork().
  160. */
  161. private static boolean setPixelToGrayWorks()
  162. {
  163. Picture bg = Picture.loadPicture("Creek.bmp");
  164. Pixel focalPixel = bg.getPixel(10, 10);
  165. bg.setPixelToGray(10, 10);
  166. int goalColor = (int) focalPixel.getAverage();
  167. int originalAlpha = focalPixel.getColor().getAlpha();
  168. boolean redCorrect = focalPixel.getRed() == goalColor;
  169. boolean greenCorrect = focalPixel.getGreen() == goalColor;
  170. boolean blueCorrect = focalPixel.getBlue() == goalColor;
  171. boolean alphaCorrect = focalPixel.getAlpha() == originalAlpha;
  172. return redCorrect && greenCorrect && blueCorrect && alphaCorrect;
  173. }
  174.  
  175. /**
  176. * This method provide JUnit access to the testing methods written
  177. * within Picture.java
  178. */
  179. public static boolean helpersWork()
  180. {
  181. if (!Picture.setPixelToGrayWorks())
  182. {
  183. return false;
  184. }
  185.  
  186. if( !Picture.setPixelToLightenWorks() )
  187. {
  188. return false;
  189. }
  190. // You could put other tests here..
  191.  
  192. if( !Picture.convertChunkToAsciiWorks() )
  193. {
  194. return false;
  195. }
  196. //Test for Negate
  197. if (!Picture.setPixelToNegateWorks())
  198. {
  199. return false;
  200. }
  201.  
  202. //Tests for adding blue
  203. if (!Picture. setPixelToAddBlueWorks(0)) // Tests to see if adding no extra blue will work
  204. {
  205. return false;
  206. }
  207. if (!Picture. setPixelToAddBlueWorks(255)) //Tests to see if completely saturating the blue will work
  208. {
  209. return false;
  210. }
  211. if (!Picture. setPixelToAddBlueWorks(1)) //Tests to see if adding some value of blue will work
  212. {
  213. return false;
  214. }
  215.  
  216. //Tests for adding green
  217. if (!Picture. setPixelToAddGreenWorks(0)) // Tests to see if adding no extra green will work
  218. {
  219. return false;
  220. }
  221. if (!Picture. setPixelToAddGreenWorks(255)) //Tests to see if completely saturating the green will work
  222. {
  223. return false;
  224. }
  225. if (!Picture. setPixelToAddGreenWorks(1)) //Tests to see if adding some value of green will work
  226. {
  227. return false;
  228. }
  229.  
  230. //Tests for adding red
  231. if (!Picture. setPixelToAddRedWorks(0)) // Tests to see if adding no extra red will work
  232. {
  233. return false;
  234. }
  235. if (!Picture. setPixelToAddRedWorks(255)) //Tests to see if completely saturating the red will work
  236. {
  237. return false;
  238. }
  239. if (!Picture. setPixelToAddRedWorks(1)) //Tests to see if adding some value of red will work
  240. {
  241. return false;
  242. }
  243.  
  244. //Tests for Chromakey
  245. if (!Picture. setChromakeySize()) //Tests to see if the right sized image will be returned
  246. {
  247. return false;
  248. }
  249.  
  250. //if (!Picture. checkExceedsThreshold(-5)) //Tests to see that threshold will be exceeded no matter what
  251. {
  252. // return false;
  253. }
  254. //if (Picture. checkExceedsThreshold(442)) //Tests to see that threshold will not be exceeded no matter what
  255. //(This is a little larger than the maximum color distance)
  256. {
  257. // return false;
  258. }
  259.  
  260. return true;
  261. }
  262.  
  263. /**
  264. * Converts the Picture into its photonegative version. The photonegative
  265. * version of an image is obtained by setting each of the red, green,
  266. * and blue components of every pixel to a value that is 255 minus their
  267. * current values.
  268. *
  269. * @return A new Picture that is the photonegative version of this Picture.
  270. */
  271. public Picture negate() {
  272. Picture newPicture = new Picture(this);
  273.  
  274. int pictureHeight = this.getHeight();
  275. int pictureWidth = this.getWidth();
  276.  
  277. for(int x = 0; x < pictureWidth; x++) {
  278. for(int y = 0; y < pictureHeight; y++)
  279. {
  280. newPicture.setPixelToNegate(x, y);
  281. }
  282. }
  283. return newPicture;
  284. }
  285.  
  286.  
  287.  
  288. /**
  289. * Helper method for negate() to set a pixel at (x, y) to be photo negative.
  290. *
  291. * @param x The x-coordinate of the pixel to be set to gray.
  292. * @param y The y-coordinate of the pixel to be set to gray.
  293. */
  294. private void setPixelToNegate(int x, int y) {
  295. Pixel currentPixel = this.getPixel(x, y);
  296. currentPixel.setRed( 255 - currentPixel.getRed());
  297. currentPixel.setGreen(255 - currentPixel.getGreen());
  298. currentPixel.setBlue(255 - currentPixel.getBlue());
  299.  
  300. }
  301.  
  302. /**
  303. * Test method for setPixelToNegate. This method is called by
  304. * the JUnit file through the public method Picture.helpersWork().
  305. */
  306. private static boolean setPixelToNegateWorks()
  307. {
  308. Picture bg = Picture.loadPicture("Creek.bmp");
  309. Pixel focalPixel = bg.getPixel(10, 10);
  310. int goalRed = (255 - focalPixel.getRed());
  311. int goalGreen = (255 - focalPixel.getGreen());
  312. int goalBlue = (255 - focalPixel.getBlue());
  313. int originalAlpha = focalPixel.getColor().getAlpha();
  314. bg.setPixelToNegate(10, 10);
  315. boolean redCorrect = focalPixel.getRed() == goalRed;
  316. boolean greenCorrect = focalPixel.getGreen() == goalGreen;
  317. boolean blueCorrect = focalPixel.getBlue() == goalBlue;
  318. boolean alphaCorrect = focalPixel.getAlpha() == originalAlpha;
  319. return redCorrect && greenCorrect && blueCorrect && alphaCorrect;
  320. }
  321.  
  322.  
  323. /**
  324. * Creates an image that is lighter than the original image by amount. The range of
  325. * each color component should be between 0 and 255 in the new image. The
  326. * alpha value should not be changed.
  327. *
  328. * @return A new Picture that has every color value of the Picture increased
  329. * by the lightenAmount.
  330. */
  331. public Picture lighten(int lightenAmount) {
  332.  
  333. Picture newPicture = new Picture(this);
  334. int pictureHeight = this.getHeight();
  335. int pictureWidth = this.getWidth();
  336.  
  337. for(int x = 0; x < pictureWidth; x++)
  338. {
  339. for(int y = 0; y < pictureHeight; y++)
  340. {
  341. newPicture.setPixelToLighten(x, y , lightenAmount);
  342. }
  343. }
  344. return newPicture;
  345. }
  346.  
  347. /**
  348. * Helper method for Lighten() to set a pixel at (x, y) to be lighter by amount.
  349. *
  350. * @param x The x-coordinate of the pixel to be set to gray.
  351. * @param y The y-coordinate of the pixel to be set to gray.
  352. */
  353. private void setPixelToLighten(int x, int y , int amount) {
  354. Pixel currentPixel = this.getPixel(x, y);
  355. currentPixel.setRed( amount + currentPixel.getRed());
  356. currentPixel.setGreen(amount + currentPixel.getGreen());
  357. currentPixel.setBlue( amount + currentPixel.getBlue());
  358.  
  359. }
  360.  
  361. /**
  362. * Test method for setPixelToLighten. This method is called by
  363. * the JUnit file through the public method Picture.helpersWork().
  364. */
  365. private static boolean setPixelToLightenWorks()
  366. {
  367. // Test the general case.
  368. Picture bg = Picture.loadPicture("Creek.bmp");
  369. Pixel focalPixel = bg.getPixel(10, 10);
  370. int originalRed = focalPixel.getRed();
  371. int originalGreen = focalPixel.getGreen();
  372. int originalBlue = focalPixel.getBlue();
  373. int originalAlpha = focalPixel.getAlpha();
  374. bg.setPixelToLighten(10, 10 , 30);
  375. Pixel newPixel = bg.getPixel(10, 10 );
  376. boolean redCorrect = newPixel.getRed() == originalRed + 30;
  377. boolean greenCorrect = newPixel.getGreen() == originalGreen + 30;
  378. boolean blueCorrect = newPixel.getBlue() == originalBlue + 30;
  379. boolean alphaCorrect = newPixel.getAlpha() == originalAlpha;
  380.  
  381. if( ! (redCorrect && greenCorrect && blueCorrect && alphaCorrect) )
  382. {
  383. return false;
  384. }
  385.  
  386. //Test the end cases.
  387. bg = Picture.loadPicture("Creek.bmp");
  388. focalPixel = bg.getPixel( bg.getWidth() -1 , bg.getHeight() -1 );
  389. originalRed = focalPixel.getRed();
  390. originalGreen = focalPixel.getGreen();
  391. originalBlue = focalPixel.getBlue();
  392. originalAlpha = focalPixel.getAlpha();
  393. bg.setPixelToLighten( bg.getWidth() -1 , bg.getHeight() -1, 30);
  394. newPixel = bg.getPixel(bg.getWidth() -1 , bg.getHeight() -1 );
  395. redCorrect = newPixel.getRed() == originalRed + 30;
  396. greenCorrect = newPixel.getGreen() == originalGreen + 30;
  397. blueCorrect = newPixel.getBlue() == originalBlue + 30;
  398. alphaCorrect = newPixel.getAlpha() == originalAlpha;
  399.  
  400. if( ! (redCorrect && greenCorrect && blueCorrect && alphaCorrect) )
  401. {
  402. return false;
  403. }
  404.  
  405. //Test the near-white pixels.
  406. bg = Picture.loadPicture("colleen.bmp");
  407. focalPixel = bg.getPixel( 40 , 10 );
  408. originalRed = focalPixel.getRed();
  409. originalGreen = focalPixel.getGreen();
  410. originalBlue = focalPixel.getBlue();
  411. originalAlpha = focalPixel.getAlpha();
  412. bg.setPixelToLighten( 40 , 10 , 30);
  413. redCorrect = 255 == originalRed;
  414. greenCorrect = 255 == originalGreen;
  415. blueCorrect = 255 == originalBlue;
  416. alphaCorrect = focalPixel.getAlpha() == originalAlpha;
  417. if( ! (redCorrect && greenCorrect && blueCorrect && alphaCorrect) )
  418. {
  419. return true;
  420. }
  421.  
  422. return true;
  423. }
  424.  
  425.  
  426. /**
  427. * Creates an image that is darker than the original image by amount. The range of
  428. * each color component should be between 0 and 255 in the new image. The
  429. * alpha value should not be changed.
  430. *
  431. * @return A new Picture that has every color value of the Picture increased
  432. * by the lightenAmount.
  433. */
  434. public Picture darken(int darkenAmount) {
  435.  
  436. Picture newPicture = new Picture(this);
  437. int pictureHeight = this.getHeight();
  438. int pictureWidth = this.getWidth();
  439.  
  440. for(int x = 0; x < pictureWidth; x++) {
  441. for(int y = 0; y < pictureHeight; y++) {
  442. newPicture.setPixelToDarken(x, y , darkenAmount);
  443. }
  444. }
  445. return newPicture;
  446. }
  447. /**
  448. * Helper method for Darken() to set a pixel at (x, y) to be a darker by amount.
  449. *
  450. * @param x The x-coordinate of the pixel to be set to gray.
  451. * @param y The y-coordinate of the pixel to be set to gray.
  452. */
  453. private void setPixelToDarken(int x, int y , int amount) {
  454. Pixel currentPixel = this.getPixel(x, y);
  455. currentPixel.setRed( currentPixel.getRed() - amount);
  456. currentPixel.setGreen(currentPixel.getGreen() - amount);
  457. currentPixel.setBlue( currentPixel.getBlue() - amount);
  458.  
  459. }
  460.  
  461.  
  462.  
  463. /**
  464. * Creates an image where the blue value has been increased by amount.The range of
  465. * each color component should be between 0 and 255 in the new image. The
  466. * alpha value should not be changed.
  467. *
  468. * @return A new Picture that has every blue value of the Picture increased
  469. * by amount.
  470. */
  471. public Picture addBlue(int amount) {
  472. Picture newPicture = new Picture(this);
  473. int pictureHeight = this.getHeight();
  474. int pictureWidth = this.getWidth();
  475.  
  476. for(int x = 0; x < pictureWidth; x++) {
  477. for(int y = 0; y < pictureHeight; y++) {
  478. newPicture.setPixelToAddBlue(x, y , amount);
  479. }
  480. }
  481. return newPicture;
  482. }
  483. /**
  484. * Helper method for addBlue() to set a pixel at (x, y) to be more Blue by blueAmount.
  485. *
  486. * @param x The x-coordinate of the pixel to be set to gray.
  487. * @param y The y-coordinate of the pixel to be set to gray.
  488. */
  489. private void setPixelToAddBlue(int x, int y , int blueAmount) {
  490. Pixel currentPixel = this.getPixel(x, y);
  491. currentPixel.setBlue( currentPixel.getBlue() + blueAmount);
  492.  
  493. }
  494. /**
  495. * Test method for setPixelToAddBlue. This method is called by
  496. * the JUnit file through the public method Picture.helpersWork().
  497. */
  498. private static boolean setPixelToAddBlueWorks(int amount)
  499. {
  500. Picture bg = Picture.loadPicture("Creek.bmp");
  501. Pixel focalPixel = bg.getPixel(10, 10);
  502. int goalBlue = (focalPixel.getBlue() + amount);
  503.  
  504. if(goalBlue > 255){
  505. goalBlue = 255; //The individual RGB and alpha values cannot exceed 255.
  506. }
  507.  
  508. int originalAlpha = focalPixel.getColor().getAlpha();
  509. bg.setPixelToAddBlue(10, 10, amount);
  510. boolean blueCorrect = focalPixel.getBlue() == goalBlue;
  511. boolean alphaCorrect = focalPixel.getAlpha() == originalAlpha;
  512. return blueCorrect && alphaCorrect;
  513. }
  514.  
  515. /**
  516. * Creates an image where the red value has been increased by amount. The range of
  517. * each color component should be between 0 and 255 in the new image. The
  518. * alpha value should not be changed.
  519. *
  520. * @return A new Picture that has every red value of the Picture increased
  521. * by amount.
  522. */
  523. public Picture addRed(int amount) {
  524. Picture newPicture = new Picture(this);
  525. int pictureHeight = this.getHeight();
  526. int pictureWidth = this.getWidth();
  527.  
  528. for(int x = 0; x < pictureWidth; x++) {
  529. for(int y = 0; y < pictureHeight; y++) {
  530. newPicture.setPixelToAddRed(x, y , amount);
  531. }
  532. }
  533. return newPicture;
  534. }
  535.  
  536. /**
  537. * Helper method for addRed() to set a pixel at (x, y) to be more red by redAmount.
  538. *
  539. * @param x The x-coordinate of the pixel to be set to gray.
  540. * @param y The y-coordinate of the pixel to be set to gray.
  541. */
  542. private void setPixelToAddRed(int x, int y , int redAmount) {
  543. Pixel currentPixel = this.getPixel(x, y);
  544. currentPixel.setRed( currentPixel.getRed() + redAmount);
  545.  
  546. }
  547.  
  548. /**
  549. * Test method for setPixelToAddRed. This method is called by
  550. * the JUnit file through the public method Picture.helpersWork().
  551. */
  552. private static boolean setPixelToAddRedWorks(int amount)
  553. {
  554. Picture bg = Picture.loadPicture("Creek.bmp");
  555. Pixel focalPixel = bg.getPixel(10, 10);
  556. int goalRed = (focalPixel.getRed() + amount);
  557.  
  558. if(goalRed > 255){
  559. goalRed = 255; //The individual RGB and alpha values cannot exceed 255.
  560. }
  561.  
  562. int originalAlpha = focalPixel.getColor().getAlpha();
  563. bg.setPixelToAddRed(10, 10, amount);
  564. boolean redCorrect = focalPixel.getRed() == goalRed;
  565. boolean alphaCorrect = focalPixel.getAlpha() == originalAlpha;
  566. return redCorrect && alphaCorrect;
  567. }
  568.  
  569.  
  570. /**
  571. * Creates an image where the green value has been increased by amount. The range of
  572. * each color component should be between 0 and 255 in the new image. The
  573. * alpha value should not be changed.
  574. *
  575. * @return A new Picture that has every green value of the Picture increased
  576. * by amount.
  577. */
  578. public Picture addGreen(int amount) {
  579. Picture newPicture = new Picture(this);
  580. int pictureHeight = this.getHeight();
  581. int pictureWidth = this.getWidth();
  582.  
  583. for(int x = 0; x < pictureWidth; x++) {
  584. for(int y = 0; y < pictureHeight; y++) {
  585. newPicture.setPixelToAddGreen(x, y , amount);
  586. }
  587. }
  588. return newPicture;
  589. }
  590. /**
  591. * Helper method for addGreen() to set a pixel at (x, y) to be more green by greenAmount.
  592. *
  593. * @param x The x-coordinate of the pixel to be set to gray.
  594. * @param y The y-coordinate of the pixel to be set to gray.
  595. */
  596. private void setPixelToAddGreen(int x, int y , int greenAmount) {
  597. Pixel currentPixel = this.getPixel(x, y);
  598. currentPixel.setGreen( currentPixel.getGreen() + greenAmount);
  599.  
  600. }
  601.  
  602. /**
  603. * Test method for setPixelToAddBlue. This method is called by
  604. * the JUnit file through the public method Picture.helpersWork().
  605. */
  606. private static boolean setPixelToAddGreenWorks(int amount)
  607. {
  608. Picture bg = Picture.loadPicture("Creek.bmp");
  609. Pixel focalPixel = bg.getPixel(10, 10);
  610. int goalGreen = (focalPixel.getGreen() + amount);
  611.  
  612. if(goalGreen > 255){
  613. goalGreen = 255; //The individual RGB and alpha values cannot exceed 255.
  614. }
  615.  
  616. int originalAlpha = focalPixel.getColor().getAlpha();
  617. bg.setPixelToAddGreen(10, 10, amount);
  618. boolean greenCorrect = focalPixel.getGreen() == goalGreen;
  619. boolean alphaCorrect = focalPixel.getAlpha() == originalAlpha;
  620. return greenCorrect && alphaCorrect;
  621. }
  622.  
  623.  
  624. /**
  625. * @param x x-coordinate of the pixel currently selected.
  626. * @param y y-coordinate of the pixel currently selected.
  627. * @param background Picture to use as the background.
  628. * @param threshold Threshold within which to replace pixels.
  629. *
  630. * @return A new Picture where all the pixels in the original Picture,
  631. * which differ from the currently selected pixel within the provided
  632. * threshold (in terms of color distance), are replaced with the
  633. * corresponding pixels in the background picture provided.
  634. *
  635. * If the two Pictures are of different dimensions, the new Picture will
  636. * have length equal to the smallest of the two Pictures being combined,
  637. * and height equal to the smallest of the two Pictures being combined.
  638. * In this case, the Pictures are combined as if they were aligned at
  639. * the top left corner (0, 0).
  640. */
  641. public Picture chromaKey(int xRef, int yRef, Picture background, int threshold) {
  642.  
  643. //Make a new picture with the dimensions of the smallest.
  644. int newWidth = Math.min(this.getWidth(), background.getWidth() );
  645. int newHeight = Math.min(this.getHeight(), background.getHeight() );
  646. Picture newPicture = new Picture(newWidth , newHeight);
  647.  
  648. Color newColor = this.getPixel(xRef, yRef).getColor();
  649.  
  650. for(int x = 0; x < newWidth; x++) {
  651. for(int y = 0; y < newHeight; y++) {
  652.  
  653. int newAlpha, newRed , newGreen, newBlue;
  654.  
  655.  
  656. if( this.getPixel(x, y).colorDistance(newColor) < threshold )
  657. {
  658. //Replace the pixel with the correspondin one from the background.
  659. newAlpha = background.getPixel(x , y).getAlpha();
  660. newRed = background.getPixel(x , y).getRed();
  661. newGreen = background.getPixel(x , y).getGreen();
  662. newBlue = background.getPixel(x , y).getBlue();
  663. }
  664. else
  665. {
  666. //The Pixel comes from the foreground.
  667. newAlpha = this.getPixel(x , y).getAlpha();
  668. newRed = this.getPixel(x , y).getRed();
  669. newGreen = this.getPixel(x , y).getGreen();
  670. newBlue = this.getPixel(x , y).getBlue();
  671. }
  672.  
  673. //Update the picture.
  674. newPicture.getPixel(x, y).updatePicture(newAlpha,newRed , newGreen, newBlue);
  675. }
  676. }
  677.  
  678. return newPicture;
  679. }
  680.  
  681. private static boolean setChromakeySize()
  682. {
  683. Picture bg1 = Picture.loadPicture("Creek.bmp");
  684. Picture bg2 = Picture.loadPicture("Colleen.bmp");
  685. int goalWidth = Math.min(bg1.getWidth(), bg2.getWidth() );
  686. int goalHeight = Math.min(bg1.getHeight(), bg2.getHeight() );
  687.  
  688. Picture finalPic = bg2.chromaKey(1, 2, bg1, 30); //The only argument that really matters here is the third one: what the second picture is.
  689.  
  690. boolean widthCorrect = finalPic.getWidth() == goalWidth;
  691. boolean heightCorrect = finalPic.getHeight() == goalHeight;
  692.  
  693. return widthCorrect && heightCorrect;
  694.  
  695. }
  696.  
  697.  
  698.  
  699. //////////////////////////////// Level 2 //////////////////////////////////
  700.  
  701. /**
  702. * Rotates this Picture by the integer multiple of 90 degrees provided.
  703. * If the number of rotations provided is positive, then the picture
  704. * is rotated clockwise; else, the picture is rotated counterclockwise.
  705. * Multiples of four rotations (including zero) correspond to no
  706. * rotation at all.
  707. *
  708. * @param rotations The number of 90-degree rotations to rotate this
  709. * image by.
  710. *
  711. * @return A new Picture that is the rotated version of this Picture.
  712. */
  713. public Picture rotate(int rotations) {
  714.  
  715. int newWidth;
  716. int newHeight;
  717.  
  718. //Get the dimensions of the new picture.
  719. if( rotations % 2 == 0 ) //The length and width do not change.
  720. {
  721. newWidth = this.getWidth();
  722. newHeight = this.getHeight();
  723. }else //The length and width are exchanged.
  724. {
  725. newWidth = this.getHeight();
  726. newHeight = this.getWidth();
  727. }
  728.  
  729. Picture newPicture = new Picture( newWidth , newHeight );
  730.  
  731. //Move every pixel.
  732. for( int x = 0 ; x < newPicture.getWidth() ; x++ )
  733. {
  734. for(int y = 0 ; y < newPicture.getHeight() ; y++ )
  735. {
  736. newPicture.rotatePixel( x , y , this, rotations );
  737. }
  738. }
  739.  
  740. return newPicture;
  741.  
  742. }
  743.  
  744. /**
  745. * Helper method for Rotate(). Updates the pixel at (x,y) with color and
  746. * transparency information from the correct pixel in fromPicture according
  747. * to number of 90-degree rotations specified.
  748. *
  749. * @param x The x-coordinate of the pixel being updated.
  750. * @param y The y-coordinate of the pixel being updated.
  751. * @param fromPicture: the from which to get the corresponding pixel information.
  752. * @param rotations: The number of 90-degree rotations to rotate this
  753. * image by.
  754. */
  755.  
  756. private void rotatePixel( int x , int y , Picture fromPicture, int rotations) {
  757. int fromX = x;
  758. int fromY = y;
  759.  
  760. rotations %= 4;
  761. switch (rotations)
  762. {
  763. //No rotation is done.
  764. case 0:
  765. break;
  766.  
  767. // Rotatate by +90deg = rotate by -270deg.
  768. case 1:
  769. case -3:
  770. fromX = y;
  771. fromY = fromPicture.getHeight() - x - 1;
  772. break;
  773.  
  774. // Rotatate by +180deg = rotate by -180deg.
  775. case 2:
  776. case -2:
  777. fromX = fromPicture.getWidth() - x - 1;
  778. fromY = fromPicture.getHeight() - y - 1;
  779. break;
  780.  
  781. // Rotatate by +270deg = rotate by -90deg.
  782. case 3:
  783. case -1:
  784. fromX = fromPicture.getWidth() - y - 1;
  785. fromY = x;
  786. break;
  787.  
  788. //No rotation is done.
  789. default:
  790. break;
  791. }
  792. Pixel fromPixel = fromPicture.getPixel( fromX, fromY );
  793.  
  794. //Get the color and transparancy information from Pixel.
  795. int newAlpha = fromPixel.getAlpha();
  796. int newRed = fromPixel.getRed();
  797. int newGreen = fromPixel.getGreen();
  798. int newBlue = fromPixel.getBlue();
  799.  
  800. //Update the color and transparency of the pixel at (x,y) .
  801. this.getPixel( x , y ).updatePicture(newAlpha,newRed , newGreen, newBlue);
  802.  
  803. }
  804.  
  805. /**
  806. * Test method for rotatePixel. This method is called by
  807. * the JUnit file through the public method Picture.helpersWork().
  808. */
  809. private static boolean rotatePixelWorks()
  810. {
  811.  
  812. // Test rotation by +90.
  813. Picture bg = Picture.loadPicture("Creek.bmp");
  814. int xOld = 43;
  815. int yOld = 23;
  816. Pixel focalPixel = bg.getPixel( xOld , yOld );
  817. int xNew = Math.pow( xOld , yOld)*Math.cos( Math.PI );
  818. int yNew = Math.pow( xOld , yOld)*Math.sin( Math.PI );
  819. int originalRed = focalPixel.getRed();
  820. int originalGreen = focalPixel.getGreen();
  821. int originalBlue = focalPixel.getBlue();
  822. int originalAlpha = focalPixel.getAlpha();
  823. bg.setPixelToLighten(10, 10 , 30);
  824. Pixel newPixel = bg.getPixel(10, 10 );
  825. boolean redCorrect = newPixel.getRed() == originalRed + 30;
  826. boolean greenCorrect = newPixel.getGreen() == originalGreen + 30;
  827. boolean blueCorrect = newPixel.getBlue() == originalBlue + 30;
  828. boolean alphaCorrect = newPixel.getAlpha() == originalAlpha;
  829.  
  830. if( ! (redCorrect && greenCorrect && blueCorrect && alphaCorrect) )
  831. {
  832. return false;
  833. }
  834.  
  835. //Test the end cases.
  836. bg = Picture.loadPicture("Creek.bmp");
  837. focalPixel = bg.getPixel( bg.getWidth() -1 , bg.getHeight() -1 );
  838. originalRed = focalPixel.getRed();
  839. originalGreen = focalPixel.getGreen();
  840. originalBlue = focalPixel.getBlue();
  841. originalAlpha = focalPixel.getAlpha();
  842. bg.setPixelToLighten( bg.getWidth() -1 , bg.getHeight() -1, 30);
  843. newPixel = bg.getPixel(bg.getWidth() -1 , bg.getHeight() -1 );
  844. redCorrect = newPixel.getRed() == originalRed + 30;
  845. greenCorrect = newPixel.getGreen() == originalGreen + 30;
  846. blueCorrect = newPixel.getBlue() == originalBlue + 30;
  847. alphaCorrect = newPixel.getAlpha() == originalAlpha;
  848.  
  849. if( ! (redCorrect && greenCorrect && blueCorrect && alphaCorrect) )
  850. {
  851. return false;
  852. }
  853.  
  854.  
  855. //Test the near-white pixels.
  856. bg = Picture.loadPicture("colleen.bmp");
  857. focalPixel = bg.getPixel( 40 , 10 );
  858. originalRed = focalPixel.getRed();
  859. originalGreen = focalPixel.getGreen();
  860. originalBlue = focalPixel.getBlue();
  861. originalAlpha = focalPixel.getAlpha();
  862. bg.setPixelToLighten( 40 , 10 , 30);
  863. redCorrect = 255 == originalRed;
  864. greenCorrect = 255 == originalGreen;
  865. blueCorrect = 255 == originalBlue;
  866. alphaCorrect = focalPixel.getAlpha() == originalAlpha;
  867. if( ! (redCorrect && greenCorrect && blueCorrect && alphaCorrect) )
  868. {
  869. return true;
  870. }
  871.  
  872. return true;
  873. }
  874.  
  875.  
  876. /**
  877. * Flips this Picture about the given axis. The axis can be one of
  878. * four static integer constants:
  879. *
  880. * (a) Picture.HORIZONTAL: The picture should be flipped about
  881. * a horizontal axis passing through the center of the picture.
  882. * (b) Picture.VERTICAL: The picture should be flipped about
  883. * a vertical axis passing through the center of the picture.
  884. * (c) Picture.FORWARD_DIAGONAL: The picture should be flipped about
  885. * an axis that passes through the north-east and south-west
  886. * corners of the picture.
  887. * (d) Picture.BACKWARD_DIAGONAL: The picture should be flipped about
  888. * an axis that passes through the north-west and south-east
  889. * corners of the picture.
  890. *
  891. * @param axis Axis about which to flip the Picture provided.
  892. *
  893. * @return A new Picture flipped about the axis provided.
  894. */
  895. public Picture flip(int axis) {
  896.  
  897. int newWidth = 0;
  898. int newHeight = 0;;
  899.  
  900. //Calculate the dimensions to fit the new picture.
  901. if( axis == VERTICAL || axis == HORIZONTAL )
  902. {
  903. //The Height and width dimensions stay the same
  904. newWidth = this.getWidth();
  905. newHeight = this.getHeight();
  906. }else if( axis == BACKWARD_DIAGONAL || axis == FORWARD_DIAGONAL )
  907. {
  908. //The Height and Width dimensions are exchanged.
  909. newWidth = this.getHeight();
  910. newHeight = this.getWidth();
  911. }
  912.  
  913. Picture newPicture = new Picture( newWidth , newHeight );
  914.  
  915. //Perform a transformation on each pixel.
  916. for( int x = 0 ; x < newPicture.getWidth() ; x++ )
  917. {
  918. for(int y = 0 ; y < newPicture.getHeight() ; y++ )
  919. {
  920. newPicture.flipPixel( x , y , this, axis );
  921. }
  922. }
  923. return newPicture;
  924. }
  925. /**
  926. * Helper method for Flip(). Updates the pixel at (x,y) with color and
  927. * transparency information from the correct pixel in fromPicture according
  928. * to axis. Where axis is an integer Representation of the axis of flip
  929. * (Horizontal , vertical, forward_Diagonal or backward_Diagonal ).
  930. *
  931. * @param x The x-coordinate of the pixel being updated.
  932. * @param y The y-coordinate of the pixel being updated.
  933. * @param fromPicture: the from which to get the corresponding pixel information.
  934. * @param axis: the axis of reflection, can be Horizontal , vertical or diagonal.
  935. */
  936. private void flipPixel( int x , int y , Picture fromPicture, int axis) {
  937.  
  938. int fromX = x;
  939. int fromY = y;
  940.  
  941. switch (axis)
  942. {
  943. case HORIZONTAL: //Flip along a horizontal axis.
  944. fromY = this.getHeight() - y - 1;
  945. break;
  946.  
  947. case VERTICAL: //Flip along a vertical axis.
  948. fromX = this.getWidth() - x - 1;
  949.  
  950. break;
  951.  
  952. case BACKWARD_DIAGONAL: //Flip along a diagonal that passes through the
  953. //north-east and south-west corners of the picture
  954. fromX = y;
  955. fromY = x;
  956. break;
  957.  
  958. case FORWARD_DIAGONAL: //Flip along a diagonal that passes through the
  959. //north-west and south-East corners of the picture
  960. fromX = this.getHeight() - y - 1;
  961. fromY = this.getWidth() - x - 1;
  962. break;
  963.  
  964. default: //The current pixel does not change.
  965. fromX = x;
  966. fromY = y;
  967.  
  968. }
  969. Pixel fromPixel = fromPicture.getPixel( fromX, fromY );
  970.  
  971. //Get the color and transparancy information from Pixel.
  972. int newAlpha = fromPixel.getAlpha();
  973. int newRed = fromPixel.getRed();
  974. int newGreen = fromPixel.getGreen();
  975. int newBlue = fromPixel.getBlue();
  976.  
  977. //Update the color and transparency of the pixel at (x,y) .
  978. this.getPixel( x , y ).updatePicture(newAlpha,newRed , newGreen, newBlue);
  979.  
  980. }
  981.  
  982. /**
  983. * @param threshold
  984. * Threshold to use to determine the presence of edges.
  985. *
  986. * @return A new Picture that contains only the edges of this Picture. For
  987. * each pixel, we separately consider the color distance between
  988. * that pixel and the one pixel to its left, and also the color
  989. * distance between that pixel and the one pixel to the north, where
  990. * applicable. As an example, we would compare the pixel at (3, 4)
  991. * with the pixels at (3, 3) and the pixels at (2, 4). Also, since
  992. * the pixel at (0, 4) only has a pixel to its north, we would only
  993. * compare it to that pixel. If either of the color distances is
  994. * larger than the provided color threshold, it is set to black
  995. * (with an alpha of 255); otherwise, the pixel is set to white
  996. * (with an alpha of 255). The pixel at (0, 0) will always be set to
  997. * white.
  998. */
  999. public Picture showEdges(int threshold) {
  1000. Picture newPicture = new Picture(this);
  1001. threshold = threshold + 1;
  1002. int pictureHeight = this.getHeight() - 1;
  1003. int pictureWidth = this.getWidth() - 1;
  1004.  
  1005.  
  1006. for (int x = pictureWidth; x > 0; x--){
  1007. for (int y = pictureHeight; y > 0; y--){
  1008. Color upPixelColor = this.getPixel(x, y-1).getColor();
  1009. Color leftPixelColor = this.getPixel(x-1, y).getColor();
  1010. if( (this.getPixel(x, y).colorDistance(upPixelColor) < threshold) && (this.getPixel(x, y).colorDistance(leftPixelColor) < threshold) ){
  1011. newPicture.getPixel( x , y ).updatePicture(255,255 , 255, 255);
  1012. }
  1013. else{
  1014. newPicture.getPixel( x , y ).updatePicture(255, 0 , 0, 0);
  1015. }
  1016. }
  1017. if(this.getPixel(x, 0).colorDistance( this.getPixel(x-1, 0).getColor()) < threshold){
  1018. newPicture.getPixel( x , 0).updatePicture(255,255 , 255, 255);
  1019. }
  1020. else{
  1021. newPicture.getPixel( x , 0).updatePicture(255, 0 , 0, 0);
  1022. }
  1023. }
  1024.  
  1025.  
  1026. for(int y = pictureHeight; y > 0; y--){
  1027. if(this.getPixel(0, y).colorDistance( this.getPixel(0, y-1).getColor()) < threshold){
  1028. newPicture.getPixel( 0 , y ).updatePicture(255,255 , 255, 255);
  1029. }
  1030. else{
  1031. newPicture.getPixel( 0 , y ).updatePicture(255, 0 , 0, 0);
  1032. }
  1033. }
  1034.  
  1035. newPicture.getPixel( 0 , 0 ).updatePicture(255, 255, 255, 255);
  1036.  
  1037.  
  1038. return newPicture;
  1039. }
  1040.  
  1041. //////////////////////////////// Level 3 //////////////////////////////////
  1042.  
  1043. /**
  1044. * @return A new Picture that is the ASCII art version of this Picture. To
  1045. * implement this, the Picture is first converted into its grayscale
  1046. * equivalent. Then, starting from the top left, the average color
  1047. * of every chunk of 10 pixels wide by 20 pixels tall is computed.
  1048. * Based on the average value obtained, this chunk will be replaced
  1049. * by the corresponding ASCII character specified by the table
  1050. * below.
  1051. *
  1052. * The ASCII characters to be used are available as Picture objects,
  1053. * also of size 10 pixels by 20 pixels. The following characters
  1054. * should be used, depending on the average value obtained:
  1055. *
  1056. * 0 to 18: # (Picture.BMP_POUND)
  1057. * 19 to 37: @ (Picture.BMP_AT)
  1058. * 38 to 56: & (Picture.BMP_AMPERSAND)
  1059. * 57 to 75: $ (Picture.BMP_DOLLAR)
  1060. * 76 to 94: % (Picture.BMP_PERCENT)
  1061. * 95 to 113: | (Picture.BMP_BAR)
  1062. * 114 to 132: ! (Picture.BMP_EXCLAMATION)
  1063. * 133 to 151: ; (Picture.BMP_SEMICOLON)
  1064. * 152 to 170: : (Picture.BMP_COLON)
  1065. * 171 to 189: ' (Picture.BMP_APOSTROPHE)
  1066. * 190 to 208: ` (Picture.BMP_GRAVE)
  1067. * 209 to 227: . (Picture.BMP_DOT)
  1068. * 228 to 255: (Picture.BMP_SPACE)
  1069. *
  1070. * We provide a getAsciiPic method to obtain the Picture object
  1071. * corresponding to a character, given any of the static Strings
  1072. * mentioned above.
  1073. *
  1074. * Note that the resultant Picture should be the exact same size
  1075. * as the original Picture; this might involve characters being
  1076. * partially copied to the final Picture.
  1077. */
  1078. public Picture convertToAscii() {
  1079.  
  1080. Picture newPicture = new Picture( this );
  1081. // Default chunk size
  1082. int chunkSizeX = 10;
  1083. int chunkSizeY = 20;
  1084.  
  1085. //Convert to grayscale
  1086. newPicture = newPicture.grayscale();
  1087.  
  1088. //Convert chunks to ascii.
  1089. for( int x = 0 ; x < newPicture.getWidth() ; x+= chunkSizeX )
  1090. {
  1091. for(int y = 0 ; y < newPicture.getHeight() ; y+= chunkSizeY )
  1092. {
  1093. newPicture.convertChunkToAscii( x , y , chunkSizeX ,chunkSizeY );
  1094. }
  1095. }
  1096.  
  1097. return newPicture;
  1098. }
  1099.  
  1100. /**
  1101. * Helper method for convertToAscii(). Updates the pixel at (x,y) with color and
  1102. * transparency information from the correct pixel in fromPicture according
  1103. * to axis. Where axis is an integer Representation of the axis of flip
  1104. * (Horizontal , vertical, forward_Diagonal or backward_Diagonal ).
  1105. *
  1106. * @param x The x-coordinate of the pixel being updated.
  1107. * @param y The y-coordinate of the pixel being updated.
  1108. * @param fromPicture: the from which to get the corresponding pixel information.
  1109. * @param axis: the axis of reflection, can be Horizontal , vertical or diagonal.
  1110. */
  1111. private void convertChunkToAscii( int x , int y , int chunkSizeX, int chunkSizeY) {
  1112.  
  1113. int totalAverage = 0;
  1114. int numPixels = 0;
  1115.  
  1116. //Calculate the average color for the chunk.
  1117. for(int Xsq = x ; Xsq < Math.min( x + chunkSizeX , this.getWidth() ) ; Xsq++ )
  1118. {
  1119. for(int Ysq = y ; Ysq < Math.min( y + chunkSizeY , this.getHeight() ) ; Ysq++ )
  1120. {
  1121.  
  1122. Pixel fromPixel = this.getPixel( Xsq, Ysq );
  1123. totalAverage += fromPixel.getRed();
  1124.  
  1125. numPixels++;
  1126.  
  1127. }
  1128. }
  1129.  
  1130. int chunkAverageColor = totalAverage/numPixels;
  1131.  
  1132. //Get the Ascii
  1133. Picture asciiPic = Picture.getAsciiPic(chunkAverageColor);
  1134.  
  1135. //Replace a chunk of picture with an ascii picture.
  1136. for(int Xsq = x ; Xsq < Math.min( x + chunkSizeX , this.getWidth() ) ; Xsq++ )
  1137. {
  1138. for(int Ysq = y ; Ysq < Math.min( y + chunkSizeY , this.getHeight() ); Ysq++ )
  1139. {
  1140.  
  1141. Pixel fromPixel = asciiPic.getPixel( Xsq % 10 , Ysq % 20);
  1142. int newAlpha = fromPixel.getAlpha();
  1143. int newRed = fromPixel.getRed();
  1144. int newGreen = fromPixel.getGreen();
  1145. int newBlue = fromPixel.getBlue();
  1146.  
  1147. //Update the color and transparency of the pixel at (x,y) .
  1148. this.getPixel( Xsq , Ysq ).updatePicture( newAlpha, newRed , newGreen, newBlue);
  1149.  
  1150. }
  1151. }
  1152.  
  1153. }
  1154.  
  1155. /**
  1156. * Test method for rotatePixel. This method is called by
  1157. * the JUnit file through the public method Picture.helpersWork().
  1158. */
  1159. private static boolean convertChunkToAsciiWorks()
  1160. {
  1161. // Test the general Case:
  1162. // The chunck is somewhere in the middle.
  1163. int total = 0;
  1164. Picture mickey = Picture.loadPicture("mickey.bmp");
  1165.  
  1166. //Get the average of the colors.
  1167. for( int i = 100 ; i < 100 + 10 ; i++ )
  1168. {
  1169. for( int j = 80 ; j < 80 + 20 ; j++ )
  1170. {
  1171. total += mickey.getPixel(i, j).getAverage();
  1172. }
  1173. }
  1174.  
  1175. int ave = total / 200;
  1176. Picture asciiPic = Picture.getAsciiPic(ave);
  1177. mickey.convertChunkToAscii( 100 , 80 , 10 , 20 );
  1178.  
  1179. asciiPic.show();
  1180.  
  1181. for( int i = 100 ; i < 100 + 10 ; i++ )
  1182. {
  1183. for( int j = 80 ; j < 80 + 20 ; j++ )
  1184. {
  1185. Pixel currentPixel = mickey.getPixel(i, j);
  1186. if( currentPixel.getColor().equals( asciiPic.getPixel(i - 100, j - 80) ) )
  1187. {
  1188. continue;
  1189. }else
  1190. {
  1191. return false;
  1192. }
  1193. }
  1194. }
  1195. //Test when chunk is at the edge;
  1196.  
  1197. return true;
  1198.  
  1199. }
  1200.  
  1201.  
  1202.  
  1203. /**
  1204. * Blurs this Picture. To achieve this, the algorithm takes a pixel, and
  1205. * sets it to the average value of all the pixels in a square of side (2 *
  1206. * blurThreshold) + 1, centered at that pixel. For example, if blurThreshold
  1207. * is 2, and the current pixel is at location (8, 10), then we will consider
  1208. * the pixels in a 5 by 5 square that has corners at pixels (6, 8), (10, 8),
  1209. * (6, 12), and (10, 12). If there are not enough pixels available -- if the
  1210. * pixel is at the edge, for example, or if the threshold is larger than the
  1211. * image -- then the missing pixels are ignored, and the average is taken
  1212. * only of the pixels available.
  1213. *
  1214. * The red, blue, green and alpha values should each be averaged separately.
  1215. *
  1216. * @param blurThreshold
  1217. * Size of the blurring square around the pixel.
  1218. *
  1219. * @return A new Picture that is the blurred version of this Picture, using
  1220. * a blurring square of size (2 * threshold) + 1.
  1221. */
  1222. public Picture blur(int blurThreshold ) {
  1223.  
  1224. Picture newPicture = new Picture( this );
  1225.  
  1226. //Blur all pixels.
  1227. for( int x = 0 ; x < newPicture.getWidth() ; x++ )
  1228. {
  1229. for(int y = 0 ; y < newPicture.getHeight() ; y++ )
  1230. {
  1231. newPicture.blurPixel( x , y , this, blurThreshold );
  1232. }
  1233. }
  1234.  
  1235. return newPicture;
  1236. }
  1237.  
  1238. /**
  1239. * Helper method for Blur(). Updates the pixel at (x,y) with average color and
  1240. * transparency information of all the pixels in a square of side (2 *
  1241. * blurThreshold) + 1 around it.
  1242. *
  1243. * @param x The x-coordinate of the pixel being blurred.
  1244. * @param y The y-coordinate of the pixel being blurred.
  1245. * @param fromPicture: the from which to get the corresponding pixel information.
  1246. * @param threshold: Size of the blurring square around the pixel.
  1247. */
  1248. private void blurPixel( int x , int y , Picture fromPicture, int blurThreshold ) {
  1249.  
  1250. int totalAlpha = 0;
  1251. int totalRed = 0;
  1252. int totalGreen = 0;
  1253. int totalBlue = 0;
  1254. int numPixels = 0;
  1255.  
  1256. //for the square side (2T+1), Compute average of the colors.
  1257.  
  1258. for(int Xsq = x - blurThreshold ; Xsq <= x + blurThreshold ; Xsq++ )
  1259. {
  1260. for(int Ysq = y - blurThreshold ; Ysq <= y + blurThreshold ; Ysq++ )
  1261. {
  1262. // Skip those unavailable pixels.
  1263. if( Xsq < 0 || Xsq >= this.getWidth() || Ysq < 0 || Ysq >= this.getHeight() )
  1264. {
  1265. continue;
  1266. }else
  1267. {
  1268. Pixel fromPixel = fromPicture.getPixel( Xsq, Ysq );
  1269.  
  1270. //Get the color and transparancy information from the Pixel.
  1271. totalAlpha += fromPixel.getAlpha();
  1272. totalRed += fromPixel.getRed();
  1273. totalGreen += fromPixel.getGreen();
  1274. totalBlue += fromPixel.getBlue();
  1275.  
  1276. numPixels++;
  1277. }
  1278. }
  1279. }
  1280.  
  1281. //Get the Average color and transparancy information from Pixel.
  1282. int newAlpha = totalAlpha/numPixels;
  1283. int newRed = totalRed/numPixels;
  1284. int newGreen = totalGreen/numPixels;
  1285. int newBlue = totalBlue/numPixels;
  1286.  
  1287. //Update the color and transparency of the pixel at (x,y) .
  1288. this.getPixel( x , y ).updatePicture(newAlpha,newRed , newGreen, newBlue);
  1289.  
  1290. }
  1291.  
  1292.  
  1293. /**
  1294. * @param x x-coordinate of the pixel currently selected.
  1295. * @param y y-coordinate of the pixel currently selected.
  1296. * @param threshold Threshold within which to delete pixels.
  1297. * @param newColor New color to color pixels.
  1298. *
  1299. * @return A new Picture where all the pixels connected to the currently
  1300. * selected pixel, and which differ from the selected pixel within the
  1301. * provided threshold (in terms of color distance), are colored with
  1302. * the new color provided.
  1303. */
  1304. public Picture paintBucket(int x, int y, int threshold, Color newColor) {
  1305.  
  1306. Pixel refPixel = this.getPixel(x, y);
  1307. Picture newPicture = new Picture( this );
  1308. Stack toStartVisitAt = new Stack();
  1309. toStartVisitAt.push( new Point(x , y) ); //Stores Pixels yet to be processed.
  1310.  
  1311. while( !toStartVisitAt.empty() ){ //While there are still pixels to be processed.
  1312.  
  1313. Point nextPoint = (Point)toStartVisitAt.pop();
  1314. x = (int)nextPoint.getX();
  1315. y = (int)nextPoint.getY();
  1316. newPicture.getPixel(x, y).setColor(newColor); //Fill the pixel.
  1317.  
  1318. //Store EAST Pixel
  1319. if( x + 1 < newPicture.getWidth() && refPixel.colorDistance( newPicture.getPixel(x + 1 , y).getColor() ) <= threshold )
  1320. {
  1321. toStartVisitAt.push( new Point( x + 1 , y ) );
  1322. }
  1323. //Store NORTH Pixel
  1324. if( y + 1 < newPicture.getHeight() && refPixel.colorDistance( newPicture.getPixel(x , y + 1 ).getColor() ) <= threshold )
  1325. {
  1326. toStartVisitAt.push( new Point( x , y + 1 ) );
  1327. }
  1328. //Store WEST Pixel
  1329. if( x - 1 >= 0 && refPixel.colorDistance( newPicture.getPixel(x - 1 , y).getColor() ) <= threshold )
  1330. {
  1331. toStartVisitAt.push( new Point( x - 1 , y ) );
  1332. }
  1333. //Store SOUTH Pixel
  1334. if( y - 1 >= 0 && refPixel.colorDistance( newPicture.getPixel(x , y -1).getColor() ) <= threshold )
  1335. {
  1336. toStartVisitAt.push( new Point( x , y - 1) );
  1337. }
  1338. //Store NORTH-East Pixel
  1339. if( x + 1 < newPicture.getWidth() && y + 1 < newPicture.getHeight()
  1340. && refPixel.colorDistance( newPicture.getPixel(x + 1 , y + 1).getColor() ) < threshold )
  1341. {
  1342. toStartVisitAt.push( new Point( x + 1 , y + 1) );
  1343. }
  1344. //Store South-West Pixel
  1345. if( x - 1 >= 0 && y - 1 >= 0
  1346. && refPixel.colorDistance( newPicture.getPixel(x -1, y - 1 ).getColor() ) < threshold )
  1347. {
  1348. toStartVisitAt.push( new Point( x - 1, y - 1 ) );
  1349. }
  1350. //Store North-West Pixel
  1351. if( x - 1 >= 0 && y + 1 < newPicture.getHeight()
  1352. && refPixel.colorDistance( newPicture.getPixel(x - 1 , y + 1).getColor() ) < threshold )
  1353. {
  1354. toStartVisitAt.push( new Point( x - 1 , y + 1 ) );
  1355. }
  1356. //Store South-East Pixel
  1357. if( x + 1 < newPicture.getWidth() && y - 1 >= 0
  1358. && refPixel.colorDistance( newPicture.getPixel(x + 1 , y -1).getColor() ) < threshold )
  1359. {
  1360. toStartVisitAt.push( new Point( x +1 , y - 1) );
  1361. }
  1362. }
  1363. return newPicture;
  1364. }
  1365.  
  1366. ///////////////////////// PROJECT 1 ENDS HERE /////////////////////////////
  1367.  
  1368. public boolean equals(Object obj) {
  1369. if (!(obj instanceof Picture)) {
  1370. return false;
  1371. }
  1372.  
  1373. Picture p = (Picture) obj;
  1374. // Check that the two pictures have the same dimensions.
  1375. if ((p.getWidth() != this.getWidth()) ||
  1376. (p.getHeight() != this.getHeight())) {
  1377. return false;
  1378. }
  1379.  
  1380. // Check each pixel.
  1381. for (int x = 0; x < this.getWidth(); x++) {
  1382. for(int y = 0; y < this.getHeight(); y++) {
  1383. if (!this.getPixel(x, y).equals(p.getPixel(x, y))) {
  1384. return false;
  1385. }
  1386. }
  1387. }
  1388.  
  1389. return true;
  1390. }
  1391.  
  1392. /**
  1393. * Helper method for loading a picture in the current directory.
  1394. */
  1395. protected static Picture loadPicture(String pictureName) {
  1396. URL url = Picture.class.getResource(pictureName);
  1397. return new Picture(url.getFile().replaceAll("%20", " "));
  1398. }
  1399.  
  1400. /**
  1401. * Helper method for loading the pictures corresponding to each character
  1402. * for the ASCII art conversion.
  1403. */
  1404. private static Picture getAsciiPic(int grayValue) {
  1405. int asciiIndex = (int) grayValue / 19;
  1406.  
  1407. if (BMP_AMPERSAND == null) {
  1408. BMP_AMPERSAND = Picture.loadPicture("ampersand.bmp");
  1409. BMP_APOSTROPHE = Picture.loadPicture("apostrophe.bmp");
  1410. BMP_AT = Picture.loadPicture("at.bmp");
  1411. BMP_BAR = Picture.loadPicture("bar.bmp");
  1412. BMP_COLON = Picture.loadPicture("colon.bmp");
  1413. BMP_DOLLAR = Picture.loadPicture("dollar.bmp");
  1414. BMP_DOT = Picture.loadPicture("dot.bmp");
  1415. BMP_EXCLAMATION = Picture.loadPicture("exclamation.bmp");
  1416. BMP_GRAVE = Picture.loadPicture("grave.bmp");
  1417. BMP_HASH = Picture.loadPicture("hash.bmp");
  1418. BMP_PERCENT = Picture.loadPicture("percent.bmp");
  1419. BMP_SEMICOLON = Picture.loadPicture("semicolon.bmp");
  1420. BMP_SPACE = Picture.loadPicture("space.bmp");
  1421. }
  1422.  
  1423. switch(asciiIndex) {
  1424. case 0:
  1425. return Picture.BMP_HASH;
  1426. case 1:
  1427. return Picture.BMP_AT;
  1428. case 2:
  1429. return Picture.BMP_AMPERSAND;
  1430. case 3:
  1431. return Picture.BMP_DOLLAR;
  1432. case 4:
  1433. return Picture.BMP_PERCENT;
  1434. case 5:
  1435. return Picture.BMP_BAR;
  1436. case 6:
  1437. return Picture.BMP_EXCLAMATION;
  1438. case 7:
  1439. return Picture.BMP_SEMICOLON;
  1440. case 8:
  1441. return Picture.BMP_COLON;
  1442. case 9:
  1443. return Picture.BMP_APOSTROPHE;
  1444. case 10:
  1445. return Picture.BMP_GRAVE;
  1446. case 11:
  1447. return Picture.BMP_DOT;
  1448. default:
  1449. return Picture.BMP_SPACE;
  1450. }
  1451. }
  1452.  
  1453. public static void main(String[] args) {
  1454. Picture initialPicture = new Picture(
  1455. FileChooser.pickAFile(FileChooser.OPEN));
  1456. initialPicture.explore();
  1457. }
  1458.  
  1459. } // End of Picture class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement