bump product version to 4.1.6.2
[LibreOffice.git] / qadevOOo / runner / graphical / JPEGComparator.java
blobdcf9cc47b51480b54430c9c26911481dc06aa83f
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package graphical;
21 import helper.OSHelper;
22 import helper.ProcessHandler;
23 import java.io.File;
25 /**
26 * Helper class to interpret a jpg filename
28 class NameDPIPage
31 String Name;
32 int DPI;
33 int Page;
35 private NameDPIPage(String _sName, int _nDPI, int _nPage)
37 Name = _sName;
38 DPI = _nDPI;
39 Page = _nPage;
42 public static NameDPIPage interpret(String _sFilename)
44 String sBasename = FileHelper.getBasename(_sFilename); // if exist a path, remove it
45 String sNameNoSuffix = FileHelper.getNameNoSuffix(sBasename); // remove extension (.jpg)
47 // check if there exist a 'DPI_' at specific position
48 String sDPICheck = sNameNoSuffix.substring(sNameNoSuffix.length() - 8, sNameNoSuffix.length() - 4);
49 String sName;
50 int nDPI = -1;
51 int nPage = -1;
52 if (sDPICheck.equals("DPI_"))
54 // seems to be a generated filename by us.
55 int nDPIStart = sNameNoSuffix.lastIndexOf("_", sNameNoSuffix.length() - 8);
56 sName = sNameNoSuffix.substring(0, nDPIStart);
57 if (nDPIStart > 0)
59 String sDPI = sNameNoSuffix.substring(nDPIStart + 1, sNameNoSuffix.length() - 8);
60 try
62 nDPI = Integer.valueOf(sDPI).intValue();
64 catch (java.lang.NumberFormatException e)
66 GlobalLogWriter.println("DPI: Number format exception");
68 String sPage = sNameNoSuffix.substring(sNameNoSuffix.length() - 4);
69 try
71 nPage = Integer.valueOf(sPage).intValue();
73 catch (java.lang.NumberFormatException e)
75 GlobalLogWriter.println("Page: Number format exception");
79 else
81 sName = sNameNoSuffix;
84 return new NameDPIPage(sName, nDPI, nPage);
88 class CountNotXXXPixelsFromImage extends Thread
91 private String m_sFilename;
92 protected int m_nValue;
94 CountNotXXXPixelsFromImage(String _sFilename)
96 m_sFilename = _sFilename;
99 public int getValue()
101 return m_nValue;
104 protected void setValue(int _nValue)
106 m_nValue = _nValue;
109 protected String getFilename()
111 return m_sFilename;
115 class CountNotWhitePixelsFromImage extends CountNotXXXPixelsFromImage
118 CountNotWhitePixelsFromImage(String _sFilename)
120 super(_sFilename);
123 public void run()
127 final int nNotWhiteCount = PixelCounter.countNotWhitePixelsFromImage(getFilename());
128 setValue(nNotWhiteCount);
130 catch (java.io.IOException e)
132 m_nValue = -1;
137 class CountNotBlackPixelsFromImage extends CountNotXXXPixelsFromImage
140 CountNotBlackPixelsFromImage(String _sFilename)
142 super(_sFilename);
145 public void run()
149 final int nNotBlackCount = PixelCounter.countNotBlackPixelsFromImage(getFilename());
150 setValue(nNotBlackCount);
152 catch (java.io.IOException e)
154 m_nValue = -1;
159 public class JPEGComparator extends EnhancedComplexTestCase
162 public String[] getTestMethodNames()
164 return new String[]{"CompareJPEGvsJPEG"};
166 private Tolerance m_aTolerance;
169 * test function.
171 public void CompareJPEGvsJPEG()
173 GlobalLogWriter.set(log);
174 ParameterHelper aParam = new ParameterHelper(param);
176 // run through all documents found in Inputpath
177 foreachJPEGcompareWithJPEG(aParam);
180 public void checkOneFile(String _sDocumentName, String _sResult, ParameterHelper _aParams) throws OfficeException
182 String sPath = FileHelper.getPath(_sDocumentName);
183 String sSectionName = FileHelper.getBasename(_sDocumentName);
185 // take the build id out of the ini file in the reference file and put it into the current parameter helper
186 String sIniFileForRefBuildID = FileHelper.appendPath(sPath, sSectionName + ".ini");
187 IniFile aIniFileForRefBuildID = new IniFile(sIniFileForRefBuildID);
188 String sRefBuildID = aIniFileForRefBuildID.getValue("global", "buildid");
189 aIniFileForRefBuildID.close();
191 _aParams.getTestParameters().put("RefBuildId", sRefBuildID);
193 String sIniFile = FileHelper.appendPath(sPath, "index.ini");
194 IniFile aIniFile = new IniFile(sIniFile);
195 if (aIniFile.hasValue(sSectionName, "pages"))
197 // only which has 'pages' has also pictures
198 int nPages = aIniFile.getIntValue(sSectionName, "pages", 0);
199 String sJPEGSchema = aIniFile.getValue(sSectionName, "jpegschema");
200 int nTolerance = aIniFile.getIntValue(sSectionName, "tolerance", 0);
201 m_aTolerance = new Tolerance(nTolerance);
202 for (int i = 1; i <= nPages; i++)
204 String sJPEGFilename = JPEGCreator.getFilenameForJPEGSchema(sJPEGSchema, i);
205 String sJPEGPath = FileHelper.getPath(sJPEGFilename);
206 if (!sPath.equals(sJPEGPath))
208 GlobalLogWriter.println("Path where to find the index and where to file the JPEG pictures are not the same.");
210 File aFile = new File(sJPEGFilename);
211 assure("File '" + sJPEGFilename + "' doesn't exists.", aFile.exists(), true);
212 if (aFile.exists())
214 GlobalLogWriter.println("Page: " + i);
215 checkOnePicture(sJPEGFilename, _sResult, _aParams);
219 else
221 GlobalLogWriter.println("The document '" + sSectionName + "' seems to have no picture representation.");
224 String sResultIniFile = FileHelper.appendPath(_sResult, sSectionName);
225 evaluateResult(sResultIniFile, _aParams);
228 private void evaluateResult(String _sDocument, ParameterHelper _aParams)
230 String sResultIniFile = _sDocument + ".ini";
231 File aFile = new File(sResultIniFile);
232 assure("Result file doesn't exists " + sResultIniFile, aFile.exists());
234 int good = 0;
235 int bad = 0;
236 int ugly = 0;
237 int ok_status = 1; // 1=ok 2=bad 3=ugly
239 IniFile aResultIniFile = new IniFile(sResultIniFile);
240 int nPages = aResultIniFile.getIntValue("global", "pages", 0);
241 for (int i = 0; i < nPages; i++)
243 String sCurrentPage = "page" + String.valueOf(i + 1);
244 int nPercent = aResultIniFile.getIntValue(sCurrentPage, "percent", -1);
245 if (nPercent == 0)
247 good++;
249 else if (nPercent <= 5)
251 bad++;
252 ok_status = 2;
254 else
256 ugly++;
257 ok_status = 3;
261 assure("Error: document doesn't contains pages", nPages > 0);
263 // TODO: this information has to come out of the ini files
264 String sStatusRunThrough = "PASSED, ";
265 String sPassed = "OK";
267 String sStatusMessage = "From " + nPages + " page(s) are: ";
268 String sGood = "";
269 String sBad = "";
270 String sUgly = "";
272 if (good > 0)
274 sGood = " good:=" + good;
275 sStatusMessage += sGood;
277 if (bad > 0)
279 sBad = " bad:=" + bad;
280 sStatusMessage += sBad;
282 if (ugly > 0)
284 sUgly = " ugly:=" + ugly;
285 sStatusMessage += sUgly;
288 // Failure matrix
289 // 0 1
290 // ugly OK FAILED
291 // bad OK
292 // good OK
294 if (ugly > 0)
296 sPassed = "FAILED";
298 else
300 if (bad > 0)
302 sPassed = "NEED A LOOK";
304 else
306 sPassed = "OK";
309 sStatusRunThrough += sPassed;
310 aResultIniFile.insertValue("global", "state", sStatusRunThrough);
311 aResultIniFile.insertValue("global", "info", sStatusMessage);
312 aResultIniFile.close();
314 _aParams.getTestParameters().put("current_state", sStatusRunThrough);
315 _aParams.getTestParameters().put("current_info", sStatusMessage);
316 _aParams.getTestParameters().put("current_ok_status", ok_status);
318 // if we have a ugly page, we must return this as a FAILED STATUS in Log file!
319 assure("There exist pages marked as ugly.", ugly == 0);
322 private void checkOnePicture(String _sDocumentName, String _sResult, ParameterHelper _aParams)
324 GlobalLogWriter.println("JPEG: Compare difference between '" + _sDocumentName + "' and '" + _sResult + "'");
325 File aResultFile = new File(_sResult);
326 if (aResultFile.isDirectory())
328 // result is just a directory, so we search for the basename of the source and take this.
329 String sBasename = FileHelper.getBasename(_sDocumentName);
330 String sResultFilename = FileHelper.appendPath(_sResult, sBasename);
331 aResultFile = new File(sResultFilename);
332 if (aResultFile.exists())
334 // Original and Result exists
335 String sInputPath = _aParams.getInputPath();
336 if (sInputPath.toLowerCase().endsWith("index.ini"))
338 // special case
339 // we want to get the buildid from the info file.
342 compareJPEG(_sDocumentName, sResultFilename, _aParams);
345 else
347 String sResultFilenamePDF = util.utils.replaceAll13(sResultFilename, ".ps_", ".pdf_");
348 File aResultPDFFile = new File(sResultFilenamePDF);
349 if (aResultPDFFile.exists())
351 // Original and Result exists
352 String sInputPath = _aParams.getInputPath();
353 if (sInputPath.toLowerCase().endsWith("index.ini"))
355 // special case
356 // we want to get the buildid from the info file.
359 compareJPEG(_sDocumentName, sResultFilenamePDF, _aParams);
361 else
363 GlobalLogWriter.println("Warning: Result JPEG doesn't exists '" + sResultFilename + "'");
367 else
369 // result is also a file
370 if (aResultFile.exists())
372 compareJPEG(_sDocumentName, _sResult, _aParams);
374 else
376 GlobalLogWriter.println("Warning: Result JPEG doesn't exists '" + _sResult + "'");
382 * compare 2 JPEGs, it is a need, that both _sDocumentName and _sResultFilename exist.
383 * @param _sDocumentName
384 * @param _sResult
385 * @param _aParams
387 private void compareJPEG(String _sDocumentName, String _sResult, ParameterHelper _aParams)
389 NameDPIPage aNameDPIPage = NameDPIPage.interpret(_sDocumentName);
391 String sSourceBasename = FileHelper.getBasename(_sDocumentName);
392 String sSourcePath = FileHelper.getPath(_sDocumentName);
393 String sDestinationBasename = FileHelper.getBasename(_sResult);
394 String sDestinationPath = FileHelper.getPath(_sResult);
396 if (!sSourcePath.equals(sDestinationPath))
398 // we want to have all in one Directory, Original, Reference and the Difference result.
399 // copy the original file to the reference path
400 String sNewSourceBasename = "Original_" + sSourceBasename;
401 String sSource = _sDocumentName;
402 String sDestination = FileHelper.appendPath(sDestinationPath, sNewSourceBasename);
403 FileHelper.copy(sSource, sDestination);
404 sSourceBasename = sNewSourceBasename;
406 JPEGCreator.convertToNearSameFileWithWidth340(sDestination);
408 String sDifferenceBasename = "Difference_between_" + FileHelper.getNameNoSuffix(sSourceBasename) + "_and_" + FileHelper.getNameNoSuffix(sDestinationBasename) + ".jpg";
410 String sSource = FileHelper.appendPath(sDestinationPath, sSourceBasename);
411 String sDestination = FileHelper.appendPath(sDestinationPath, sDestinationBasename);
412 String sDifference = FileHelper.appendPath(sDestinationPath, sDifferenceBasename);
413 int nErr = compareJPEG(sSource, sDestination, sDifference);
414 if (nErr == 0 && FileHelper.exists(sDifference))
416 // check the difference, returns the count of different colors
417 // this means, 1=only one color, no differences found.
418 int nResult = identify(sDifference);
419 int nPercentColorDiffer = 0;
421 String sResult = "YES";
423 if (m_aTolerance != null)
425 final int nAcceptedTolerance = m_aTolerance.getAccept();
426 if (nResult <= nAcceptedTolerance)
428 nResult = 1;
429 sResult = "IN TOLERANCE";
430 GlobalLogWriter.println("The differences are in tolerance.");
434 if (nResult != 1)
436 sResult = "NO";
439 nPercentColorDiffer = estimateGfx(sSource, sDestination, sDifference);
441 catch (java.io.IOException e)
443 GlobalLogWriter.println("Can't estimate the different colors. " + e.getMessage());
447 // store the result in a result.ini file
448 String sResultFile = FileHelper.appendPath(sDestinationPath, aNameDPIPage.Name + ".ini");
449 int nPage = aNameDPIPage.Page;
450 if (nPage < 0)
452 nPage = 0;
454 IniFile aResultIni = new IniFile(sResultFile);
456 String[] aComment =
458 "; This file is automatically created by a graphical.JPEGComparator run",
459 "; ",
460 "; If you see this file in a browser you may have forgotten to set the follows in the property file",
461 "; " + PropertyName.DOC_COMPARATOR_HTML_OUTPUT_PREFIX + "=http://<computer>/gfxcmp_ui/cw.php?inifile=",
462 "; Please check the documentation if you got confused.",
463 "; ",
464 "; "
466 aResultIni.insertFirstComment(aComment);
468 // write down the global flags
469 int nMaxPage = Math.max(nPage, aResultIni.getIntValue("global", "pages", 0));
470 aResultIni.insertValue("global", "pages", nMaxPage);
472 String sRefBuildId = (String) _aParams.getTestParameters().get("RefBuildId");
473 if (sRefBuildId == null)
475 sRefBuildId = "";
477 aResultIni.insertValue("global", "refbuildid", sRefBuildId);
479 aResultIni.insertValue("global", "diffdiff", "no");
480 aResultIni.insertValue("global", "basename", aNameDPIPage.Name);
481 aResultIni.insertValue("global", "dpi", aNameDPIPage.DPI);
483 // write down flags for each page
484 String sSection = "page" + String.valueOf(nPage);
486 aResultIni.insertValue(sSection, "oldgfx", sSource);
487 aResultIni.insertValue(sSection, "newgfx", sDestination);
488 aResultIni.insertValue(sSection, "diffgfx", sDifference);
489 aResultIni.insertValue(sSection, "percent", nPercentColorDiffer);
490 aResultIni.insertValue(sSection, "BM", "false");
491 aResultIni.insertValue(sSection, "result", sResult);
493 aResultIni.close();
498 * count how much pixel differ and between Old or New and the Difference graphics
500 * First, count the old graphics, then the new graphics due to the fact both should be equal
501 * it should be legal to take result from old or new. We take the graphics with less values.
503 * Second, count the difference graphics, now take the percent algorithm and
504 * build a percent value, which contain the number of different pixels as a percent value
506 * Interpretation:
507 * 0% there is no difference
509 * &lt;100% Take a look into the difference graphics, maybe the difference graphics shows
510 * text like outlined or the text is little bit move left, right up or down.
512 * &gt;>100% Yes it's possible that there is a difference more then 100%, maybe a font problem
513 * between old and new graphics. The font of the new graphics is little bit bigger,
514 * so the pixel count between old graphics and new graphics is twice the more.
516 * @param _sOldGfx path & name to the jpeg file (1)
517 * @param _sNewGfx path & name to the other jpeg file (2)
518 * @param _sDiffGfx path & name to the new difference file which shows the difference between (1) and (2)
519 * @return the count of different pixels
520 * @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
525 TimeHelper a = new TimeHelper();
526 a.start();
527 // Count Pixels
528 final int nNotWhiteCount_OldGraphic = PixelCounter.countNotWhitePixelsFromImage(_sOldGfx);
529 final int nNotWhiteCount_NewGraphic = PixelCounter.countNotWhitePixelsFromImage(_sNewGfx);
530 final int nNotBlackCount_DiffGraphic = PixelCounter.countNotBlackPixelsFromImage(_sDiffGfx);
532 a.stop();
533 GlobalLogWriter.println("Thread Time is: " + a.getTime());
535 int nMinNotWhiteCount = Math.min(nNotWhiteCount_NewGraphic, nNotWhiteCount_OldGraphic);
537 // check if not zero
538 if (nMinNotWhiteCount == 0)
540 nMinNotWhiteCount = Math.max(nNotWhiteCount_NewGraphic, nNotWhiteCount_OldGraphic);
541 if (nMinNotWhiteCount == 0)
543 nMinNotWhiteCount = 1;
547 int nPercent = Math.abs(nNotBlackCount_DiffGraphic * 100 / nMinNotWhiteCount);
548 GlobalLogWriter.println("Graphics check, pixel based:" + String.valueOf(nPercent) + "% pixel differ ");
549 return nPercent;
552 private static int compareJPEG(String _sOldGfx, String _sNewGfx, String _sDiffGfx)
554 String sComposite = "composite";
555 if (OSHelper.isWindows())
557 sComposite = "composite.exe";
558 String sIMPath = (String) param.get("imagemagick.path");
559 if (sIMPath != null)
561 sComposite = FileHelper.appendPath(sIMPath, sComposite);
565 String[] sCommandArray =
567 sComposite,
568 "-compose",
569 "difference",
570 _sOldGfx,
571 _sNewGfx,
572 _sDiffGfx
575 ProcessHandler aHandler = new ProcessHandler(sCommandArray);
576 aHandler.executeSynchronously();
577 int nExitCode = aHandler.getExitCode();
578 if (nExitCode != 0)
580 GlobalLogWriter.println("'" + sComposite + "' return with ");
581 String sBack = aHandler.getOutputText();
582 GlobalLogWriter.println("'" + sBack + "'");
584 else
586 // creates an extra smaller difference picture
587 File aDiffFile = new File(_sDiffGfx);
588 if (aDiffFile.exists())
590 JPEGCreator.convertToNearSameFileWithWidth340(_sDiffGfx);
593 return nExitCode;
597 * wrapper for ImageMagick identify,
598 * function checks how many different colors a picture contains.
599 * if it's only one color (nResult==1), like background color, there is no difference.
601 int identify(String _sDiffGfx)
603 int nResult = 0;
604 // would like to know what the meaning of %k is for ImageMagick's 'identify'
605 String sIM_Format = "%k";
607 String sIdentify = "identify";
608 if (OSHelper.isWindows())
610 sIdentify = "identify.exe";
611 String sIMPath = (String) param.get("imagemagick.path");
612 if (sIMPath != null)
614 sIdentify = FileHelper.appendPath(sIMPath, sIdentify);
618 String[] sCommandArray =
620 sIdentify,
621 "-format",
622 sIM_Format,
623 _sDiffGfx
625 ProcessHandler aHandler = new ProcessHandler(sCommandArray);
626 aHandler.executeSynchronously();
627 aHandler.getExitCode();
629 String sBack = aHandler.getOutputText();
630 GlobalLogWriter.println("'" + sBack + "'");
632 // try to interpret the result, which we get as a String
635 int nIdx = sBack.indexOf("\n");
636 if (nIdx > 0)
638 sBack = sBack.substring(0, nIdx);
641 nResult = Integer.valueOf(sBack).intValue();
643 catch (java.lang.NumberFormatException e)
645 GlobalLogWriter.println("identify(): Number format exception");
646 nResult = 0;
648 return nResult;