Skip to content

Commit 304ede1

Browse files
committed
Implement a merge driver for loss-less image files.
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
1 parent e1010af commit 304ede1

2 files changed

Lines changed: 76 additions & 2 deletions

File tree

contrib/imgdiff/README

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
This directory contains facilities that allow to highlight changes
2-
between two images.
2+
between two images and to perform a 3-way merge of images.
33

44
Prerequisites
55
-------------
@@ -10,7 +10,7 @@ ImageMagick - http://www.imagemagick.org/script/download.php
1010
Installation
1111
------------
1212

13-
Copy the file imgdiff into a directory that is in your PATH
13+
Copy the files imgdiff and imgmerge into a directory that is in your PATH.
1414

1515

1616
Usage
@@ -33,3 +33,27 @@ are supported that your ImageMagick installation supports.
3333
You can also run the program from the command line like this:
3434

3535
$ imgdiff pictureold.png picturenew.png
36+
37+
Activate imgmerge in your repository
38+
39+
40+
a. Define a custom merge driver:
41+
42+
$ git config merge.imgmerge.name "image merge driver"
43+
$ git config merge.imgmerge.driver "imgmerge %O %A %B %A"
44+
45+
b. Use the custom driver for your images, i.e. put
46+
a line like this in your .git/info/attributes:
47+
48+
*.png merge=imgmerge
49+
50+
You can also run the merge driver from the command line like this:
51+
52+
$ imgmerge base.png ours.png theirs.png result.png
53+
54+
The merge algorithm produces no conflict if the changes on the branches
55+
("base" to "ours" vs. "base" to "theirs") are on disjoint sets of
56+
pixels. If the branches modify the same pixel, then this results in a
57+
conflict, and the conflicting pixels are set to "ours".
58+
59+
The merge does not work with images that have an alpha channel.

contrib/imgdiff/imgmerge

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/bin/bash
2+
3+
if test $# -ne 4; then
4+
echo >&2 "usage: $0 base ours theirs result"
5+
exit 2
6+
fi
7+
8+
base=$1
9+
ours=$2
10+
theirs=$3
11+
result=$4
12+
13+
mask_bo=$result.mask-bo$$.bmp
14+
mask_bo_neg=$result.mask-bon$$.bmp
15+
mask_bt=$result.mask-bt$$.bmp
16+
mask_both=$result.mask-both$$.ppm
17+
18+
tmp1=$result.tmp1$$.bmp
19+
tmp2=$result.tmp2$$.bmp
20+
21+
# the formula is:
22+
#
23+
# mask = | ours-base |
24+
# result = ours * (mask) + theirs * (1-mask)
25+
26+
# $1,$2...images to compare, $3...resulting mask file
27+
# sets all pixels to white where the two images differ
28+
# and all pixels to black where they are identical
29+
make_diff_mask ()
30+
{
31+
composite -compose difference "$1" "$2" "$3" &&
32+
33+
# if the first -level operation were dropped, then the conversion
34+
# to gray-scale could map pixels with only a tiny difference to black
35+
convert "$3" -level 0,1 -colorspace GRAY -level 0,1 "$3"
36+
}
37+
38+
trap 'rm -f "$mask_bt" "$mask_bo" "$mask_bo_neg" "$tmp1" "$tmp2" "$mask_both"' 0
39+
40+
make_diff_mask "$theirs" "$base" "$mask_bt" &&
41+
make_diff_mask "$ours" "$base" "$mask_bo" &&
42+
convert "$mask_bo" -negate "$mask_bo_neg" &&
43+
44+
composite -compose multiply "$ours" "$mask_bo" "$tmp1" &&
45+
composite -compose multiply "$theirs" "$mask_bo_neg" "$tmp2" &&
46+
composite -compose plus "$tmp1" "$tmp2" "$result" &&
47+
48+
composite -compose multiply "$mask_bt" "$mask_bo" -compress None "$mask_both" || exit 2
49+
50+
test -z "$(sed -n -e '1,3d' -e '/65535/{p;q;}' < "$mask_both")"

0 commit comments

Comments
 (0)