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