1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski package convwatch;
25*b1cdbd2cSJim Jagielski 
26*b1cdbd2cSJim Jagielski import convwatch.ImageHelper;
27*b1cdbd2cSJim Jagielski import java.io.File;
28*b1cdbd2cSJim Jagielski import java.awt.image.RenderedImage;
29*b1cdbd2cSJim Jagielski import java.awt.image.BufferedImage;
30*b1cdbd2cSJim Jagielski import java.lang.reflect.Method;
31*b1cdbd2cSJim Jagielski 
32*b1cdbd2cSJim Jagielski // -----------------------------------------------------------------------------
33*b1cdbd2cSJim Jagielski class Rect
34*b1cdbd2cSJim Jagielski {
35*b1cdbd2cSJim Jagielski     int x;
36*b1cdbd2cSJim Jagielski     int y;
37*b1cdbd2cSJim Jagielski     int w;
38*b1cdbd2cSJim Jagielski     int h;
39*b1cdbd2cSJim Jagielski 
Rect(int _x, int _y, int _w, int _h)40*b1cdbd2cSJim Jagielski     public Rect(int _x, int _y, int _w, int _h)
41*b1cdbd2cSJim Jagielski         {
42*b1cdbd2cSJim Jagielski             x = _x;
43*b1cdbd2cSJim Jagielski             y = _y;
44*b1cdbd2cSJim Jagielski             w = _w;
45*b1cdbd2cSJim Jagielski             h = _h;
46*b1cdbd2cSJim Jagielski         }
getX()47*b1cdbd2cSJim Jagielski     public int getX() {return x;}
getY()48*b1cdbd2cSJim Jagielski     public int getY() {return y;}
getWidth()49*b1cdbd2cSJim Jagielski     public int getWidth() {return w;}
getHeight()50*b1cdbd2cSJim Jagielski     public int getHeight() {return h;}
51*b1cdbd2cSJim Jagielski }
52*b1cdbd2cSJim Jagielski 
53*b1cdbd2cSJim Jagielski class BorderRemover
54*b1cdbd2cSJim Jagielski {
55*b1cdbd2cSJim Jagielski     ImageHelper m_aImage;
56*b1cdbd2cSJim Jagielski 
57*b1cdbd2cSJim Jagielski     // Helper values, filled after find Border
58*b1cdbd2cSJim Jagielski 
59*b1cdbd2cSJim Jagielski     // --------------------------------- test mode ---------------------------------
60*b1cdbd2cSJim Jagielski 
61*b1cdbd2cSJim Jagielski     // void pixelValue(int pixel)
62*b1cdbd2cSJim Jagielski     // {
63*b1cdbd2cSJim Jagielski     //     int alpha = (pixel >> 24) & 0xff;
64*b1cdbd2cSJim Jagielski     //     int red   = (pixel >> 16) & 0xff;
65*b1cdbd2cSJim Jagielski     //     int green = (pixel >>  8) & 0xff;
66*b1cdbd2cSJim Jagielski     //     int blue  = (pixel      ) & 0xff;
67*b1cdbd2cSJim Jagielski     //     int dummy = 0;
68*b1cdbd2cSJim Jagielski     // }
69*b1cdbd2cSJim Jagielski 
70*b1cdbd2cSJim Jagielski     /*
71*b1cdbd2cSJim Jagielski      * compares 2 colors with a given tolerance. So it's possible to check differences approximate.
72*b1cdbd2cSJim Jagielski      * @param _nColor1
73*b1cdbd2cSJim Jagielski      * @param _nColor2
74*b1cdbd2cSJim Jagielski      * @param _nTolerance is a percentage value how strong the colors could be differ
75*b1cdbd2cSJim Jagielski 
76*b1cdbd2cSJim Jagielski      */
compareColorWithTolerance(int _nColor1, int _nColor2, int _nTolerance)77*b1cdbd2cSJim Jagielski     boolean compareColorWithTolerance(int _nColor1, int _nColor2, int _nTolerance)
78*b1cdbd2cSJim Jagielski         {
79*b1cdbd2cSJim Jagielski             // int alpha1 = (_nColor1 >> 24) & 0xff;
80*b1cdbd2cSJim Jagielski             int red1   = (_nColor1 >> 16) & 0xff;
81*b1cdbd2cSJim Jagielski             int green1 = (_nColor1 >>  8) & 0xff;
82*b1cdbd2cSJim Jagielski             int blue1  = (_nColor1      ) & 0xff;
83*b1cdbd2cSJim Jagielski 
84*b1cdbd2cSJim Jagielski             // int alpha2 = (_nColor2 >> 24) & 0xff;
85*b1cdbd2cSJim Jagielski             int red2   = (_nColor2 >> 16) & 0xff;
86*b1cdbd2cSJim Jagielski             int green2 = (_nColor2 >>  8) & 0xff;
87*b1cdbd2cSJim Jagielski             int blue2  = (_nColor2      ) & 0xff;
88*b1cdbd2cSJim Jagielski 
89*b1cdbd2cSJim Jagielski             if (_nTolerance > 100)
90*b1cdbd2cSJim Jagielski             {
91*b1cdbd2cSJim Jagielski                 _nTolerance = 100;
92*b1cdbd2cSJim Jagielski             }
93*b1cdbd2cSJim Jagielski 
94*b1cdbd2cSJim Jagielski             // calculate tolerance halve
95*b1cdbd2cSJim Jagielski             double nTolerable = (_nTolerance * 256 / 100);
96*b1cdbd2cSJim Jagielski             if (nTolerable < 0)
97*b1cdbd2cSJim Jagielski             {
98*b1cdbd2cSJim Jagielski                 nTolerable = 0;
99*b1cdbd2cSJim Jagielski             }
100*b1cdbd2cSJim Jagielski 
101*b1cdbd2cSJim Jagielski             // X - th < Y < X + th
102*b1cdbd2cSJim Jagielski             // if ((red1 - nTolerable) < red2 && red2 < (red1 + nTolerable))
103*b1cdbd2cSJim Jagielski             // is the same
104*b1cdbd2cSJim Jagielski             // abs (X - Y) < th
105*b1cdbd2cSJim Jagielski             if (Math.abs(red1 - red2) < nTolerable)
106*b1cdbd2cSJim Jagielski             {
107*b1cdbd2cSJim Jagielski                 if (Math.abs(green1 - green2) < nTolerable)
108*b1cdbd2cSJim Jagielski                 {
109*b1cdbd2cSJim Jagielski                     if (Math.abs(blue1 - blue2) < nTolerable)
110*b1cdbd2cSJim Jagielski                     {
111*b1cdbd2cSJim Jagielski                         return true;
112*b1cdbd2cSJim Jagielski                     }
113*b1cdbd2cSJim Jagielski                     else
114*b1cdbd2cSJim Jagielski                     {
115*b1cdbd2cSJim Jagielski                         // blue differ
116*b1cdbd2cSJim Jagielski                     }
117*b1cdbd2cSJim Jagielski                 }
118*b1cdbd2cSJim Jagielski                 else
119*b1cdbd2cSJim Jagielski                 {
120*b1cdbd2cSJim Jagielski                     // green differ
121*b1cdbd2cSJim Jagielski                 }
122*b1cdbd2cSJim Jagielski             }
123*b1cdbd2cSJim Jagielski             else
124*b1cdbd2cSJim Jagielski             {
125*b1cdbd2cSJim Jagielski                 // red differ
126*b1cdbd2cSJim Jagielski             }
127*b1cdbd2cSJim Jagielski 
128*b1cdbd2cSJim Jagielski             return false;
129*b1cdbd2cSJim Jagielski         }
130*b1cdbd2cSJim Jagielski 
131*b1cdbd2cSJim Jagielski     /**
132*b1cdbd2cSJim Jagielski      * create a new image from an exist one without it's borders
133*b1cdbd2cSJim Jagielski      * open the file (_sFilenameFrom) as an image, check if it contains any borders and remove
134*b1cdbd2cSJim Jagielski      * the borders.
135*b1cdbd2cSJim Jagielski      */
createNewImageWithoutBorder(String _sFilenameFrom, String _sFilenameTo)136*b1cdbd2cSJim Jagielski     public boolean createNewImageWithoutBorder(String _sFilenameFrom, String _sFilenameTo)
137*b1cdbd2cSJim Jagielski         throws java.io.IOException
138*b1cdbd2cSJim Jagielski         {
139*b1cdbd2cSJim Jagielski             // System.out.println("load image: " + fileName);
140*b1cdbd2cSJim Jagielski             m_aImage = ImageHelper.createImageHelper(_sFilenameFrom);
141*b1cdbd2cSJim Jagielski 
142*b1cdbd2cSJim Jagielski             // System.out.println("image  width:" + String.valueOf(m_aImage.getWidth()));
143*b1cdbd2cSJim Jagielski             // System.out.println("image height:" + String.valueOf(m_aImage.getHeight()));
144*b1cdbd2cSJim Jagielski 
145*b1cdbd2cSJim Jagielski             // int nw = graphics_stuff.countNotWhitePixel(m_aImage);
146*b1cdbd2cSJim Jagielski             // System.out.println("not white pixels:" + String.valueOf(nw));
147*b1cdbd2cSJim Jagielski 
148*b1cdbd2cSJim Jagielski             // int nb = graphics_stuff.countNotBlackPixel(m_aImage);
149*b1cdbd2cSJim Jagielski             // System.out.println("not black pixels:" + String.valueOf(nb));
150*b1cdbd2cSJim Jagielski 
151*b1cdbd2cSJim Jagielski             int nBorderColor = m_aImage.getPixel(0,0);
152*b1cdbd2cSJim Jagielski             Rect aInnerRect = findBorder(m_aImage, nBorderColor);
153*b1cdbd2cSJim Jagielski 
154*b1cdbd2cSJim Jagielski             RenderedImage aImage = createImage(m_aImage, aInnerRect);
155*b1cdbd2cSJim Jagielski 
156*b1cdbd2cSJim Jagielski             File aWriteFile = new File(_sFilenameTo);
157*b1cdbd2cSJim Jagielski             // GlobalLogWriter.get().println("Hello World: File to: " + _sFilenameTo);
158*b1cdbd2cSJim Jagielski 
159*b1cdbd2cSJim Jagielski             Exception ex = null;
160*b1cdbd2cSJim Jagielski             try
161*b1cdbd2cSJim Jagielski             {
162*b1cdbd2cSJim Jagielski                 Class imageIOClass = Class.forName("javax.imageio.ImageIO");
163*b1cdbd2cSJim Jagielski                 // GlobalLogWriter.get().println("Hello World: get Class");
164*b1cdbd2cSJim Jagielski 
165*b1cdbd2cSJim Jagielski                 Method getWriterMIMETypesMethod = imageIOClass.getDeclaredMethod("getWriterMIMETypes", new Class[]{ });
166*b1cdbd2cSJim Jagielski                 // GlobalLogWriter.get().println("Hello World: get Methode");
167*b1cdbd2cSJim Jagielski 
168*b1cdbd2cSJim Jagielski                 Object aObj = getWriterMIMETypesMethod.invoke(imageIOClass, new Object[]{ });
169*b1cdbd2cSJim Jagielski                 String[] types = (String[])aObj;
170*b1cdbd2cSJim Jagielski                 // GlobalLogWriter.get().println("Hello World: types: " + Arrays.asList(types) );
171*b1cdbd2cSJim Jagielski 
172*b1cdbd2cSJim Jagielski                 Method writeMethod = imageIOClass.getDeclaredMethod("write", new Class[]{ java.awt.image.RenderedImage.class,
173*b1cdbd2cSJim Jagielski                                                                                           java.lang.String.class,
174*b1cdbd2cSJim Jagielski                                                                                           java.io.File.class});
175*b1cdbd2cSJim Jagielski                 // GlobalLogWriter.get().println("Hello World: get Methode");
176*b1cdbd2cSJim Jagielski                 writeMethod.invoke(imageIOClass, new Object[]{aImage, "image/jpeg", aWriteFile});
177*b1cdbd2cSJim Jagielski             }
178*b1cdbd2cSJim Jagielski             catch(java.lang.ClassNotFoundException e) {
179*b1cdbd2cSJim Jagielski                 e.printStackTrace();
180*b1cdbd2cSJim Jagielski                 ex = e;
181*b1cdbd2cSJim Jagielski             }
182*b1cdbd2cSJim Jagielski             catch(java.lang.NoSuchMethodException e) {
183*b1cdbd2cSJim Jagielski                 e.printStackTrace();
184*b1cdbd2cSJim Jagielski                 ex = e;
185*b1cdbd2cSJim Jagielski             }
186*b1cdbd2cSJim Jagielski             catch(java.lang.IllegalAccessException e) {
187*b1cdbd2cSJim Jagielski                 e.printStackTrace();
188*b1cdbd2cSJim Jagielski                 ex = e;
189*b1cdbd2cSJim Jagielski             }
190*b1cdbd2cSJim Jagielski             catch(java.lang.reflect.InvocationTargetException e) {
191*b1cdbd2cSJim Jagielski                 e.printStackTrace();
192*b1cdbd2cSJim Jagielski                 ex = e;
193*b1cdbd2cSJim Jagielski             }
194*b1cdbd2cSJim Jagielski 
195*b1cdbd2cSJim Jagielski             if (ex != null) {
196*b1cdbd2cSJim Jagielski                 // get Java version:
197*b1cdbd2cSJim Jagielski                 String javaVersion = System.getProperty("java.version");
198*b1cdbd2cSJim Jagielski                 throw new java.io.IOException(
199*b1cdbd2cSJim Jagielski                     "Cannot construct object with current Java version " +
200*b1cdbd2cSJim Jagielski                     javaVersion + ": " + ex.getMessage());
201*b1cdbd2cSJim Jagielski             }
202*b1cdbd2cSJim Jagielski //            ImageIO.write(aImage, "jpg", aWriteFile);
203*b1cdbd2cSJim Jagielski 
204*b1cdbd2cSJim Jagielski             return true;
205*b1cdbd2cSJim Jagielski         }
206*b1cdbd2cSJim Jagielski 
207*b1cdbd2cSJim Jagielski 
208*b1cdbd2cSJim Jagielski     /**
209*b1cdbd2cSJim Jagielski      * runs through the image, pixel by pixel
210*b1cdbd2cSJim Jagielski      * as long as found pixels like the color at (0,0) this is interpreted as border.
211*b1cdbd2cSJim Jagielski      * as result it fills the m_nXMin, m_nXMax, m_nYMin, m_nYMax values.
212*b1cdbd2cSJim Jagielski      */
213*b1cdbd2cSJim Jagielski 
findBorder(ImageHelper _aImage, int _nBorderColor)214*b1cdbd2cSJim Jagielski     Rect findBorder(ImageHelper _aImage, int _nBorderColor)
215*b1cdbd2cSJim Jagielski         {
216*b1cdbd2cSJim Jagielski             int h = _aImage.getHeight();
217*b1cdbd2cSJim Jagielski             int w = _aImage.getWidth();
218*b1cdbd2cSJim Jagielski             int nXMin = w;
219*b1cdbd2cSJim Jagielski             int nXMax = 0;
220*b1cdbd2cSJim Jagielski             int nYMin = h;
221*b1cdbd2cSJim Jagielski             int nYMax = 0;
222*b1cdbd2cSJim Jagielski 
223*b1cdbd2cSJim Jagielski             for (int y = 0; y < h; y++)
224*b1cdbd2cSJim Jagielski             {
225*b1cdbd2cSJim Jagielski                 for (int x = 0; x < nXMin; x++)
226*b1cdbd2cSJim Jagielski                 {
227*b1cdbd2cSJim Jagielski                     // handlesinglepixel(x+i, y+j, pixels[j * w + i]);
228*b1cdbd2cSJim Jagielski                     int nCurrentColor = _aImage.getPixel(x, y);
229*b1cdbd2cSJim Jagielski                     if (! compareColorWithTolerance(nCurrentColor, _nBorderColor, 10))
230*b1cdbd2cSJim Jagielski                     {
231*b1cdbd2cSJim Jagielski                         // pixelValue(nCurrentColor);
232*b1cdbd2cSJim Jagielski                         // System.out.print("*");
233*b1cdbd2cSJim Jagielski                         nXMin = java.lang.Math.min(nXMin, x);
234*b1cdbd2cSJim Jagielski                         nYMin = java.lang.Math.min(nYMin, y);
235*b1cdbd2cSJim Jagielski                     }
236*b1cdbd2cSJim Jagielski                     // else
237*b1cdbd2cSJim Jagielski                     // {
238*b1cdbd2cSJim Jagielski                     //     System.out.print(" ");
239*b1cdbd2cSJim Jagielski                     // }
240*b1cdbd2cSJim Jagielski                 }
241*b1cdbd2cSJim Jagielski             }
242*b1cdbd2cSJim Jagielski             for (int y = 0; y < h; y++)
243*b1cdbd2cSJim Jagielski             {
244*b1cdbd2cSJim Jagielski                 for (int nx = w - 1; nx >= nXMax; --nx)
245*b1cdbd2cSJim Jagielski                 {
246*b1cdbd2cSJim Jagielski                     int ny = h - y - 1;
247*b1cdbd2cSJim Jagielski                     int nCurrentColor = _aImage.getPixel(nx, ny);
248*b1cdbd2cSJim Jagielski                     if (! compareColorWithTolerance(nCurrentColor, _nBorderColor, 10))
249*b1cdbd2cSJim Jagielski                     {
250*b1cdbd2cSJim Jagielski                         nXMax = java.lang.Math.max(nXMax, nx);
251*b1cdbd2cSJim Jagielski                         nYMax = java.lang.Math.max(nYMax, ny);
252*b1cdbd2cSJim Jagielski                     }
253*b1cdbd2cSJim Jagielski                 }
254*b1cdbd2cSJim Jagielski                 // System.out.println();
255*b1cdbd2cSJim Jagielski             }
256*b1cdbd2cSJim Jagielski             // System.out.println("xmin: " + String.valueOf(nXMin));
257*b1cdbd2cSJim Jagielski             // System.out.println("xmax: " + String.valueOf(nXMax));
258*b1cdbd2cSJim Jagielski             // System.out.println("ymin: " + String.valueOf(nYMin));
259*b1cdbd2cSJim Jagielski             // System.out.println("ymax: " + String.valueOf(nYMax));
260*b1cdbd2cSJim Jagielski 
261*b1cdbd2cSJim Jagielski             Rect aRect;
262*b1cdbd2cSJim Jagielski             if (nXMin < nXMax && nYMin < nYMax)
263*b1cdbd2cSJim Jagielski             {
264*b1cdbd2cSJim Jagielski                 int nw = nXMax - nXMin + 1;
265*b1cdbd2cSJim Jagielski                 int nh = nYMax - nYMin + 1;
266*b1cdbd2cSJim Jagielski 
267*b1cdbd2cSJim Jagielski                 // this is the rectangle around the image content.
268*b1cdbd2cSJim Jagielski                 aRect = new Rect(nXMin, nYMin, nw, nh );
269*b1cdbd2cSJim Jagielski             }
270*b1cdbd2cSJim Jagielski             else
271*b1cdbd2cSJim Jagielski             {
272*b1cdbd2cSJim Jagielski                 // create the smalles possible image
273*b1cdbd2cSJim Jagielski                 aRect = new Rect(0,0,1,1);
274*b1cdbd2cSJim Jagielski             }
275*b1cdbd2cSJim Jagielski 
276*b1cdbd2cSJim Jagielski 
277*b1cdbd2cSJim Jagielski             // m_nXMin = nXMin;
278*b1cdbd2cSJim Jagielski             // m_nXMax = nXMax;
279*b1cdbd2cSJim Jagielski             // m_nYMin = nYMin;
280*b1cdbd2cSJim Jagielski             // m_nYMax = nYMax;
281*b1cdbd2cSJim Jagielski             return aRect;
282*b1cdbd2cSJim Jagielski         }
283*b1cdbd2cSJim Jagielski 
createImage(ImageHelper _aImage, Rect _aRect)284*b1cdbd2cSJim Jagielski     RenderedImage createImage(ImageHelper _aImage, Rect _aRect) throws IllegalArgumentException
285*b1cdbd2cSJim Jagielski         {
286*b1cdbd2cSJim Jagielski // TODO: throw if w or h < 0
287*b1cdbd2cSJim Jagielski             int w = _aRect.getWidth();
288*b1cdbd2cSJim Jagielski             int h = _aRect.getHeight();
289*b1cdbd2cSJim Jagielski 
290*b1cdbd2cSJim Jagielski             if (w <= 0 || h <= 0)
291*b1cdbd2cSJim Jagielski             {
292*b1cdbd2cSJim Jagielski                 throw new IllegalArgumentException("width or height are too small or negative.");
293*b1cdbd2cSJim Jagielski             }
294*b1cdbd2cSJim Jagielski 
295*b1cdbd2cSJim Jagielski             BufferedImage aBI = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
296*b1cdbd2cSJim Jagielski 
297*b1cdbd2cSJim Jagielski             int nXOffset = _aRect.getX();
298*b1cdbd2cSJim Jagielski             int nYOffset = _aRect.getY();
299*b1cdbd2cSJim Jagielski 
300*b1cdbd2cSJim Jagielski             // Memory Block move
301*b1cdbd2cSJim Jagielski             for (int y = 0; y < h; y++)
302*b1cdbd2cSJim Jagielski             {
303*b1cdbd2cSJim Jagielski                 for (int x = 0; x < w; x++)
304*b1cdbd2cSJim Jagielski                 {
305*b1cdbd2cSJim Jagielski                     // aPixels[y * w + x] = m_aImage.getPixel(m_nXMin + x, m_nYMin + y);
306*b1cdbd2cSJim Jagielski                     aBI.setRGB(x, y, _aImage.getPixel(x + nXOffset, y + nYOffset));
307*b1cdbd2cSJim Jagielski                 }
308*b1cdbd2cSJim Jagielski             }
309*b1cdbd2cSJim Jagielski             // java.awt.image.MemoryImageSource aSource = new java.awt.image.MemoryImageSource(w, h, aPixels, 0, w);
310*b1cdbd2cSJim Jagielski //             return java.awt.Component.createImage(aSource);
311*b1cdbd2cSJim Jagielski              // return java.awt.Toolkit.getDefaultToolkit().createImage(aSource);
312*b1cdbd2cSJim Jagielski              return aBI;
313*b1cdbd2cSJim Jagielski         }
314*b1cdbd2cSJim Jagielski 
315*b1cdbd2cSJim Jagielski }
316