Zielony Smok - logo witryny

Niemal wszystko co pojawia się w Internecie staje się własnością publiczną. Każdy może ściągnąć stronę, czy zdjęcie i używać jak swojego. Zabezpieczenie zdjęć przed ściąganiem jest praktycznie niemożliwe, chociaż można je utrudnić przez zniechęcenie Internauty. Jednym z takich sposobów jest pokrojenie obrazka na kawałki. Zdjęcie jest widoczne jako całość, ale przy próbie ściągnięcia Internauta otrzymuje tyle fragmentów na ile je podzieliłeś. Oczywiście złożenie tych zdjęć ponownie w całość jest możliwe, ale niemal nikomu nie będzie się chciało tego robić albo nie potrafi tego zrobić, gdyż nie zna technik albo nie ma odpowiedniego narzędzia. Raczej poszuka podobnego zdjęcia gdzie indziej.

Przygotowanie

Mamy obrazek:

Kwiatek

Przygotowujemy stosowną aplikację w IntelliJ IDEA

A oto wstępny widok z klasami Java i obrazkiem do pokrojenia

Widok aplikacji

Klasy Java

ImageSlicer.java
package imageslicer;

import java.awt.image.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.*;
public class ImageSlicer {

    private static final Logger LOGGER = Logger.getLogger(ImageSlicer.class.getName());

    private ImageSlicer() {
    }

    /**
     * tworzy listę plików typu "*.jpg" w podanym katalogu
     *
     * @param dir String - katalog zawierający pliki
     * @param ext rozszerzenie z kropką np. ".jpg"
     * @return String[] - lista plików w podanym katalogu
     */
    public static String[] listFileNames(String dir, String ext) {
        File file = new File(dir);
        File[] files = null;
        String[] names = null;
        if (file.isDirectory()) {
            MultiFilter fef = new MultiFilter(file, ext);
            files = file.listFiles(fef);
        } else {
            System.out.println("Podaj nazwę katalogu z plikami");
        }
        if (files != null) {
            names = new String[files.length];
            for (int i = 0; i < files.length; i++) {
                names[i] = dir + "/" + files[i].getName();
            }
        }
        return names;
    }

    public static void slicePictureToHTMLTableLayout(String fileIn, int cols,
            int rows, String pictureDir, String htmlDir, String lastDir) {
        BufferedImage bimage = fileToBimage(fileIn);
        int pos = fileIn.lastIndexOf("/");
        String plik;
        if (pos != -1) {
            plik = fileIn.substring(pos + 1);
        } else {
            plik = fileIn;
        }
        int pos1 = plik.indexOf(".");
        String name = plik.substring(0, pos1);
        String ext1 = plik.substring(pos1 + 1);
        String ext2 = plik.substring(pos1 + 1);
        int image_w = bimage.getWidth();
        int image_h = bimage.getHeight();
        int segment_w = image_w / cols;
        int diff_w = 0;
        if (!(image_w % cols == 0)) {
            diff_w = image_w - cols * (image_w / cols);
        }
        int segment_h = image_h / rows;
        int diff_h = 0;
        if (!(image_h % rows == 0)) {
            diff_h = image_h - rows * (image_h / rows);
        }
        String ext = null;
        if (ext1.equals("jpg") || ext1.equals("JPG") || ext1.equals("JPEG")) {
            ext = "JPEG";
        } else if (ext1.equals("png") || ext1.equals("PNG")) {
            ext = "PNG";
        }
        BufferedImage[] pieces = new BufferedImage[cols * rows];
        int[] widths = new int[cols * rows];
        int[] heights = new int[cols * rows];
        int xx;
        int yy;
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                if (y == rows - 1) {
                    yy = diff_h;
                } else {
                    yy = 0;
                }
                if (x == cols - 1) {
                    xx = diff_w;
                } else {
                    xx = 0;
                }
                int i = y * cols + x;
                pieces[i] = bimage.getSubimage(segment_w * x, segment_h * y,
                        segment_w + xx, segment_h + yy);
                widths[i] = segment_w + xx;
                heights[i] = segment_h + yy;
            }
        }
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                bimageToFile(pictureDir + "/" + name + y + x + "." + ext2, ext,
                        pieces[y * cols + x]);
            }
        }
        PrintWriter pw = null;
        try {
            pw = new PrintWriter(htmlDir.concat("/").concat(name).concat(".")
                    .concat("html"));
        } catch (FileNotFoundException e) {
            LOGGER.log(Level.SEVERE, e.getMessage());
        }
        if (pw != null) {
            pw.println("<!DOCTYPE html>");
            pw.println("<html>");
            pw.println("<head>");
            pw.println("<style>");
            pw.println("   div.obrazek {");
            pw.println("      display: table;");
            pw.println("   }");
            pw.println("   div.rzad {");
            pw.println("      display: table-row;");
            pw.println("   }");
            pw.println("   p.komorka {");
            pw.println("      display: table-cell;");
            pw.println("      border: 0px;");
            pw.println("      margin: 0px;");
            pw.println("      padding: 0px;");
            pw.println("   }");
            pw.println("   img.left {");
            pw.println("      float: left;");
            pw.println("   }");
            pw.println("</style>");
            pw.println("</head>");
            pw.println("<body>");
            pw.println("   <div class=\"obrazek\">");
            for (int y = 0; y < rows; y++) {
                pw.println("      <div class=\"rzad\">");
                for (int x = 0; x < cols; x++) {
                    pw.println(
                            "         <p class=\"komorka\"><img class=\"left\" src=\""
                            + lastDir + "/" + name + y + x + "." + ext2
                            + "\"" + " width=\"" + widths[y * cols + x]
                            + "\"" + " height=\"" + heights[y * cols + x]
                            + "\"" + " /></p>");
                }
                pw.println("      </div>");
            }
            //-
            pw.println("   </div>");
            pw.println("</body>");
            pw.println("</html>");
            pw.close();
        }
    }

    public static void slicePicture(String fileIn, String outDir) {
        BufferedImage bi = fileToBimage(fileIn);
        int pos = fileIn.lastIndexOf("/");
        String plik;
        if (pos != -1) {
            plik = fileIn.substring(pos + 1);
        } else {
            plik = fileIn;
        }
        int pos1 = plik.indexOf(".");
        String name = plik.substring(0, pos1);
        String ext1 = plik.substring(pos1 + 1);
        String ext2 = plik.substring(pos1 + 1);
        int image_w = bi.getWidth();
        int seg_w1 = bi.getWidth() / 2;
        int seg_w2 = bi.getWidth() / 2;
        int image_h = bi.getHeight();
        int seg_h1 = bi.getHeight() / 2;
        int seg_h2 = bi.getHeight() / 2;
        if (!(image_w % 2 == 0)) {
            seg_w2++;
        }
        if (!(image_h % 2 == 0)) {
            seg_h2++;
        }
        String ext = null;
        if (ext1.equals("jpg") || ext1.equals("JPG") || ext1.equals("JPEG")) {
            ext = "JPEG";
        } else if (ext1.equals("png") || ext1.equals("PNG")) {
            ext = "PNG";
        }
        BufferedImage bi1 = bi.getSubimage(0, 0, seg_w1, seg_h1);
        BufferedImage bi2 = bi.getSubimage(seg_w1, 0, seg_w2, seg_h1);
        BufferedImage bi3 = bi.getSubimage(0, seg_h1, seg_w1, seg_h2);
        BufferedImage bi4 = bi.getSubimage(seg_w1, seg_h1, seg_w2, seg_h2);
        bimageToFile(outDir.concat("/").concat(name).concat("00").concat(".")
                .concat(ext2), ext, bi1);
        bimageToFile(outDir.concat("/").concat(name).concat("01").concat(".")
                .concat(ext2), ext, bi2);
        bimageToFile(outDir.concat("/").concat(name).concat("10").concat(".")
                .concat(ext2), ext, bi3);
        bimageToFile(outDir.concat("/").concat(name).concat("11").concat(".")
                .concat(ext2), ext, bi4);
    }

    //przekształca obrazek w tabelkę html, w której każdy piksel jest 
    //przekształcony w element <td> o wielkości jednego piksela 
    //i o kolorze tła będącym kolorem pixela
    public static void pictureAsHTMLTable(String fileIn, String fileOut) {
        BufferedImage bi = fileToBimage(fileIn);
        PrintWriter pw = null;
        try {
            pw = new PrintWriter(fileOut);
        } catch (FileNotFoundException e) {
            LOGGER.log(Level.SEVERE, e.getMessage());
        }
        if (pw != null) {
            pw.println("<!DOCTYPE html>");
            pw.println("<html>");
            pw.println("<head>");
            pw.println("<style>");
            pw.println("   table.obrazek{");
            pw.println("      border-collapse: collapse;");
            pw.println("      margin:auto;");
            pw.println("   }");
            pw.println("   .obrazek tr td {");
            pw.println("      padding:0;");
            pw.println("      margin:0;");
            pw.println("   }");
            pw.println("   .obrazek td{");
            pw.println("      width: 1px;");
            pw.println("      height: 1px;");
            pw.println("   }");
            pw.println("</style>");
            pw.println("</head>");
            pw.println("<body>");
            pw.println("   <table class=\"obrazek\">");
            WritableRaster wr = bi.getRaster();
            int width = bi.getWidth();
            int height = bi.getHeight();
            if (fileIn.endsWith("jpg")) {
                int[] pixel = new int[3];
                for (int i = 0; i < height; i++) {
                    pw.println("      <tr>");
                    pw.print("         ");
                    for (int j = 0; j < width; j++) {
                        wr.getPixel(j, i, pixel);
                        String rgb = RGBToHex(pixel[0], pixel[1], pixel[2]);
                        pw.print("<td bgcolor=\"" + rgb + "\"></td>");
                    }
                    pw.println("</tr>");
                }
            } else if (fileIn.endsWith("png")) {
                int[] pixel = new int[4];
                for (int i = 0; i < height; i++) {
                    pw.println("      <tr>");
                    pw.print("         ");
                    String rgb;
                    for (int j = 0; j < width; j++) {
                        wr.getPixel(j, i, pixel);
                        if (pixel[3] != 0) {
                            rgb = RGBToHex(pixel[0], pixel[1], pixel[2]);
                        } else {
                            rgb = "#ffffff";
                        }
                        pw.print("<td bgcolor=\"" + rgb + "\"></td>");
                    }
                    pw.println("</tr>");
                }
            }
            pw.println("   </table>");
            pw.println("</body>");
            pw.println("</html>");
            pw.close();
        }
    }

    /**
     * Zamienia wartosci R, G, B na liczbę HEX
     *
     * @param r int - składnik czerwony
     * @param g int - składnik zielony
     * @param b int - składnik niebieski
     * @return String - waartość HEX
     */
    public static String RGBToHex(int r, int g, int b) {
        String r1 = Integer.toString(r, 16);
        String g1 = Integer.toString(g, 16);
        String b1 = Integer.toString(b, 16);
        if (r1.length() == 1) {
            r1 = "0" + r1;
        }
        if (g1.length() == 1) {
            g1 = "0" + g1;
        }
        if (b1.length() == 1) {
            b1 = "0" + b1;
        }
        return "#" + r1 + g1 + b1;
    }

    /**
     * Zapisuje obrazek BufferedImage w podanym formacie do pliku o podanej
     * nazwie     *
     * @param path String - umiejscowienie obrazka
     * @param format String - "PNG" lub "JPEG"
     * @param bimage BufferedImage - obrazek do zapisania
     */
    public static void bimageToFile(String path, String format,
            BufferedImage bimage) {
        File f = new File(path);
        try {
            ImageIO.write(bimage, format, f);
        } catch (IOException e) {
           LOGGER.log(Level.SEVERE, e.getMessage());
        }
    }

    public static BufferedImage fileToBimage(String fileIn) {
        BufferedImage bi = null;
        try {
            bi = ImageIO.read(new File(fileIn));
        } catch (IOException e) {
           LOGGER.log(Level.SEVERE, e.getMessage());
        }
        return bi;
    }
}
MultiFilter.java
package imageslicer;

import java.io.*;
import java.util.*;
public class MultiFilter implements FilenameFilter {
    private String[] exts;
    private String[] lowerExts;

    /**
     * Tworzy filtr dla wskazanych reozszerzeń
     * @param dir -ścieżka do folderu
     * @param exts - lista uwzględnionych rozszerzeń
     */
    public MultiFilter(File dir, String... exts) {
        if (exts == null || exts.length == 0) {
            throw new IllegalArgumentException(
                    "musisz podać przynajmniej jedno nie-puste rozszerzenie");
        }
        for (String i : exts) {
            if (i == null || i.length() == 0) {
                throw new IllegalArgumentException(
                        "argument nie może  być ani 'null' ani 'pusty' ");
            }
        }
        this.exts = new String[exts.length];
        lowerExts = new String[exts.length];
        for (int i = 0; i < exts.length; i++) {
            this.exts[i] = exts[i];
            lowerExts[i] = exts[i].toLowerCase(Locale.ENGLISH);
        }
    }

    @Override
    public boolean accept(File dir, String s) {
        for (int i = 0; i < lowerExts.length; i++) {
            if (s.endsWith(exts[i])) {
                return true;
            }
        }
        return false;
    }
}
module-info.java
module imageslicer {
    requires java.desktop;
    requires java.logging;
}
KrojenieObrazka1.java
package imageslicer;

public class KrojenieObrazka1 {
    public static void main(String[] args) {
        ImageSlicer.slicePicture("assets/images/kwiatek.jpg", "assets/images/sliced");
    }
}
KrojenieObrazka2.java
package imageslicer;

public class KrojenieObrazka2 {
    public static void main(String[] args) {
        String[] pliki = ImageSlicer.listFileNames("assets/images", ".jpg");
        for (String pliki1 : pliki) {
            ImageSlicer.slicePictureToHTMLTableLayout(pliki1,
                    2,
                    2,
                    "assets/webcontent/images",
                    "assets/webcontent", "images");
        }
    }
}

Krojenie obrazka

Gdy uruchomimy klasę KrojenieObrazka1 to obrazek ‘assets/images/kwiatek.jpg’ zostanie pokrojony na 4 części, które zostaną umieszczone w folderze ‘assets/images/sliced/’.

Kwiatek pokrojony

Przygotowanie layoutu dla obrazka

Gdy uruchomimy klasę KrojenieObrazka2 to:

  • Obrazek ‘assets/images/kwiatek.jpg’ zostanie pokrojony i umieszczony w ‘assets/webcontent/images/’
  • W folderze ‘assets/webcontent/’ pojawi się plik ‘kwiatek.html’
Plik kwiatek.html
<!DOCTYPE html>
<html>
<head>
<style>
   div.obrazek {
      display: table;
   }
   div.rzad {
      display: table-row;
   }
   p.komorka {
      display: table-cell;
      border: 0px;
      margin: 0px;
      padding: 0px;
   }
   img.left {
      float: left;
   }
</style>
</head>
<body>
   <div class="obrazek">
      <div class="rzad">
         <p class="komorka"><img class="left" src="images/kwiatek00.jpg" width="128" height="96" /></p>
         <p class="komorka"><img class="left" src="images/kwiatek01.jpg" width="128" height="96" /></p>
      </div>
      <div class="rzad">
         <p class="komorka"><img class="left" src="images/kwiatek10.jpg" width="128" height="96" /></p>
         <p class="komorka"><img class="left" src="images/kwiatek11.jpg" width="128" height="96" /></p>
      </div>
   </div>
</body>
</html>

Gdy plik ‘kwiatek.html’ otworzymy w przeglądarce zobaczymy:

Widok końcowy

Widzimy cały obrazek składający się z części. Możemy się o tym przekonać, gdy spróbujemy skopiować obrazek – zawsze otrzymamy jedna z czterech części.

A oto końcowy widok naszej aplikacji:

Widok aplikacji