Roll src/third_party/WebKit 318ad17:e6ddb0d (svn 202527:202532)
[chromium-blink-merge.git] / third_party / fuzzymatch / fuzzymatch.c
blobc68fcf7357399f1ffda8601b472b02d8a50db7fa
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /* Fuzzy pixel test matching.
7 * This is designed to compare two layout test images (RGB 800x600) and manage
8 * to ignore the noise caused by the font renderers choosing slightly different
9 * pixels.
11 * A B
12 * | |
13 * |--->delta<---|
14 * |
15 * V
16 * gray
17 * |
18 * V
19 * binary
20 * |
21 * |-------------|
22 * | |
23 * 1x3 3x1 Morphological openings
24 * | |
25 * |-----OR------|
26 * |
27 * V
28 * count pixels
30 * The result is that three different pixels in a row (vertically or
31 * horizontally) will cause the match to fail and the binary exits with code 1.
32 * Otherwise the binary exists with code 0.
34 * This requires leptonica to be installed. On Ubuntu do
35 * # apt-get install libleptonica libleptonica-dev libtiff4-dev
37 * Build with:
38 * % gcc -o fuzzymatch fuzzymatch.c -llept -ljpeg -ltiff -lpng -lz -lm -Wall -O2
40 * Options:
41 * --highlight: write highlight.png which is a copy of the first image
42 * argument where the differing areas (after noise removal) are ringed
43 * in red
44 * --no-ignore-scrollbars: usually the rightmost 15px of the image are
45 * ignored to account for scrollbars. Use this flag to include them in
46 * consideration
49 #include <unistd.h>
50 #include <stdio.h>
51 #include <leptonica/allheaders.h>
53 static int
54 usage(const char *argv0) {
55 fprintf(stderr, "Usage: %s [--highlight] [--no-ignore-scrollbars] "
56 "[--output filename] "
57 "<input a> <input b>\n", argv0);
58 return 1;
61 int
62 main(int argc, char **argv) {
63 if (argc < 3)
64 return usage(argv[0]);
66 char highlight = 0;
67 char ignore_scrollbars = 1;
68 /* Default output filename; can be overridden by command line. */
69 const char *output_filename = "highlight.png";
71 int argi = 1;
73 for (; argi < argc; ++argi) {
74 if (strcmp("--highlight", argv[argi]) == 0) {
75 highlight = 1;
76 } else if (strcmp("--no-ignore-scrollbars", argv[argi]) == 0) {
77 ignore_scrollbars = 0;
78 } else if (strcmp("--output", argv[argi]) == 0) {
79 if (argi + 1 >= argc) {
80 fprintf(stderr, "missing argument to --output\n");
81 return 1;
83 output_filename = argv[++argi];
84 } else {
85 break;
89 if (argc - argi < 2)
90 return usage(argv[0]);
92 PIX *a = pixRead(argv[argi]);
93 PIX *b = pixRead(argv[argi + 1]);
95 if (!a) {
96 fprintf(stderr, "Failed to open %s\n", argv[argi]);
97 return 1;
100 if (!b) {
101 fprintf(stderr, "Failed to open %s\n", argv[argi + 1]);
102 return 1;
105 if (pixGetWidth(a) != pixGetWidth(b) ||
106 pixGetHeight(a) != pixGetHeight(b)) {
107 fprintf(stderr, "Inputs are difference sizes\n");
108 return 1;
111 PIX *delta = pixAbsDifference(a, b);
112 pixInvert(delta, delta);
113 if (!highlight)
114 pixDestroy(&a);
115 pixDestroy(&b);
117 PIX *deltagray = pixConvertRGBToGray(delta, 0, 0, 0);
118 pixDestroy(&delta);
120 PIX *deltabinary = pixThresholdToBinary(deltagray, 254);
121 PIX *deltabinaryclipped;
122 const int clipwidth = pixGetWidth(deltabinary) - 15;
123 const int clipheight = pixGetHeight(deltabinary) - 15;
125 if (ignore_scrollbars && clipwidth > 0 && clipheight > 0) {
126 BOX *clip = boxCreate(0, 0, clipwidth, clipheight);
128 deltabinaryclipped = pixClipRectangle(deltabinary, clip, NULL);
129 boxDestroy(&clip);
130 pixDestroy(&deltabinary);
131 } else {
132 deltabinaryclipped = deltabinary;
133 deltabinary = NULL;
136 PIX *hopened = pixOpenBrick(NULL, deltabinaryclipped, 3, 1);
137 PIX *vopened = pixOpenBrick(NULL, deltabinaryclipped, 1, 3);
138 pixDestroy(&deltabinaryclipped);
140 PIX *opened = pixOr(NULL, hopened, vopened);
141 pixDestroy(&hopened);
142 pixDestroy(&vopened);
144 l_int32 count;
145 pixCountPixels(opened, &count, NULL);
146 fprintf(stderr, "%d\n", count);
148 if (count && highlight) {
149 PIX *d1 = pixDilateBrick(NULL, opened, 7, 7);
150 PIX *d2 = pixDilateBrick(NULL, opened, 3, 3);
151 pixInvert(d2, d2);
152 pixAnd(d1, d1, d2);
153 pixPaintThroughMask(a, d1, 0, 0, 0xff << 24);
154 pixWrite(output_filename, a, IFF_PNG);
157 return count > 0;