2 * ************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2008 by Sun Microsystems, Inc.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * $RCSfile: JPEGComparator.java,v $
11 * $Revision: 1.1.2.6 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 * ***********************************************************************
35 import helper
.OSHelper
;
36 import helper
.ProcessHandler
;
40 * Helper class to interpret a jpg filename
48 private NameDPIPage(String _sName
, int _nDPI
, int _nPage
)
55 public static NameDPIPage
interpret(String _sFilename
)
57 String sBasename
= FileHelper
.getBasename(_sFilename
); // if exist a path, remove it
58 String sNameNoSuffix
= FileHelper
.getNameNoSuffix(sBasename
); // remove extension (.jpg)
60 // check if there exist a 'DPI_' at specific position
61 String sDPICheck
= sNameNoSuffix
.substring(sNameNoSuffix
.length() - 8, sNameNoSuffix
.length() - 4);
65 if (sDPICheck
.equals("DPI_"))
67 // seems to be a generated filename by us.
68 int nDPIStart
= sNameNoSuffix
.lastIndexOf("_", sNameNoSuffix
.length() - 8);
69 sName
= sNameNoSuffix
.substring(0, nDPIStart
);
72 String sDPI
= sNameNoSuffix
.substring(nDPIStart
+ 1, sNameNoSuffix
.length() - 8);
75 nDPI
= Integer
.valueOf(sDPI
).intValue();
77 catch(java
.lang
.NumberFormatException e
)
79 GlobalLogWriter
.get().println("DPI: Number format exception");
81 String sPage
= sNameNoSuffix
.substring(sNameNoSuffix
.length() - 4);
84 nPage
= Integer
.valueOf(sPage
).intValue();
86 catch(java
.lang
.NumberFormatException e
)
88 GlobalLogWriter
.get().println("Page: Number format exception");
94 sName
= sNameNoSuffix
;
97 return new NameDPIPage(sName
, nDPI
, nPage
);
105 public class JPEGComparator
extends EnhancedComplexTestCase
108 public String
[] getTestMethodNames()
110 return new String
[]{"CompareJPEGvsJPEG"};
116 public void CompareJPEGvsJPEG()
118 GlobalLogWriter
.set(log
);
119 ParameterHelper aParam
= new ParameterHelper(param
);
121 // run through all documents found in Inputpath
122 foreachJPEGcompareWithJPEG(aParam
);
125 public void checkOneFile(String _sDocumentName
, String _sResult
, ParameterHelper _aParams
) throws OfficeException
127 // private void callEveryPictureInIniFile(IniFile _aIniFile, String _sSectionName, ParameterHelper _aParam)
129 String sPath
= FileHelper
.getPath(_sDocumentName
);
130 String sSectionName
= FileHelper
.getBasename(_sDocumentName
);
132 // take the build id out of the ini file in the reference file and put it into the current parameter helper
133 String sIniFileForRefBuildID
= FileHelper
.appendPath(sPath
, sSectionName
+ ".ini");
134 IniFile aIniFileForRefBuildID
= new IniFile(sIniFileForRefBuildID
);
135 String sRefBuildID
= aIniFileForRefBuildID
.getValue("global", "buildid");
136 aIniFileForRefBuildID
.close();
138 _aParams
.getTestParameters().put("RefBuildId", sRefBuildID
);
140 String sIniFile
= FileHelper
.appendPath(sPath
, "index.ini");
141 IniFile aIniFile
= new IniFile(sIniFile
);
142 if (aIniFile
.hasValue(sSectionName
, "pages"))
144 // only which has 'pages' has also pictures
145 int nPages
= aIniFile
.getIntValue(sSectionName
, "pages", 0);
146 String sJPEGSchema
= aIniFile
.getValue(sSectionName
, "jpegschema");
148 for (int i
=1 ; i
<=nPages
; i
++)
150 String sJPEGFilename
= JPEGCreator
.getFilenameForJPEGSchema(sJPEGSchema
, i
);
151 // String sPath = FileHelper.getPath(_aParam.getInputPath());
152 String sJPEGPath
= FileHelper
.getPath(sJPEGFilename
);
153 if (!sPath
.equals(sJPEGPath
))
155 GlobalLogWriter
.println("Path where to find the index and where to file the JPEG pictures are not the same.");
158 // String sEntry = FileHelper.appendPath(sPath, sSection);
159 File aFile
= new File(sJPEGFilename
);
160 assure("File '" + sJPEGFilename
+ "' doesn't exists.", aFile
.exists(), true);
163 GlobalLogWriter
.println("Page: " + i
);
164 checkOnePicture(sJPEGFilename
, _sResult
, _aParams
);
170 GlobalLogWriter
.println("The document '" + sSectionName
+ "' seems to have no picture representation.");
173 String sResultIniFile
= FileHelper
.appendPath(_sResult
, sSectionName
);
174 evaluateResult(sResultIniFile
, _aParams
);
178 private void evaluateResult(String _sDocument
, ParameterHelper _aParams
)
180 String sResultIniFile
= _sDocument
+ ".ini";
181 File aFile
= new File(sResultIniFile
);
182 assure("Result file doesn't exists " + sResultIniFile
, aFile
.exists());
187 int ok_status
= 1; // 1=ok 2=bad 3=ugly
189 IniFile aResultIniFile
= new IniFile(sResultIniFile
);
190 int nPages
= aResultIniFile
.getIntValue("global", "pages", 0);
191 for (int i
=0;i
<nPages
;i
++)
193 String sCurrentPage
= "page" + String
.valueOf(i
+ 1);
194 int nPercent
= aResultIniFile
.getIntValue(sCurrentPage
, "percent", -1);
199 else if (nPercent
<= 5)
211 assure("Error: document doesn't contains pages", nPages
> 0);
213 // TODO: this information has to come out of the ini files
214 String sStatusRunThrough
= "PASSED, ";
215 String sPassed
= "OK";
217 String sStatusMessage
= "From " + nPages
+ " page(s) are: ";
224 sGood
= " good:=" + good
;
225 sStatusMessage
+= sGood
;
229 sBad
= " bad:=" + bad
;
230 sStatusMessage
+= sBad
;
234 sUgly
= " ugly:=" + ugly
;
235 sStatusMessage
+= sUgly
;
252 sPassed
= "NEED A LOOK";
259 sStatusRunThrough
+= sPassed
;
260 aResultIniFile
.insertValue("global", "state", sStatusRunThrough
);
261 aResultIniFile
.insertValue("global", "info", sStatusMessage
);
262 aResultIniFile
.close();
264 _aParams
.getTestParameters().put("current_state", sStatusRunThrough
);
265 _aParams
.getTestParameters().put("current_info", sStatusMessage
);
266 _aParams
.getTestParameters().put("current_ok_status", ok_status
);
268 // if we have a ugly page, we must return this as a FAILED STATUS in Log file!
269 // assure( "There exist pages marked as ugly.", ugly == 0)
272 private void checkOnePicture(String _sDocumentName
, String _sResult
, ParameterHelper _aParams
)
274 GlobalLogWriter
.println("JPEG: Compare difference between '" + _sDocumentName
+ "' and '" + _sResult
+ "'");
275 File aResultFile
= new File(_sResult
);
276 if (aResultFile
.isDirectory())
278 // result is just a directory, so we search for the basename of the source and take this.
279 String sBasename
= FileHelper
.getBasename(_sDocumentName
);
280 String sResultFilename
= FileHelper
.appendPath(_sResult
, sBasename
);
281 aResultFile
= new File(sResultFilename
);
282 if (aResultFile
.exists())
284 // Original and Result exists
285 String sInputPath
= _aParams
.getInputPath();
286 if (sInputPath
.toLowerCase().endsWith("index.ini"))
289 // we want to get the buildid from the info file.
293 compareJPEG(_sDocumentName
, sResultFilename
, _aParams
);
298 GlobalLogWriter
.println("Warning: Result JPEG doesn't exists '" + sResultFilename
+ "'");
303 // result is also a file
304 if (aResultFile
.exists())
306 compareJPEG(_sDocumentName
, _sResult
, _aParams
);
310 GlobalLogWriter
.println("Warning: Result JPEG doesn't exists '" + _sResult
+ "'");
318 * compare 2 JPEGs, it is a need, that both _sDocumentName and _sResultFilename exist.
319 * @param _sDocumentName
322 * @return 0=no difference !=0 both files differ
325 private void compareJPEG(String _sDocumentName
, String _sResult
, ParameterHelper _aParams
)
327 NameDPIPage aNameDPIPage
= NameDPIPage
.interpret(_sDocumentName
);
329 String sSourceBasename
= FileHelper
.getBasename(_sDocumentName
);
330 String sSourcePath
= FileHelper
.getPath(_sDocumentName
);
331 String sDestinationBasename
= FileHelper
.getBasename(_sResult
);
332 String sDestinationPath
= FileHelper
.getPath(_sResult
);
334 if (! sSourcePath
.equals(sDestinationPath
))
336 // we want to have all in one Directory, Original, Reference and the Difference result.
337 // copy the original file to the reference path
338 String sNewSourceBasename
= "Original_" + sSourceBasename
;
339 // String sSource = FileHelper.appendPath(sSourcePath, sSourceBasename);
340 String sSource
= _sDocumentName
;
341 String sDestination
= FileHelper
.appendPath(sDestinationPath
, sNewSourceBasename
);
342 FileHelper
.copy(sSource
, sDestination
);
343 sSourceBasename
= sNewSourceBasename
;
345 String sDifferenceBasename
= "Difference_between_" + FileHelper
.getNameNoSuffix(sSourceBasename
) + "_and_" + FileHelper
.getNameNoSuffix(sDestinationBasename
) + ".jpg";
346 // String sDifferencePath = sDestinationPath;
348 String sSource
= FileHelper
.appendPath(sDestinationPath
, sSourceBasename
);
349 String sDestination
= FileHelper
.appendPath(sDestinationPath
, sDestinationBasename
);
350 String sDifference
= FileHelper
.appendPath(sDestinationPath
, sDifferenceBasename
);
351 int nErr
= compareJPEG(sSource
, sDestination
, sDifference
);
352 if (nErr
== 0 && FileHelper
.exists(sDifference
))
354 // check the difference, returns the count of different colors
355 // this means, 1=only one color, no differences found.
356 int nResult
= identify(sDifference
);
357 int nPercentColorDiffer
= 0;
358 String sResult
= "NO";
363 nPercentColorDiffer
= estimateGfx(sSource
, sDestination
, sDifference
);
365 catch (java
.io
.IOException e
)
367 GlobalLogWriter
.println("Can't estimate the different colors. " + e
.getMessage());
375 // store the result in a result.ini file
376 String sResultFile
= FileHelper
.appendPath(sDestinationPath
, aNameDPIPage
.Name
+ ".ini");
377 int nPage
= aNameDPIPage
.Page
;
382 IniFile aResultIni
= new IniFile(sResultFile
);
384 String
[] aComment
= {
385 "; This file is automatically created by a graphical.JPEGComparator run",
387 "; If you see this file in a browser you may have forgotten to set the follows in the property file",
388 "; " + PropertyName
.DOC_COMPARATOR_HTML_OUTPUT_PREFIX
+ "=http://<computer>/gfxcmp_ui/cw.php?inifile=",
389 "; Please check the documentation if you got confused.",
392 aResultIni
.insertFirstComment(aComment
);
394 // write down the global flags
395 int nMaxPage
= Math
.max(nPage
, aResultIni
.getIntValue("global", "pages", 0));
396 aResultIni
.insertValue("global", "pages", nMaxPage
);
398 // INIoutput.writeValue("buildid", _sBuildID);
399 // INIoutput.writeValue("refbuildid", _sRefBuildID);
400 String sRefBuildId
= (String
)_aParams
.getTestParameters().get("RefBuildId");
401 if (sRefBuildId
== null)
405 aResultIni
.insertValue("global", "refbuildid", sRefBuildId
);
407 aResultIni
.insertValue("global", "diffdiff", "no");
408 aResultIni
.insertValue("global", "basename", aNameDPIPage
.Name
);
409 aResultIni
.insertValue("global", "dpi", aNameDPIPage
.DPI
);
411 // write down flags for each page
412 String sSection
= "page" + String
.valueOf(nPage
);
414 aResultIni
.insertValue(sSection
, "oldgfx", sSource
);
415 aResultIni
.insertValue(sSection
, "newgfx", sDestination
);
416 aResultIni
.insertValue(sSection
, "diffgfx", sDifference
);
417 aResultIni
.insertValue(sSection
, "percent", nPercentColorDiffer
);
418 aResultIni
.insertValue(sSection
, "BM", "false");
419 aResultIni
.insertValue(sSection
, "result", sResult
);
425 // // This creates a status for exact on document
426 // static boolean createINIStatus(StatusHelper[] aList, String _sFilenamePrefix, String _sOutputPath, String _sAbsoluteInputFile, String _sBuildID, String _sRefBuildID)
429 // String fs = System.getProperty("file.separator");
430 // String sBasename = FileHelper.getBasename(_sAbsoluteInputFile);
431 // String sNameNoSuffix = FileHelper.getNameNoSuffix(sBasename);
432 //// String sHTMLFile = _sFilenamePrefix + sNameNoSuffix + ".html";
433 //// HTMLOutputter HTMLoutput = HTMLOutputter.create(_sOutputPath, sHTMLFile, "", "");
434 //// HTMLoutput.header(sNameNoSuffix);
435 //// TODO: version info was fine
436 //// HTMLoutput.checkSection(sBasename);
439 // String sINIFile = _sFilenamePrefix + sNameNoSuffix + ".ini";
440 // INIOutputter INIoutput = INIOutputter.create(_sOutputPath, sINIFile, "", "");
441 // INIoutput.createHeader();
442 //// TODO: version info was fine
444 // INIoutput.writeSection("global");
445 // INIoutput.writeValue("pages", String.valueOf(aList.length));
446 // INIoutput.writeValue("buildid", _sBuildID);
447 // INIoutput.writeValue("refbuildid", _sRefBuildID);
448 // INIoutput.writeValue("diffdiff", "no");
449 // INIoutput.writeValue("basename", sBasename);
451 // boolean bResultIsOk = true; // result over all pages
452 // for (int i=0;i<aList.length; i++)
454 // INIoutput.writeSection("page" + String.valueOf(i + 1)); // list start at point 0, but this is page 1 and so on... current_page = (i + 1)
455 // aList[i].printStatus();
457 // boolean bCurrentResult = true; // result over exact one page
459 // int nCurrentDiffStatus = aList[i].nDiffStatus;
461 // // check if the status is in a defined range
462 // if (nCurrentDiffStatus == StatusHelper.DIFF_NO_DIFFERENCES)
466 // else if (nCurrentDiffStatus == StatusHelper.DIFF_DIFFERENCES_FOUND && aList[i].nPercent < 5)
470 // else if (nCurrentDiffStatus == StatusHelper.DIFF_AFTER_MOVE_DONE_NO_PROBLEMS)
474 // else if (nCurrentDiffStatus == StatusHelper.DIFF_AFTER_MOVE_DONE_DIFFERENCES_FOUND && aList[i].nPercent2 < 5)
481 // bCurrentResult = false; // logic: nDiff==0 = true if there is no difference
485 //// HTMLoutput.checkLine(aList[i], bCurrentResult);
486 // INIoutput.checkLine(aList[i], bCurrentResult);
487 // bResultIsOk &= bCurrentResult;
490 //// HTMLoutput.close();
491 // INIoutput.close();
492 // return bResultIsOk;
497 * count how much pixel differ and between Old or New and the Difference graphics
499 * First, count the old graphics, then the new graphics due to the fact both should be equal
500 * it should be legal to take result from old or new. We take the graphics with less values.
502 * Second, count the difference graphics, now take the percent algorithm and
503 * build a percent value, which contain the number of different pixels as a percent value
506 * 0% there is no difference
508 * <100% Take a look into the difference graphics, maybe the difference graphics shows
509 * text like outlined or the text is little bit move left, right up or down.
511 * >>100% Yes it's possible that there is a difference more then 100%, maybe a font problem
512 * between old and new graphics. The font of the new graphics is little bit bigger,
513 * so the pixel count between old graphics and new graphics is twice the more.
515 * @param _sOldGfx path & name to the jpeg file (1)
516 * @param _sNewGfx path & name to the other jpeg file (2)
517 * @param _sDiffGfx path & name to the new difference file which shows the difference between (1) and (2)
518 * @return the count of different pixels
519 * @throws java.io.IOException if file access is not possible
522 public static int estimateGfx(String _sOldGfx
, String _sNewGfx
, String _sDiffGfx
)
523 throws java
.io
.IOException
526 final int nNotWhiteCount_OldGraphic
= PixelCounter
.countNotWhitePixelsFromImage(_sOldGfx
);
527 final int nNotWhiteCount_NewGraphic
= PixelCounter
.countNotWhitePixelsFromImage(_sNewGfx
);
528 final int nNotBlackCount_DiffGraphic
= PixelCounter
.countNotBlackPixelsFromImage(_sDiffGfx
);
530 int nMinNotWhiteCount
= Math
.min(nNotWhiteCount_NewGraphic
, nNotWhiteCount_OldGraphic
);
533 if (nMinNotWhiteCount
== 0)
535 nMinNotWhiteCount
= Math
.max(nNotWhiteCount_NewGraphic
, nNotWhiteCount_OldGraphic
);
536 if (nMinNotWhiteCount
== 0)
538 nMinNotWhiteCount
= 1;
542 int nPercent
= Math
.abs(nNotBlackCount_DiffGraphic
* 100 / nMinNotWhiteCount
);
543 GlobalLogWriter
.get().println( "Graphics check, pixel based:" + String
.valueOf(nPercent
) + "% pixel differ ");
547 private static int compareJPEG(String _sOldGfx
, String _sNewGfx
, String _sDiffGfx
)
549 String sComposite
= "composite";
550 if (OSHelper
.isWindows())
552 sComposite
= "composite.exe";
555 // String sCommand = sComposite + " -compose difference " +
556 // StringHelper.doubleQuoteIfNeed(_sOldGfx) + " " +
557 // StringHelper.doubleQuoteIfNeed(_sNewGfx) + " " +
558 // StringHelper.doubleQuoteIfNeed(_sDiffGfx);
560 String
[] sCommandArray
=
570 ProcessHandler aHandler
= new ProcessHandler(sCommandArray
);
571 boolean bBackValue
= aHandler
.executeSynchronously();
572 int nExitCode
= aHandler
.getExitCode();
575 GlobalLogWriter
.println("'" + sComposite
+ "' return with ");
576 String sBack
= aHandler
.getOutputText();
577 GlobalLogWriter
.get().println("'" + sBack
+ "'");
581 // creates an extra smaller difference picture
582 File aDiffFile
= new File(_sDiffGfx
);
583 if (aDiffFile
.exists())
585 JPEGCreator
.convertToNearSameFileWithWidth340(_sDiffGfx
);
592 * wrapper for ImageMagick identify,
593 * function checks how many different colors a picture contains.
594 * if it's only one color (nResult==1), like background color, there is no difference.
596 int identify(String _sDiffGfx
)
599 // would like to know what the meaning of %k is for ImageMagick's 'identify'
600 String sIM_Format
= "%k";
601 // if (OSHelper.isWindows())
603 // sIM_Format = "%%k";
606 String sIdentify
= "identify";
607 if (OSHelper
.isWindows())
609 sIdentify
= "identify.exe";
612 // String sCommand = sIdentify + " " + sIM_Format + " " + StringHelper.doubleQuoteIfNeed(_sDiffGfx);
614 String
[] sCommandArray
=
621 ProcessHandler aHandler
= new ProcessHandler(sCommandArray
);
622 boolean bBackValue
= aHandler
.executeSynchronously();
623 int nExitCode
= aHandler
.getExitCode();
625 String sBack
= aHandler
.getOutputText();
626 GlobalLogWriter
.get().println("'" + sBack
+ "'");
628 // try to interpret the result, which we get as a String
631 int nIdx
= sBack
.indexOf("\n");
634 sBack
= sBack
.substring(0, nIdx
);
637 nResult
= Integer
.valueOf(sBack
).intValue();
639 catch(java
.lang
.NumberFormatException e
)
641 GlobalLogWriter
.get().println("identify(): Number format exception");
649 public static void main(String
[] _args
)
651 // give an index.ini file, ok
652 // give a directory, where exist jpeg files ok
653 // inputpath (given file) doesn't exists
657 "-TimeOut", "3600000",
658 "-tb", "java_complex",
659 "-o", "graphical.JPEGComparator",
660 "-DOC_COMPARATOR_INPUT_PATH", "C:\\CWS\\temp\\output\\index.ini",
661 "-DOC_COMPARATOR_OUTPUT_PATH", "C:\\CWS\\temp\\output2",
662 // "-DOC_COMPARATOR_INPUT_PATH", "C:\\CWS\\temp\\output\\GroupReport.odt.pdf_180DPI_0001.jpg",
663 // "-DOC_COMPARATOR_OUTPUT_PATH", "C:\\CWS\\temp\\output2\\Report1.odt.pdf_180DPI_0001.jpg",
664 "-DOC_COMPARATOR_HTML_OUTPUT_PREFIX", "http://so-gfxcmp-lin.germany.sun.com/gfxcmp_ui/cw.php?inifile=",
665 // "-DOC_COMPARATOR_REFERENCE_CREATOR_TYPE", "PDF", /* default: "OOo" */
666 // "-DOC_COMPARATOR_REFERENCE_CREATOR_TYPE", "msoffice", /* default: "OOo" */
667 // "-OFFICE_VIEWABLE", "false",
668 // "-AppExecutionCommand", "\"C:/Programme/sun/staroffice 9/program/soffice.exe\" -norestore -nocrashreport -accept=pipe,name=ll93751;urp;",
672 org
.openoffice
.Runner
.main(args
);