XOR two monochrome images

28

6

Challenge:

Take input of two black and white (monochrome) images and xor each pixel of the first, with each pixel of the second, add them to a new image and output the new image.

Some clarifications:

Size of pictures does not matter. Extension/Image format doesn't matter. You can make it take input any extension and output any extension, as long as the extension is used to store digital images. You can also use graphics to draw the output in eg: a picturebox if you wish. Otherwise, save the output as a file. Input can be taken as a path to the image, or url.

One thing you can't do however, is I/O arrays, eg. of triplets(R,G,B).

Do NOT tamper with alpha. It should not be xored, it should be 255 (max value) for every pixel.

What do you mean xor each pixel?

You don't have to do it this way, but one way to xor two pixels is to take their RGB values and xor R1 with R2, G1 with G2, B1 with B2, and take the result, which is your new color

Since we have only two colors, obviously when the colors are the same the result would be (0,0,0) and when they are different (white is 255,255,255 and black is 0,0,0) in this case, the result would be 255,255,255.

Thus when two pixels are different, the result is a white pixel, else a black pixel

Example I/O:


Input 1: Input 2:

Input 1 Input 2


Output:

Output


This is so shortest code wins.

P. Ktinos

Posted 2017-01-15T17:07:40.113

Reputation: 2 742

Can we take the input image as a URL? – user41805 – 2017-01-15T17:11:05.940

@KritixiLithos yup, I edited it in the challenge for any further viewers. – P. Ktinos – 2017-01-15T17:14:17.633

5

Bonus challenge: http://i.imgur.com/a0M6o9e.png and http://i.imgur.com/bP1TsjQ.png.

– orlp – 2017-01-15T17:26:07.387

May we read/write matrices of (R, G, B) triplets?

– Lynn – 2017-01-15T17:28:46.363

@orlp I got up to the qr code – user41805 – 2017-01-15T17:29:55.717

@Lynn No, simply because it is tagged "image-processing" and graphical-output. You need to output an image, and take an image. Otherwise the challenge would be xor two arrays. – P. Ktinos – 2017-01-15T17:30:38.223

@P.Ktinos Then you need to explicitly state this in the challenge, as arrays of (R,G,B) triplets are an accepted I/O format by default for these challenges. – orlp – 2017-01-15T17:36:11.550

Is it okay if we output nothing instead of white? – user41805 – 2017-01-15T17:44:04.913

Nothing as in a pixel with 0 alpha @KritixiLithos ? What would Nothing look like in the image? – P. Ktinos – 2017-01-15T17:45:50.603

@P.Ktinos http://i.stack.imgur.com/ShkoX.png

– user41805 – 2017-01-15T17:47:03.910

Not really @KritixiLithos . I guess it's kind of my fault for not specifying to not tamper with the alpha value. The alpha value should be at maximum for every pixel, and should not be xored, ill add to the question – P. Ktinos – 2017-01-15T17:49:06.020

Just to clarify, do we need to handle for all image sizes, or can we handle only specific image sizes? I was thinking it would be easier if I would handle images upto 400x400px – user41805 – 2017-01-15T17:54:05.090

@KritixiLithos Since "Size of the images doesn't matter", do whatever you think will help you achieve shorter code. If only handling specific image sizes makes your code shorter (or vice versa with all image sizes), then go ahead. – P. Ktinos – 2017-01-15T17:56:05.303

I would replace the word "extension" with "image format". (The "extension" is just a part of the file name.) – Paŭlo Ebermann – 2017-01-15T19:10:23.827

@PaŭloEbermann Done – P. Ktinos – 2017-01-15T19:15:19.910

@orlp Your QR links to http://codegolf.stackexchange.com/

– NoOneIsHere – 2017-01-16T22:27:38.663

Answers

20

The Fx Expression Language (ImageMagick), 8 4 bytes

EDITS

  • Simplified to u!=v, -4 bytes

As "Fx Expression Language" is apparently Turing complete, I've re-profiled my answer to it (was Unix Shell + Image Magick).

Golfed

u!=v

Fx does not support bitwise XOR nor bitwise NOT, so I've used != instead (which works just fine for the pure BW images).

u=> stands for "first image in list"
v=> "second image in list"

Input and output are implicit (controlled by the interpreter).

Usage

ImageMagick convert utility, serves as the "Fx Expression Language" interpreter, when invoked with -fx, as illustrated below:

convert $1 $2 -fx u!=v $3

The arguments are:

  1. Input image A
  2. Input image B
  3. Output image O (A^B).

Sample output

convert a.png b.png -fx u!=v o.png

enter image description here

zeppelin

Posted 2017-01-15T17:07:40.113

Reputation: 7 884

15

Mathematica, 37 34 15 bytes

Thanks to Ian Miller for cutting the number of bytes by more than half!

ImageDifference

In the end, there's always a builtin. This function takes two images as input and outputs an image; it does something more complicated for color images, but for black-and-white it's exactly XOR.

Previous submissions:

Thanks to JungHwan Min for saving 3 bytes!

Image[BitXor@@Chop[ImageData/@#]]&

Unnamed function that takes an ordered pair of images (of compatible dimensions) as input, and returns a displayed image. ImageData gets only the pixel data without all the wrappers/metadata; unfortunately it returns real numbers, so Chop is needed to help treat them as integers. BitXor does exactly what it says on the tin (and threads over nested lists), and Image turns the resulting RGB back into an image.

Original submission, which took an ordered pair of URLs or filenames a input:

Image[BitXor@@(#~Import~"Data"&/@#)]&

Greg Martin

Posted 2017-01-15T17:07:40.113

Reputation: 13 940

4For binary images you can use ImageDifference[#,#2]& – Ian Miller – 2017-01-16T04:08:44.780

10

Java, 336 335 328 bytes

import static javax.imageio.ImageIO.*;import java.io.*;public class M{static void main(String[]y)throws Exception{java.awt.image.BufferedImage a=read(new File("a.png"));for(int i=0,j;i<a.getHeight();i++)for(j=0;j<a.getWidth();)a.setRGB(j,i,a.getRGB(j,i)^read(new File("b.png")).getRGB(j++,i));write(a,"png",new File("c.png"));}}

Ungolfed:

import static javax.imageio.ImageIO.*;

import java.io.*;

class M {
    public static void main(String[]y) throws Exception {
        java.awt.image.BufferedImage a = read(new File("a.png"));
        for (int i = 0, j; i < a.getHeight(); i++)
            for (j = 0; j < a.getWidth(); ) a.setRGB(j, i, a.getRGB(j, i) ^ read(new File("b.png")).getRGB(j++, i));
        write(a, "png", new File("c.png"));
    }
}

Marv

Posted 2017-01-15T17:07:40.113

Reputation: 839

1You can save a byte by removing the space between String[] y. Just a minor little golf. – HyperNeutrino – 2017-01-15T22:55:42.550

Oh dang you're right. Haven't been golfing much lately, totally overlooked that one. Cheers. – Marv – 2017-01-15T23:14:13.103

3You can remove the public from public class M to save 7 bytes – user41805 – 2017-01-16T06:35:41.153

The file extension .png shouldn't be necessary – Huntro – 2017-01-16T09:25:36.380

You can save a byte by doing ..."i++ < a.getHeight();)" – Tatarize – 2017-01-16T22:16:03.350

"Input can be taken as a path to the image" -- I gotta note y[0] (4 bytes) is fewer bytes than "a.png" (6 bytes) – Tatarize – 2017-01-16T22:24:44.577

for (j=0;j++<a.getWidth();a.setRGB(j, i, a.getRGB(j, i) ^ read(new File(y[1])).getRGB(j, i))) write(a, "png", new File(y[2])); -- Feels wrong, but you can move the command of the second loop into the for's terminator section and then just save every single iteration of the loop, thereby getting rid of one semicolon. – Tatarize – 2017-01-16T22:40:42.427

Also, this fails. It tamples with alpha. Needs to save to something without alpha. – Tatarize – 2017-01-16T23:02:31.747

Bunch of tricks to save 1 character, that coulda been more than saved by y[0] or any of the rest.

import static javax.imageio.ImageIO.;import java.io.;class Main{public static void main(String[]y)throws Exception{java.awt.image.BufferedImage a=read(new File(y[0])),b=read(new File(y[1]));for(int i=0,q=a.getWidth();i<q*a.getHeight();)a.setRGB(i%q,i/q,a.getRGB(i%q,i/q)^b.getRGB(i%q,i++/q));write(a,"jpg",new File(y[2]));}} – Tatarize – 2017-01-17T00:44:05.103

I'm not convinced that you need the throws Exception on main. Then again, I haven't done Java in a while. – Fund Monica's Lawsuit – 2017-01-17T03:21:09.350

That feeling you get when you golf in a verbose language – ckjbgames – 2017-01-23T20:21:23.450

9

Python, 64 60 57 bytes

I'm new to golfing so have some mercy!

from cv2 import*
r=imread;lambda a,b:imshow('c',r(a)^r(b))

Thanks to @Blender and @FlipTack for saving me 7 bytes!

hashcode55

Posted 2017-01-15T17:07:40.113

Reputation: 581

1Using from cv2 import* should shave off 4 characters. – Blender – 2017-01-16T07:43:30.013

1Here, unnamed lambdas are allowed for function answers, so you can drop the d= :) also, doing r=imread and then using r twice might be shorter – FlipTack – 2017-01-17T18:41:27.733

7

Octave, 43 38 34 bytes

@(a,b)imshow(imread(a)~=imread(b))

Thanks to flawr saved me 5 bytes.

Thanks to Luis Mendo saved me 4 bytes suggested to use a~=b instead of xor(a,b).

A function that takes as input file name of the two input images a,b and shows the result.

Previous answer that writes to a file:

@(a,b,c)imwrite(imread(a)~=imread(b),c)

A function that takes as input file name of the two input images a,b and file name of the output image c.

Usage:

#two test images that used in the question
#https://i.stack.imgur.com/UbbfM.png
#https://i.stack.imgur.com/YyZG2.png
A = "UbbfM.png"; 
B = "YyZG2.png"; 
C = "out.png";
(@(a,b,c)imwrite(imread(a)~=imread(b),c))(A,B,C)

Result is saved in out.png

rahnema1

Posted 2017-01-15T17:07:40.113

Reputation: 5 435

1Couldn't you use imshow() instead of imwrite()? – flawr – 2017-01-15T18:55:20.770

@flawr Of course that will save some bytes:) – rahnema1 – 2017-01-15T18:56:56.673

1Can't you use imread(a)~=imread(b) (or +(imread(a)~=imread(b)) if logical input is not allowed by imshow) instead of xor(...)? – Luis Mendo – 2017-01-17T01:18:16.933

1@LuisMendo Thanks, I always learn from your comments! – rahnema1 – 2017-01-17T03:54:54.337

7

Processing, 124 118 117 bytes

void m(PImage a,PImage q){for(int i=0,j;i<400;i++)for(j=0;j<400;point(i,j++))stroke((a.get(i,j)^q.get(i,j))<9?0:-1);}

Usage:

Note: this code can support images up to 400px (with modifications can support upto 999 for the same bytecount). Any "leftover" space will be coloured black, so for best results, the image size should be the same size as the dimensions in the code (also the size() needs to be changed with the updated dimensions)

m(loadImage("http://i.imgur.com/a0M6o9e.png"),loadImage("http://i.imgur.com/bP1TsjQ.png"));

enter image description here

m(loadImage("https://i.stack.imgur.com/UbbfM.png"),loadImage("https://i.stack.imgur.com/YyZG2.png"));

enter image description here

Ungolfed

void Q106945(PImage a,PImage q){     // takes two images as input
  for(int i=0,j;i<400;i++)           // looping through the x-coordinates
    for(j=0;j<400;point(i,j++))      // looping through the y-coordinates
      stroke((a.get(i,j)^q.get(i,j))<9?0:-1);
/*
Here we have to colour the point according to the xor. So we do a simple 
a.get(i,j)^q.get(i,j). But since the alpha gets xored, instead of outputting white, this
outputs a colour with alpha 0 (completely invisible). So to fix this I have a ternary that
checks the value and changes the colour accordingly. At the end of all this, the third 
statement of the for-loop with j gets triggered since all this code is in this for-loop. 
Now we draw a point over the coordinate with the colour we have chosen before.
*/
}

user41805

Posted 2017-01-15T17:07:40.113

Reputation: 16 320

7

JavaScript (ES6), 333 320 308 299 297 bytes

- 12 20 bytes saved by Ismael Miguel
- 2 bytes saved by user2428118

Expects already loaded images, takes the first input's size as output size and returns a canvas element.

(i,j)=>{c=i=>{with(document.createElement(C='canvas')){width=i.width,height=i.height;return getContext`2d`}},g=i=>{x=c(i);x.drawImage(i,0,0);return x.getImageData(0,0,i.width,i.height)},a=g(i),b=g(j).data,d=a.data,r=c(i);d.forEach((e,i)=>{d[i]=i%4>2?255:e^b[i]});r.putImageData(a,0,0);return r[C]}

let func = (i,j)=>{c=i=>{with(document.createElement(C='canvas')){width=i.width,height=i.height;return getContext`2d`}},g=i=>{x=c(i);x.drawImage(i,0,0);return x.getImageData(0,0,i.width,i.height)},a=g(i),b=g(j).data,d=a.data,r=c(i);d.forEach((e,i)=>{d[i]=i%4>2?-1:e^b[i]});r.putImageData(a,0,0);return r[C]}

window.onload =_=>{
  document.body.appendChild(func(img1, img2));
  }
<img id="img1" crossOrigin="anonymous" src="https://dl.dropboxusercontent.com/s/nnfkzpvabk77pnl/UbbfM.png">
<img id="img2" crossOrigin="anonymous" src="https://dl.dropboxusercontent.com/s/58euf43vcb9pvpa/YyZG2.png">

Ungolfed

(i, j) => {
  c = i => { // an helper to create a canvas object
      with(document.createElement(C='canvas')) {
        width= i.width,
        height= i.height;
        return getContext`2d`
      }
    },
    g = i => { // an helper to get an imageData object
      x = c(i);
      x.drawImage(i, 0, 0);
      return x.getImageData(0, 0, i.width, i.height)
    },
    a = g(i),
    b = g(j).data,
    d = a.data,
    r = c(i);
  d.forEach((e, i) => { // loop through all rgba values
    d[i] = i % 4 > 2 ? 255 : e ^ b[i] // we need to avoid alpha channel...
  });
  r.putImageData(a, 0, 0);
  return r[C]
}

Ps: First time at code-golf, so it can probably be golfed more and my count might be erroneous.

PPs: canvas 2D context has an xor [compositing mode(https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation), but it works on alpha values...

Could be even further golfed (251 bytes) with a fixed 300*150px size (all remaining is black) as in the Processing answer

(i,j)=>{c=i=>{return document.createElement(C='canvas').getContext('2d')},g=i=>{x=c(i);x.drawImage(i,0,0);return x.getImageData(0,0,W=300,W)},a=g(i),b=g(j).data,d=a.data,r=c(i);d.forEach((e,i)=>{d[i]=i%4>2?W:e^b[i]});r.putImageData(a,0,0);return r[C]}

let func = (i,j)=>{c=i=>{return document.createElement(C='canvas').getContext('2d')},g=i=>{x=c(i);x.drawImage(i,0,0);return x.getImageData(0,0,W=300,W)},a=g(i),b=g(j).data,d=a.data,r=c(i);d.forEach((e,i)=>{d[i]=i%4>2?W:e^b[i]});r.putImageData(a,0,0);return r[C]}

window.onload =_=>{
  document.body.appendChild(func(img1, img2));
  }
<img id="img1" crossOrigin="anonymous" src="https://dl.dropboxusercontent.com/s/nnfkzpvabk77pnl/UbbfM.png">
<img id="img2" crossOrigin="anonymous" src="https://dl.dropboxusercontent.com/s/58euf43vcb9pvpa/YyZG2.png">

Kaiido

Posted 2017-01-15T17:07:40.113

Reputation: 181

1Replace the function c with c=i=>{with(document.createElement('canvas')){width=i.width,height=i.height;return getContext`2d`}} and you save 16 bytes. – Ismael Miguel – 2017-01-16T15:36:54.177

Can you not xor a black rectangle over the xor of the two images to get back to 255 alpha? – Neil – 2017-01-16T17:50:42.860

@IsmaelMiguel, thanks, Not used to use with but seems quite good for golfing ;-) Also, forgot the template literal saves 2 bytes... – Kaiido – 2017-01-17T00:44:34.067

@Neil, I'm not sure, here we've got an 8bit array, maybe with a 32bits, that could do it, but it will take more chars... – Kaiido – 2017-01-17T00:45:29.533

Maybe if you start with a black canvas, then xor each of the two image on to it? – Neil – 2017-01-17T00:46:42.407

@Kaiido You're welcome. You can also change your g function to g=i=>{with(c(i)){drawImage(i,0,0);return getImageData(0,0,i.width,i.height)}}. This saves 1 byte. Also, remove those let. You don't need them. Nobody cares if it writes thash to the window. – Ismael Miguel – 2017-01-17T01:44:03.307

@IsmaelMiguel, actually once let are removed, the with form is longer. (I've got a strange feeling going against my convictions while doing this...) – Kaiido – 2017-01-17T01:57:13.877

(i,j)=>{let c=i=>{with(document.createElement('canvas')){width=i.width,height=i.height;return getContext`2d`}},g=i=>{with(c(i)){drawImage(i,0,0);return getImageData(0,0,i.width,i.height)}},b=g(j).data,r=c(i);(d=(a=g(i)).data).forEach((e,i)=>{d[i]=i%4>2?255:e^=b[i]});r.putImageData(a,0,0);return r.canvas} <-- I wrote that piece of code with a let and it isn't longer. – Ismael Miguel – 2017-01-17T01:58:47.443

@IsmaelMiguel, g=i=>{with(c(i)){drawImage(i,0,0);return getImageData(0,0,i.width,i.height)}} is 77 while g=i=>{x=c(i);x.drawImage(i,0,0);return x.getImageData(0,0,i.width,i.height)} is 76 – Kaiido – 2017-01-17T02:05:36.007

Strange... Then I must have changed something because the code is shorter and still works... Also, you could use currying: i=>j=> which saves another byte. – Ismael Miguel – 2017-01-17T08:56:19.523

Currying is allowed ? I mean the question asks for a program that takes two images as input, with currying it's not exactly the case, is it ? However, I can save one more byte by changing ^= to ^, which was hum... a brain-fart. – Kaiido – 2017-01-17T09:08:18.103

1Saves 4 bytes: (i,j)=>{c=i=>{with(document.createElement(C='canvas')){width=i.width,height=i.height;return getContext`2d`}},g=i=>{x=c(i);x.drawImage(i,0,0);return x.getImageData(0,0,i.width,i.height)},a=g(i),b=g(j).data,d=a.data,r=c(i);d.forEach((e,i)=>{d[i]=i%4>2?255:e^b[i]});r.putImageData(a,0,0);return r[C]} – user2428118 – 2017-01-17T13:49:31.733

7

MATL, 10 bytes

YiiYiY~1YG

Explanation

This is basically the same answer, as the existing Octave solution: It takes the file names or URLs of both images as inputs and displays the result on the screen.

Yi    % Read first image from the URL or filename (implicit input)
i     % Get the second URL or filename as input
Yi    % Read that second image
Y~    % XOR the two images
1     % Push 1 (needed to make YG act as imagesc)
YG    % Display result using the MATLAB imagesc function

Usage

>> matl
 > YiiYiY~1YG
 > 
> 'https://i.stack.imgur.com/UbbfM.png'
> 'https://i.stack.imgur.com/YyZG2.png'

hbaderts

Posted 2017-01-15T17:07:40.113

Reputation: 221

1This is 10 bytes. – Erik the Outgolfer – 2017-04-23T18:18:49.783

3

Perl, 260 bytes

251 bytes of code + 9 bytes for -MImager.

($i,$j)=map{new Imager(file,pop)}0,1;$p=getpixel;for$x(0..$i->getwidth()-1){$i->setpixel(x=>$x,y=>$_,color=>[map{($j->$p(%t)->rgba)[$c++%3]^$_?0:255}($i->$p(%t=(x=>$x,y=>$_,type=>'8bit'))->rgba)[0..2]])for 0..$i->getheight()-1}$i->write(file=>'a.png')

I'm not sure Perl is the best language for this challenge, but I wanted to know what was the image of @orlp's comment. And it makes me use a little bit of those graphic modules, that's a good thing. And I enjoyed coding it!

A more readable version:

use Imager;
$img1 = new Imager( file => $ARGV[1] );
$img2 = new Imager( file => $ARGV[0] );

for $x ( 0 .. $img1->getwidth()-1 ) {
    for $y ( 0 .. $img1->getheight()-1 ) {
    ($r1, $g1, $b1) = $img1->getpixel( x => $x, y => $y, type => "8bit" )->rgba();
    ($r2, $g2, $b2) = $img2->getpixel( x => $x, y => $y, type => "8bit" )->rgba();
    $r = $r1 ^ $r2 ? 0 : 255 ;
    $g = $g1 ^ $g2 ? 0 : 255 ;
    $b = $b1 ^ $b2 ? 0 : 255 ;
    $img1->setpixel( x => $x, y => $y , color => [ $r, $g, $b] );
    }
}
$img1->write( file => 'a.png' )

You'll need to install Imager if you want to try it, but it's quite simple: just run (echo y;echo) | perl -MCPAN -e 'install Imager' in your terminal.

Dada

Posted 2017-01-15T17:07:40.113

Reputation: 8 279

3

LÖVE2D, 199 bytes

u,c=... i=love.image.newImageData a=math.abs X=i(u)Y=i(c)Z=i(X:getDimensions())Z:mapPixel(function(x,y)r,g,b=X:getPixel(x,y)R,G,B=Y:getPixel(x,y)return a(r-R),a(g-G),a(b-B)end)Z:encode("png","Z")

Simple enough, takes two image files on the command line, outputs a file called "Z" to the Love directory. Also works for full colour images!

ATaco

Posted 2017-01-15T17:07:40.113

Reputation: 7 898

1

@MDXF https://love2d.org/

– ATaco – 2017-09-27T04:04:08.953

2

J, 54 bytes

load'bmp'
'o'writebmp~256#.255*~:&*&((3#256)#:readbmp)

Takes two arguments where each is the path to an input image in bmp format. Each image is read as a matrix of 24-bit RGB integers and parsed into a triplet of 8-bit RGB values, the sign of each is taken, and the two matrices are XOR'd together. The result is then scaled by 255, converted back from a triplet of base 256 numbers into an integer, and written to an output bmp file named o.

miles

Posted 2017-01-15T17:07:40.113

Reputation: 15 654

2

C#, 233 bytes

using System.Drawing;class C{static void Main(){Bitmap
a=new Bitmap("a"),b=new Bitmap("b");for(int
x=0,y=0;;)try{a.SetPixel(x,y,a.GetPixel(x,y)==b.GetPixel(x,y)?Color.Black:Color.White);x++;}catch{if(x<1)break;x=0;++y;}a.Save("c");}}

Thanks to Unknown6656 for the tip that command line arguments are not necessary. The program now reads from files "a" and "b" and writes to file "c" in the same format as "a". Off by one error fixed too.

It sets each pixel to black if the colour is the same, otherwise white.

To save bytes, it catches out of bounds exceptions, rather than checking the Width and Height properties of the Bitmaps. Each time x goes out of bounds it is reset to 0, and y is incremented. When y goes out of bounds, x is 0 and the loop breaks to save the image and quit.

Example compile using csc and run using mono:

csc xor.cs

mono xor.exe

Simon Biber

Posted 2017-01-15T17:07:40.113

Reputation: 121

You could drop the token (string[] v) inside the main-declaration, as C# does not explicitly needs it to run an application – unknown6656 – 2017-01-17T18:21:04.563

2

C, 189 bytes

#include<stdio.h>
s,t[9];
#define o(f,p)int*f=fopen(p,"ab+");
#define f(p,q,r)o(a,p)o(b,q)o(c,r)fscanf(a,"%*s %*d %*d %n",&s);for(fwrite(t,1,fread(t,1,s,b),c);s=~getc(a);putc(~s^getc(b),c))

Operates on PBM images. Call f(a, b, out) with the names of both input files and the output file.

Assumptions:

  • Both input image headers are identical (whitespace included), and are less than 9 * sizeof(int) characters.

  • We're on a nice OS that flushes and closes leaked files.

  • EOF == -1

Ungolfed and explained: (backslashes omitted)

// Scratch variable and "big enough" buffer
s, t[9];

// Opens a file in read/append binary mode
#define o(f,p)int*f=fopen(p,"ab+");

#define f(p, q, r)

    // Open the three file pointers a, b, c from the paths p, q, r
    o(a, p)
    o(b, q)
    o(c, r)

    // Read from a to locate the end of the PBM header
    fscanf(a, "%*s %*d %*d %n", &s);

    for(
        // Read the header from b into the buffer,
        // then write it back from the buffer to c
        fwrite(t, 1, fread(t, 1, s, b), c);

        // Loop condition: get the next byte from a
        // and check for EOF with a bitwise-not
        // (Assumes that EOF == -1)
        s = ~getc(a);

        // Loop increment: get the next byte from b,
        // flip s back, xor and write to c
        putc(~s ^ getc(b), c)

    ) // Snatch the semicolon from the call syntax :)

C (spec-bending), 149 bytes

#include<stdio.h>
t[7];
#define o(f,p,u)int*f=fopen(p,"ab+");u(t,1,7,f);
#define f(p,q,r)o(a,p,fread)o(b,q,fread)o(c,r,fwrite)putc(getc(a)^getc(b),c)

Still uses PBM files, but now:

  • The image has to be one pixel high and 8 pixels wide or less, because PBM packs 8 pixels in a byte.

  • The header has to be 7 bytes (e.g. P4 8 1 with a trailing space).

Both files are seeked forwards while filling t with their header, then the last bytes are read, xor'd and written back. Takes advantage of fread and fwrite having similar parameter lists to factor all three operations on the header behind the same macro.

Quentin

Posted 2017-01-15T17:07:40.113

Reputation: 1 187

2

R, 45 bytes

p=png::readPNG;plot(as.raster(+(p(a)!=p(b))))

aand b represent the file names of the two image files.

Example:

a <- "YyZG2.png"
b <- "UbbfM.png"
p=png::readPNG;plot(as.raster(+(p(a)!=p(b))))

Output:

enter image description here

Sven Hohenstein

Posted 2017-01-15T17:07:40.113

Reputation: 2 464

2

Processing, 82 bytes

void x(PImage a,PImage b){int x=b.width;b.blend(a,0,0,x,x,0,0,x,x,32);set(0,0,b);}

Abuses Processing's extensive drawing functions to avoid actually doing any XORing. Blends the two images together with DIFFERENCE mode and draws them to the screen.

Usage

x(loadImage("http://i.imgur.com/a0M6o9e.png"),loadImage("http://i.imgur.com/bP1TsjQ.png"));

Ungolfed

void xor(PImage a, PImage b) {
  int x = a.width;
  b.blend(a, 0, 0, x, x, 0, 0, x, x, DIFFERENCE);
  set(0, 0, b);
}

quat

Posted 2017-01-15T17:07:40.113

Reputation: 1 211

Nice golf! It's really smart that you used 32 instead of DIFFERENCE. This would be a nice tip for golfing: http://codegolf.stackexchange.com/questions/26809/tips-for-golfing-in-processing :)

– user41805 – 2017-01-17T10:43:27.153

1

Clojure, 300 bytes

(ns s(:import[java.io File][java.awt.image BufferedImage][javax.imageio ImageIO]))(defn -main[](let[a(ImageIO/read(File."a.png"))](doseq[i(range(.getHeight a))j(range(.getWidth a))](.setRGB a j i(bit-xor(.getRGB a j i)(.getRGB(ImageIO/read(File."b.png")) j i))))(ImageIO/write a"png"(File."c.png"))))

Blatant rip-off of the Java answer. I didn't know how to do the challenge, but was curious how well the Java solution translated into Clojure. It was pretty straightforward. The ungolfed code is actually kind of pretty.

This was the first code-golf challenge I've done that included imports. There's probably a way to optimize them to save some bytes.

Ungolfed:

(ns bits.golf.bit-or-picts
  (:import [java.io File]
           [java.awt.image BufferedImage]
           [javax.imageio ImageIO]))

(defn -main []
  (let [^BufferedImage a (ImageIO/read (File. "a.png"))
        ^BufferedImage b (ImageIO/read (File. "b.png"))]
    (doseq [i (range (.getHeight a))
            j (range (.getWidth a))]
      (.setRGB a j i
                (bit-xor (.getRGB a j i)
                         (.getRGB b j i))))
    (ImageIO/write a "png" (File. "c.png"))))

Carcigenicate

Posted 2017-01-15T17:07:40.113

Reputation: 3 295

1

PHP, 246 243 bytes

I can probably golf this down more.

$o=imagecreatetruecolor($w=max(imagesx($a=($i=imagecreatefrompng)($argv[1])),imagesx($b=$i($argv[2]))),$h=max(imagesy($a),imagesy($b)));for(;$k<$w*$h;)imagesetpixel($o,$x=$k%$w,$y=$k++/$w,($t=imagecolorat)($a,$x,$y)^$t($b,$x,$y));imagepng($o);

Run it from the command line like this:

php -d error_reporting=0 -r "$o=imagecreatetruecolor($w=max(imagesx($a=($i=imagecreatefrompng)($argv[1])),imagesx($b=$i($argv[2]))),$h=max(imagesy($a),imagesy($b)));for(;$k<$w*$h;)imagesetpixel($o,$x=$k%$w,$y=$k++/$w,($t=imagecolorat)($a,$x,$y)^$t($b,$x,$y));imagepng($o);" "http://i.stack.imgur.com/UbbfM.png" "http://i.stack.imgur.com/YyZG2.png" > output.png

Kodos Johnson

Posted 2017-01-15T17:07:40.113

Reputation: 776

Defining the function name variables at their first occurence can help: $i=imagecreatefrompng;$a=$i($argv[1]) is one byte longer than $a=($i=imagecreatefrompng)($argv[1]). And you could try palette images with a two color palette. – Titus – 2017-01-17T04:07:17.473

I tried to define it at the first occurrence but I kept getting a fatal error. I'll try again later when I have time. Maybe I didn't do it correctly. – Kodos Johnson – 2017-01-17T04:11:45.597

($f=func)(params) requires PHP 7. – Titus – 2017-01-17T04:38:30.703

@Titus ah ok thanks. That took me down 3 bytes. – Kodos Johnson – 2017-01-17T07:45:25.520

Here are 7 more bytes: Replace for(;$k<$w*$h;) with for(;$y<$h;$y+=1/$w), $x=$k%$w, $y=$k++/$w with $x, $y and the last $x with $x++. (assuming there are no rounding errors for any reasonable image sizes) – Titus – 2017-01-17T15:35:36.927

If that doesn´t work, try for(;$y<$h;$y+=!$x), $x%=$w for the first $x and the $x++. (-4 bytes instead of -7) – Titus – 2017-01-17T16:02:16.773

0

Node.js, 156 135 bytes

(a,b)=>(f=require('fs')).writeFile(a+b,((s=f.readFileSync)(a)+'').replace(/\d+$/,(c,d)=>[...c].map((e,f)=>+!(e^(s(b)+b)[f+d])).join``))

Input and output image files should be in the PBM (P1) format, where the first line is P1 [width] [height], and the second line is the b/w ascii values without spaces.

Here's a the input images followed by the xor output (32x32 pixels):

Input #1 Input #2 Output

Mwr247

Posted 2017-01-15T17:07:40.113

Reputation: 3 494