1 /*
   2  * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 
  32 /*
  33  * This source code is provided to illustrate the usage of a given feature
  34  * or technique and has been deliberately simplified. Additional steps
  35  * required for a production-quality application, such as security checks,
  36  * input validation and proper error handling, might not be present in
  37  * this sample code.
  38  */
  39 package stream.parallel;
  40 
  41 import java.awt.image.BufferedImage;
  42 import static java.awt.image.BufferedImage.TYPE_INT_RGB;
  43 import java.io.File;
  44 import java.util.stream.IntStream;
  45 import javax.imageio.ImageIO;
  46 import static stream.parallel.RandomPrimeNumber.usage;
  47 
  48 /**
  49  * This demo shows parallel geometrical transformations of images.The operations
  50  * of image include rotation, shift, scale, inversion.
  51  *
  52  * @author tyan
  53  */
  54 public class ImageTransform {
  55 
  56     public static void main(String[] args) {
  57         try {
  58             if (args.length < 5) {
  59                 usage();
  60                 return;
  61             }
  62             int argPos = 0;
  63             int oprand = 0;
  64             String command = "";
  65             String inputFile = "", outputFile = "";
  66             boolean yes = true;
  67             while (argPos < args.length) {
  68                 switch (args[argPos++]) {
  69                     case "-ls":
  70                     case "-rs":
  71                         yes = args[argPos - 1].equals("-ls");
  72                         oprand = Integer.parseInt(args[argPos++]);
  73                         command = "shift";
  74                         break;
  75                     case "-cl":
  76                     case "-ccl":
  77                         yes = args[argPos - 1].equals("-cl");
  78                         oprand = Integer.parseInt(args[argPos++]);
  79                         command = "rotate";
  80                         break;
  81                     case "-zo":
  82                         oprand = Integer.parseInt(args[argPos++]);
  83                         command = "zoom";
  84                         break;
  85                     case "-iv":
  86                         command = "invert";
  87                         break;
  88                     case "-i":
  89                         inputFile = args[argPos++];
  90                         break;
  91                     case "-o":
  92                         outputFile = args[argPos++];
  93                         break;
  94                     default:
  95                         usage();
  96                         return;
  97                 }
  98             }
  99             if (inputFile.equals("") || outputFile.equals("")) {
 100                 throw new Exception("Input/Output file is needed");
 101             }
 102             File inFile = new File(inputFile);
 103             File outFile = new File(outputFile);
 104             BufferedImage in = ImageIO.read(inFile);
 105             int newWidth = in.getWidth();
 106             int newHeight = in.getHeight();
 107             if (command.equals("zoom")) {
 108                 double magnitude = oprand / 100.0;
 109                 newWidth = (int) (newWidth * magnitude);
 110                 newHeight = (int) (newHeight * magnitude);
 111             } else if (command.equals("rorate")) {
 112                 int max = Math.max(newWidth, newWidth);
 113                 newWidth = max;
 114                 newHeight = max;
 115             }
 116             BufferedImage out = new BufferedImage(newWidth, newHeight, TYPE_INT_RGB);
 117             if(!command.equals("invert") && oprand <= 0) {
 118                 throw new Exception("Value must be a positive number");
 119             }
 120             switch (command) {
 121                 case "shift":
 122                     shift(in, out, yes, oprand);
 123                     break;
 124                 case "rotate":
 125                     rotate(in, out, yes, oprand);
 126                     break;
 127                 case "zoom":
 128                     zoom(in, out, oprand / 100.0);
 129                     break;
 130                 case "invert":
 131                     invert(in, out);
 132                     break;
 133             }
 134             ImageIO.write(out, "jpg", outFile);
 135         } catch (Exception ex) {
 136             usage();
 137         }
 138     }
 139 
 140     /**
 141      * Rotate an image as given angle.
 142      * @param in        input image
 143      * @param out       output image
 144      * @param clockwise true clockwise
 145      *                  false counter-clockwise
 146      * @param angle     angle that image will rotate
 147      */
 148     public static void rotate(BufferedImage in, BufferedImage out,
 149             boolean clockwise, int angle) {
 150         int width = (int) in.getWidth();
 151         int height = (int) in.getHeight();
 152         int centerX = width / 2;
 153         int centerY = height / 2;
 154         double rotateV = (clockwise ? 360 - angle : angle) / 180.0 * Math.PI;
 155         IntStream.range(0, width).parallel().forEach(x -> {
 156             IntStream.range(0, height).parallel().forEach(y -> {
 157                 int newX = (int) (centerX + (x - centerX) * Math.cos(rotateV)
 158                         + (y - centerY) * Math.sin(rotateV));
 159                 int newY = (int) (centerY + (x - centerX) * Math.sin(rotateV)
 160                         + (y - centerY) * Math.cos(rotateV));
 161                 if (newX >= 0 && newX < width && newY >= 0 && newY < height) {
 162                     out.setRGB(newX, newY, in.getRGB(x, y));
 163                 }
 164             });
 165         });
 166     }
 167 
 168     /**
 169      * Shift an image horizontally.
 170      * @param in        input image
 171      * @param out       output image
 172      * @param left      true left shift
 173      *                  false right shift
 174      * @param length    size that image shifts
 175      */
 176     public static void shift(BufferedImage in, BufferedImage out,
 177             boolean left, int length) {
 178         int width = (int) out.getWidth();
 179         int height = (int) out.getHeight();
 180         int leftShift = left ? length % width : width - length % width;
 181         IntStream.range(0, width).parallel().forEach(x -> {
 182             IntStream.range(0, height).parallel().forEach(y -> {
 183                 int newX = x >= leftShift ? x - leftShift : width + x - leftShift;
 184                 out.setRGB(newX, y, in.getRGB(x, y));
 185             });
 186         });
 187     }
 188 
 189     /**
 190      * Zoom in/out an image.
 191      * @param in         input image
 192      * @param out        output image
 193      * @param magnitude  scale of original image.
 194      */
 195     public static void zoom(BufferedImage in, BufferedImage out,
 196             double magnitude) {
 197         int width = (int) out.getWidth();
 198         int height = (int) out.getHeight();
 199         IntStream.range(0, width).parallel().forEach(x -> {
 200             IntStream.range(0, height).parallel().forEach(y -> {
 201                 int oldX = (int) (x / magnitude);
 202                 int oldY = (int) (y / magnitude);
 203                 if (oldX < in.getWidth() && oldY < in.getHeight()) {
 204                     out.setRGB(x, y, in.getRGB(oldX, oldY));
 205                 }
 206             });
 207         });
 208     }
 209 
 210     /**
 211      * Invert color of an image.
 212      * @param in         input image
 213      * @param out        output image
 214      */
 215     public static void invert(BufferedImage in, BufferedImage out) {
 216         int width = (int) out.getWidth();
 217         int height = (int) out.getHeight();
 218         IntStream.range(0, width).parallel().forEach(x -> {
 219             IntStream.range(0, height).parallel().forEach(y -> {
 220                 out.setRGB(x, y, in.getRGB(x, y) ^ 0xffffff);
 221             });
 222         });
 223     }
 224 
 225     /**
 226      * Usage of this program
 227      */
 228     public static void usage() {
 229         System.out.println("Usage: java ImageTransform {-rs size|-ls size|"
 230                 + "-cl angle|-ccl angle|-zo percentage|-zo precentage|-iv} "
 231                 + "-i InputFile -o OutputFile");
 232     }
 233 }