[eyeshot]How can I add a new Viewport into a viewer - viewport

what is the best way to add a new viewport into the viewer with the same drawing?
Regards Jürgen

You can check the Custom ViewportLayout source code sample.
Here is the code extracted from the above sample
private static void InitializeViewportsByLayoutType(Design design, viewportLayoutType layout)
{
int viewportsNumber;
switch (layout)
{
case viewportLayoutType.SingleViewport:
viewportsNumber = 1;
break;
case viewportLayoutType.TwoViewportsVertical:
case viewportLayoutType.TwoViewportsHorizontal:
viewportsNumber = 2;
break;
case viewportLayoutType.ThreeViewportsWithOneOnBottom:
case viewportLayoutType.ThreeViewportsWithOneOnLeft:
case viewportLayoutType.ThreeViewportsWithOneOnRight:
case viewportLayoutType.ThreeViewportsWithOneOnTop:
viewportsNumber = 3;
break;
case viewportLayoutType.FourViewports:
case viewportLayoutType.Stacked:
viewportsNumber = 4;
break;
default:
viewportsNumber = 1;
break;
}
if (design.Viewports.Count > viewportsNumber)
{
while (design.Viewports.Count > viewportsNumber)
design.Viewports.RemoveAt(design.Viewports.Count - 1);
}
else
{
while (design.Viewports.Count < viewportsNumber)
{
design.Viewports.Add((Viewport)design.Viewports[0].Clone());
}
}
// When changing the LayoutMode, the UpdateViewportsSizeAndLocation() method is called as well.
design.LayoutMode = layout;
}

Related

Cell note in jxls template is not deleted

PoiTransformer transformer = PoiTransformer.createTransformer(is, os);
AreaBuilder areaBuilder = new XlsCommentAreaBuilder(transformer, false);
List<Area> xlsAreaList = areaBuilder.build();
int curSheetSize = 3;
for(int i = 1; i < 1; i++) {
Area mainArea = xlsAreaList.get(i);
Area loopArea = mainArea.getCommandDataList().get(0).getCommand().getAreaList().get(0);
loopArea.addAreaListener(new JxlsAreaListener(transformer, i));
switch (i) {
case 1 :
mainArea.applyAt(new CellRef("KOR!A1"), context);
break;
case 2 :
mainArea.applyAt(new CellRef("JPN!A1"), context);
break;
case 3 :
mainArea.applyAt(new CellRef("FRA!A1"), context);
break;
case 4 :
mainArea.applyAt(new CellRef("AUS!A1"), context);
break;
case 5 :
mainArea.applyAt(new CellRef("UK!A1"), context);
break;
case 6 :
mainArea.applyAt(new CellRef("CAN!A1"), context);
break;
case 7 :
mainArea.applyAt(new CellRef("MEX!A1"), context);
break;
}
mainArea.processFormulas();
}
transformer.write();
is.close();
os.close();
I hope the memo is deleted in the Excel file made from template. please.
is templete
enter image description here
is Files created from templates
enter image description here

QLineEdit and QComboBox have unrelated behavior

I have a user interface with a lot of controls. However I have a problem with a QLineEdit and a QComboBox that are not responding properly.
I am basically converting from pixel measurements to millimeters/centimeters/decimeters and meters with a QComboBox and showing the result on a QLineEdit.
For the conversion table I used this page.
When I choose fromPixelToMillimeters() it does the conversion, but when I choose fromPixelToCentimeters() I think it is using the present value after the first conversion of fromPixelToMillimeters(). And if I go back choosing fromPixelToMillimeters() I get a different result too. This happens continuously, I get different measures each time.
See the code below:
void MainWindow::on_cBoxMeasures_currentIndexChanged(const QString &arg1)
{
if(arg1 == "Select Conversion(s)") {
return ui->leftLineEditDist->setText(QString("%1").arg(ui->leftLineEditDist->text().toDouble()));
} else if(arg1 == "pixel") {
return ui->leftLineEditDist->setText(QString("%1").arg(ui->leftLineEditDist->text().toDouble()));
} else if(arg1 == "mm") {
return fromPixelToMillimeters();
} else if(arg1 == "dm") {
return fromPixelToDecimeters();
} else if(arg1 == "cm") {
return fromPixelToCentimeters();
} else if(arg1 == "m") {
return fromPixelToMeters();
}
}
void MainWindow::fromPixelToMillimeters()
{
double mm = ui->leftLineEditDist->text().toDouble();
double dpi = 300;
double totalDistanceInMillimeter = (mm*25.4)/dpi;
ui->leftLineEditDist->setText(QString("%1").arg(totalDistanceInMillimeter));
ui->leftLineEditDist->show();
}
void MainWindow::fromPixelToCentimeters()
{
double mm = ui->leftLineEditDist->text().toDouble();
double dpi = 300;
double totalDistanceInCm = ((mm*25.4)/dpi)*0.1;
ui->leftLineEditDist->setText(QString("%1").arg(totalDistanceInCm));
ui->leftLineEditDist->show();
}
void MainWindow::fromPixelToDecimeters()
{
double mm = ui->leftLineEditDist->text().toDouble();
double dpi = 300;
double totalDistanceInDcm = ((mm*25.4)/dpi)*0.01;
ui->leftLineEditDist->setText(QString("%1").arg(totalDistanceInDcm));
ui->leftLineEditDist->show();
}
void MainWindow::fromPixelToMeters()
{
double mm = ui->leftLineEditDist->text().toDouble();
double dpi = 300;
double totalDistanceInM = ((mm*25.4)/dpi)*0.001;
ui->leftLineEditDist->setText(QString("%1").arg(totalDistanceInM));
ui->leftLineEditDist->show();
}
void MainWindow::on_cBoxMeasures_currentIndexChanged(int index)
{
switch (index) {
case(0):
break;
case(1):
break;
case(2):
fromPixelToMillimeters();
break;
case(3):
fromPixelToCentimeters();
break;
case(4):
fromPixelToDecimeters();
break;
case(5):
fromPixelToMeters();
break;
}
}
Please advise on what the problem might be.
I think these slots
on_cBoxMeasures_currentIndexChanged(const QString &arg1)
on_cBoxMeasures_currentIndexChanged(int index)
are connected the onIndexChange signal.
When the combo value will be changed, these two slots will be called simultaneously.
So that your code wont work well.
I recommend you to remove one of these slots.

Efficient algorithm to generate a kind of maze

I have done a lot of searching for this and have found lots of help to generate a maze, but I have a very specific requirement and all the loops Iv tried have failed horribly.
I created an editor where I could draw what I need, but a generator would help a great deal and this has failed.
Requirement:
Given a square grid of DIV elements (no smaller than 10x10 and no larger than 60x60) I need a joined path through and around the grid that will not touch itself at any point except at start/finish.
There must always be at least one blank square between all path squares (any number of blanks is fine so long as the path never comes into contact with itself).
There can be no dead ends and no loops (Where the path would cross itself).
This is kind of like a reverse maze - I do not need to fill the entire grid, in fact I have no problem with lots of space around the path. It might be easier to think of this along similar lines to a Monopoly board game where the path around the board wanders about instead of going around the edges. I'm actually stuck for an adequate description, hence calling it a reverse maze.
Things I tried:
Lots and lots of overly complex loops. Iv not really come very close and the issue is also one of performance.
Lots and lots of code designed to generate a maze. Some of these have been very good indeed, but they all generate a typical maze, which is not what I need at all really, and adapting the code has proven trickier than writing an insane set of loops within loops.
Any ideas would be helpful. Thanks.
Update Code
Okay, I have translated KIKO's PHP code into Javascript but somewhere along the line I have made a simple error that I cannot track down: The code works and generates a table of the correct dimensions and generates a path through it.
However, in the function "isWithinGrid" I have to subtract 1 from the width and height of the table or the entire thing will fail, and, if I do this, the code will work and created a path through the table minus one cell which will be incorrectly colored although clearly a part of the path.
Note that sometimes the path will be broken or touching itself. I have little doubt that some small problem is causing all of this, but currently this is the best I have come up with and any further help would be much appreciated.
class Grid{
constructor(width,height){
this.width = width;
this.height = height;
this.cells = [];
for(var x=0; x < this.width; x++){
var tmparray = [];
for(var y=0; y < this.height; y++){
tmparray.push(false);
}
this.cells.push(tmparray);
}
}
isWithinGrid(x,y){
return (x >= 0) && (x <= this.width-1) && (y >= 0) && (y <= this.height-1);
}
isWithinPath(x,y){
return this.isWithinGrid(x,y) && this.cells[x][y];
}
setCellInPath(x,y,boolean){
this.cells[x][y] = boolean;
return this;
}
drawHorizontalLine(x1,x2,y){
for(var x=x1; x < x2; x++){
this.setCellInPath(x,y,true);
}
return this;
}
drawVerticalLine(x,y1,y2){
for(var y=y1; y < y2; y++){
this.setCellInPath(x,y,true);
}
return this;
}
drawSquare(){
var left = Math.round(this.width/5);
var right = Math.round(4*this.width/5);
var top = Math.round(this.height/5);
var bottom = Math.round(4*this.height/5);
this.drawHorizontalLine(left,right,top)
.drawHorizontalLine(left,right,bottom)
.drawVerticalLine(left,top,bottom)
.drawVerticalLine(right,top,bottom);
return this;
}
moveCell(x,y,dx,dy){
this.setCellInPath(x,y,false);
this.setCellInPath(x+dx,y+dy,true);
}
canMoveCell(x,y,dx,dy){
return this.isWithinPath(x,y) &&
this.isWithinGrid(x+dx,y+dy) &&
!this.isWithinPath(x+dx,y+dy) &&
!this.isWithinPath(x+2*dx,y+2*dy) &&
!this.isWithinPath(x+dy+dx,y+dx+dy)
!this.isWithinPath(x-dy+dx,y-dx+dy);
}
tryToDistortOnce(x,y,dx,dy){
if (!this.canMoveCell(x,y,dx,dy)) return false;
if (!this.canMoveCell(x+dy,y+dx,dx,dy)) return false;
if (!this.canMoveCell(x-dy,y-dx,dx,dy)) return false;
this.moveCell(x,y,dx,dy);
this.setCellInPath(x+dy+dx,y+dx+dy,true);
this.setCellInPath(x-dy+dx,y-dx+dy,true);
return true;
}
distortOnce(){
var x=0, y=0, dx=0, dy=0;
do {
x = Math.floor(Math.random() * this.width) + 1;
y = Math.floor(Math.random() * this.height) + 1;
} while (!this.isWithinPath(x,y));
switch (Math.floor(Math.random() * 4) + 1){
case 1: dx = -1; dy = 0; break;
case 2: dx = +1; dy = 0; break;
case 3: dx = 0; dy = +1; break;
case 4: dx = 0; dy = -1; break;
}
if (this.tryToDistortOnce(x,y,dx,dy)){
do {
x += dx;
y += dy;
} while (this.tryToDistortOnce(x,y,dx,dy));
return true;
}
return false;
}
distortPath(numberOfDistortions = 10){
for(var counter=1; counter < numberOfDistortions; counter++){
var tries = 0;
while (!this.distortOnce() && (tries < this.width+this.height)){ tries++; }
}
return this;
}
renderGrid(){
var str = '<table class="TSTTAB">';
for(var y=0; y < this.width; y++){
for(var x=0; x < this.height; x++){
str += '<td'+(this.cells[y][x] ? ' class="path">' : '>');
}
str += '</tr>';
}
str += '</table>';
document.getElementById('cont').innerHTML =str;
return this;
}
}
var Testgrid = new Grid(20,20);
Testgrid.drawSquare().distortPath(10).renderGrid();
.TSTTAB{background-color:#7F7F7F;border-collapse:collapse;}
.TSTTAB td{ width:20px; height: 20px; border: 1px solid #000;background-color: #E5E5E5; }
.TSTTAB td.path { background-color: #44F; }
<div id='cont'></div>
Well, I've given it a try. One hour of work seems more than enough for a simple question. It is, of course, far from perfect, but it illustrates what I was talking about. It generates solutions like this:
The complete code is:
<?php
// error reporting
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// configuration
const SIZE_X = 20;
const SIZE_Y = 20;
const COMPLEXITY = 20;
// grid class
class Grid
{
public function __construct($width,$height)
{
// remember
$this->width = $width;
$this->height = $height;
// initiate grid
foreach (range(1,$width) as $x) {
foreach (range(1,$height) as $y) {
$this->cells[$x][$y] = FALSE; // false means: not in path
}
}
}
public function isWithinGrid($x,$y)
// testb whether (x,y) is within the grid
{
return ($x >= 1) && ($x <= $this->width) &&
($y >= 1) && ($y <= $this->height);
}
public function isWithinPath($x,$y)
// is a cell part of the path?
{
return $this->isWithinGrid($x,$y) && $this->cells[$x][$y];
}
public function setCellInPath($x,$y,$boolean)
// remember whether a cell is part of the path or not
{
$this->cells[$x][$y] = $boolean;
return $this;
}
public function drawHorizontalLine($x1,$x2,$y)
// simple horizontal line
{
foreach (range($x1,$x2) as $x) $this->setCellInPath($x,$y,TRUE);
return $this;
}
public function drawVerticalLine($x,$y1,$y2)
// simple vertical line
{
foreach (range($y1,$y2) as $y) $this->setCellInPath($x,$y,TRUE);
return $this;
}
public function drawSquare()
// simple square
{
$left = round($this->width/5);
$right = round(4*$this->width/5);
$top = round($this->height/5);
$bottom = round(4*$this->height/5);
$this->drawHorizontalLine($left,$right,$top)
->drawHorizontalLine($left,$right,$bottom)
->drawVerticalLine($left,$top,$bottom)
->drawVerticalLine($right,$top,$bottom);
return $this;
}
private function moveCell($x,$y,$dx,$dy)
// move a cell
{
$this->setCellInPath($x,$y,FALSE);
$this->setCellInPath($x+$dx,$y+$dy,TRUE);
}
private function canMoveCell($x,$y,$dx,$dy)
// answers the question whether or not we can move (x,y) by (dx,dy)
{
return $this->isWithinPath($x,$y) && // must be part of path
$this->isWithinGrid($x+$dx,$y+$dy) && // stay within grid
!$this->isWithinPath($x+$dx,$y+$dy) && // but not on the path
!$this->isWithinPath($x+2*$dx,$y+2*$dy) && // and don't touch path
!$this->isWithinPath($x+$dy+$dx,$y+$dx+$dy) && // and don't touch path
!$this->isWithinPath($x-$dy+$dx,$y-$dx+$dy); // and don't touch path
}
private function tryToDistortOnce($x,$y,$dx,$dy)
{
// this one should be able to move
if (!$this->canMoveCell($x,$y,$dx,$dy)) return FALSE;
// but also its neighbours must be able to move
if (!$this->canMoveCell($x+$dy,$y+$dx,$dx,$dy)) return FALSE;
if (!$this->canMoveCell($x-$dy,$y-$dx,$dx,$dy)) return FALSE;
// move the target cell by displacement
$this->moveCell($x,$y,$dx,$dy);
// move neighbours by adding two cells
$this->setCellInPath($x+$dy+$dx,$y+$dx+$dy,TRUE);
$this->setCellInPath($x-$dy+$dx,$y-$dx+$dy,TRUE);
return TRUE; // success!
}
private function distortOnce()
// distort a random cell, returns success or failure
{
// find a random cell in path
do {
$x = rand(1,$this->width);
$y = rand(1,$this->height);
} while (!$this->isWithinPath($x,$y));
// choose one of four directions to move in
switch (rand(1,4))
{
case 1: $dx = -1; $dy = 0; break;
case 2: $dx = +1; $dy = 0; break;
case 3: $dx = 0; $dy = +1; break;
case 4: $dx = 0; $dy = -1; break;
}
// try to do it
if ($this->tryToDistortOnce($x,$y,$dx,$dy))
{
// more moves
do {
$x += $dx;
$y += $dy;
} while ($this->tryToDistortOnce($x,$y,$dx,$dy));
return TRUE; // it was a success!
}
return FALSE; // we failed
}
public function distortPath($numberOfDistortions = 10)
// distort up to a certain amount of times
{
// find a random cell that is part of the path to distort
for ($counter = 1; $counter <= $numberOfDistortions; $counter++) {
// we try that a limited number of times, depending on the grid size
$tries = 0;
while (!$this->distortOnce() &&
($tries < $this->width+$this->height)) { $tries++; }
}
return $this;
}
public function renderGrid()
// render grid
{
echo '<!DOCTYPE HTML><html><head><style>'.
' td { width:20px; height: 20px; border: 1px solid #000; }'.
' .path { background-color: #44F; }'.
'</style></head><body><table>';
foreach (range(1,SIZE_Y) as $y) {
echo '<tr>';
foreach (range(1,SIZE_X) as $x) {
echo '<td'.($this->cells[$x][$y] ? ' class="path">' : '>');
}
echo '</tr>';
}
echo '</body></html></table>';
return $this;
}
}
// create grid
$grid = new Grid(SIZE_X,SIZE_Y);
// start with a square, distort and then render
$grid->drawSquare()
->distortPath(COMPLEXITY)
->renderGrid();
There are lots of things you can do to improve on this.... have fun!
On my server this code takes between 2 and 5 milliseconds to execute. Mileage may vary...

How to change height of edit box associated with CMFCToolbarEditBoxButton

I would like to decrease the height of the edit box associated with a CMFCToolbarEditBoxButton on a CMFCToolBar.
I have been able to change successfully the height of a combo box associated with CMFCToolbarComboBoxButton by changing the font size after the ReplaceButton step in OnToolbarReset.
This approach doesn't work for CMFCToolbarEditBoxButton. (see CGuiEditBox section in the following code.)
The first code is from OnToolbarSet. I assign a font to the edit box. I even tried making the size of the font very small. It had no effect.
Next I tried to change the rectangle associated with the edit box in the toolbar's AdjustLocations method. That approach also was unsuccessful.
LRESULT CMainFrame::OnToolbarReset(WPARAM wp, LPARAM)
{
UINT uiToolBarId = (UINT)wp;
switch (uiToolBarId)
{
case IDR_TOPTOOLBAR_REG:
{
CZoomCombo ZoomCombo;
ZoomCombo.EnableWindow(TRUE);
ZoomCombo.SetDropDownHeight(300);
ZoomCombo.SetCenterVert(TRUE);
ZoomCombo.AddItem(_T(".5x"));
ZoomCombo.AddItem(_T("1x"));
ZoomCombo.AddItem(_T("2x"));
ZoomCombo.AddItem(_T("3x"));
ZoomCombo.AddItem(_T("4x"));
ZoomCombo.AddItem(_T("5x"));
ZoomCombo.AddItem(_T("6x"));
ZoomCombo.AddItem(_T("7x"));
ZoomCombo.AddItem(_T("8x"));
ZoomCombo.AddItem(_T("9x"));
ZoomCombo.AddItem(_T("10x"));
m_wndTopToolBar.ReplaceButton(IDC_ZOOMCOMBO_DUMMY, ZoomCombo);
do
{
CMFCToolBarButton* pButton = NULL;
int nZoomIndex = m_wndTopToolBar.CommandToIndex(IDC_ZOOMCOMBO);
if (nZoomIndex == -1)
break;
pButton = m_wndTopToolBar.GetButton(nZoomIndex);
if (pButton == NULL)
break;
ASSERT(pButton->IsKindOf(RUNTIME_CLASS(CMFCToolBarComboBoxButton)));
CMFCToolBarComboBoxButton* pComboButton = (CMFCToolBarComboBoxButton*)pButton;
CComboBox* pCbo = pComboButton->GetComboBox();
CEdit* pEdit = pComboButton->GetEditCtrl();
if (pCbo == NULL || pEdit == NULL)
break;
pCbo->SetFont(&m_ToolBarBtnFont);
pEdit->SetFont(&m_ToolBarBtnFont);
m_wndTopToolBar.InvalidateButton(nZoomIndex);
int nSel = GetZoomComboIndex(m_Zoom);
if (nSel >= 0)
{
pCbo->SetCurSel(nSel);
CString str;
pCbo->GetWindowText(str);
pComboButton->SetText(str);
}
} while (false);
//
CGuiEditBox GuiEditBox;
GuiEditBox.EnableWindow(TRUE);
m_wndTopToolBar.ReplaceButton(IDC_GUIEDITBOX_DUMMY, GuiEditBox);
do
{
CMFCToolBarButton* pButton = NULL;
int nGuiIndex = m_wndTopToolBar.CommandToIndex(IDC_GUIEDITBOX);
if (nGuiIndex == -1)
break;
pButton = m_wndTopToolBar.GetButton(nGuiIndex);
if (pButton == NULL)
break;
ASSERT(pButton->IsKindOf(RUNTIME_CLASS(CMFCToolBarEditBoxButton)));
CMFCToolBarEditBoxButton* pEditBoxButton = (CMFCToolBarEditBoxButton*)pButton;
CEdit* pEdit = pEditBoxButton->GetEditBox();
if (pEdit == NULL)
break;
pEdit->SetFont(&m_ToolBarBtnFont); // height of this font is much less than default
//CFont* pFont = pEdit->GetFont();
//LOGFONT lf;
//pFont->GetLogFont(&lf); // confirmed that font has been changed
m_wndTopToolBar.InvalidateButton(nGuiIndex);
} while (false);
}
break;
}
return 0;
}
//
void CMFCToolBarEx::AdjustLocations()
{
CMFCToolBar::AdjustLocations();
if (GetSafeHwnd())
{
CMFCToolBarButton* pButton = NULL;
int nGuiIndex = CommandToIndex(IDC_GUIEDITBOX);
if (nGuiIndex != -1)
{
pButton = GetButton(nGuiIndex);
if (pButton)
{
ASSERT(pButton->IsKindOf(RUNTIME_CLASS(CMFCToolBarEditBoxButton)));
CMFCToolBarEditBoxButton* pEditBoxButton = (CMFCToolBarEditBoxButton*)pButton;
CEdit* pEdit = pEditBoxButton->GetEditBox();
if (pEdit != NULL)
{
CRect rPos;
pEdit->GetRect(&rPos);
rPos.DeflateRect(0, 4);
pEdit->SetRect(rPos);
}
}
}
}
}
I investigated the source code for afxtoolbareditboxbutton.cpp and saw that the height of the edit box is being set in the OnMove method by the following line
int cy = GetGlobalData()->GetTextHeight();
I changed that line in a subclass of CMFCToolBarEditBoxButton to resolve my problem.

In Selenium, how to compare images?

As i have been asked to automate our Company's website using Selenium Automation tooL.
But i am new to Selenium tool to proceed with, but i have learnt the basics of Selenium IDE and RC. But i am very much confused with how to compare actual and original images as we usually do in other automation tools. How do we come to a result that there bug in the website? Its obviously through image comparison but i wonder as selenium is one of the very popular tools but it doesn't have image comparing option. On the other hand i doubt whether my way of proceeding with the automation process is correct! Could somebody please help me out..
Thanks in Advance!!
Sanjay S
I had simillar task. I needed to compare more than 3000 images on a WebPage.
First of all I scrolled page to load all images:
public void compareImage() throws InterruptedException {
driver.get(baseUrl);
driver.manage().window().maximize();
JavascriptExecutor executor = (JavascriptExecutor) driver;
Long previousHeight;
Long currentHeight;
do {
previousHeight = (Long) executor.executeScript("return document.documentElement.scrollHeight");
executor.executeScript("window.scrollBy(0, document.documentElement.scrollHeight)");
Thread.sleep(500);
currentHeight = (Long) executor.executeScript("return document.documentElement.scrollHeight");
} while (Long.compare(previousHeight, currentHeight) != 0);
after I compared size of all images with first image(or you can just write size):
List<WebElement> images = driver.findElements(By.cssSelector("img[class='playable']"));
List<String> errors = new LinkedList<>();
int imgWidth, imgHeight, elWidth, elHeight;
int imgNum = 0;
imgWidth = images.get(0).getSize().getWidth();
imgHeight = images.get(0).getSize().getHeight();
for (WebElement el : images) {
imgNum++;
elWidth = el.getSize().getWidth();
elHeight = el.getSize().getHeight();
if (imgWidth != elWidth || imgHeight != elHeight) {
errors.add(String.format("Picture # %d has incorrect size (%d : %d) px"
, imgNum, elWidth, elHeight));
}
}
for (String str : errors)
System.out.println(str);
if (errors.size() == 0)
System.out.println("All images have the same size");
}
Since you mention knowledge about Selenium RC, you can easily extend Selenium's capability using a library for your chosen programming language. For instance, in Java you can use the PixelGrabber class for comparing two images and assert their match.
imagemagick and imagediff are also two good tools to use for image matching. You would require Selenium RC and a programming language knowledge to work with it.
Image comparison on C#. To get exact results I recommend to disable anti aliasing browser feature before taking screenshots, otherwise pixels each time are a little bit different drawn. For example HTML canvas element options.AddArgument("disable-canvas-aa");
private static bool ImageCompare(Bitmap bmp1, Bitmap bmp2, Double TolerasnceInPercent)
{
bool equals = true;
bool flag = true; //Inner loop isn't broken
//Test to see if we have the same size of image
if (bmp1.Size == bmp2.Size)
{
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
Color Bitmap1 = bmp1.GetPixel(x, y);
Color Bitmap2 = bmp2.GetPixel(x, y);
if (Bitmap1.A != Bitmap2.A)
{
if (!CalculateTolerance(Bitmap1.A, Bitmap2.A, TolerasnceInPercent))
{
flag = false;
equals = false;
break;
}
}
if (Bitmap1.R != Bitmap2.R)
{
if (!CalculateTolerance(Bitmap1.R, Bitmap2.R, TolerasnceInPercent))
{
flag = false;
equals = false;
break;
}
}
if (Bitmap1.G != Bitmap2.G)
{
if (!CalculateTolerance(Bitmap1.G, Bitmap2.G, TolerasnceInPercent))
{
flag = false;
equals = false;
break;
}
}
if (Bitmap1.B != Bitmap2.B)
{
if (!CalculateTolerance(Bitmap1.B, Bitmap2.B, TolerasnceInPercent))
{
flag = false;
equals = false;
break;
}
}
}
if (!flag)
{
break;
}
}
}
else
{
equals = false;
}
return equals;
}
This C# function calculates tolerance
private static bool CalculateTolerance(Byte FirstImagePixel, Byte SecondImagePixel, Double TolerasnceInPercent)
{
double OneHundredPercent;
double DifferencesInPix;
double DifferencesPercentage;
if (FirstImagePixel > SecondImagePixel)
{
OneHundredPercent = FirstImagePixel;
}
else
{
OneHundredPercent = SecondImagePixel;
}
if (FirstImagePixel > SecondImagePixel)
{
DifferencesInPix = FirstImagePixel - SecondImagePixel;
}
else
{
DifferencesInPix = SecondImagePixel - FirstImagePixel;
}
DifferencesPercentage = (DifferencesInPix * 100) / OneHundredPercent;
DifferencesPercentage = Math.Round(DifferencesPercentage, 2);
if (DifferencesPercentage > TolerasnceInPercent)
{
return false;
}
return true;
}

Resources