29
\$\begingroup\$

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.

\$\endgroup\$
14
  • \$\begingroup\$ Can we take the input image as a URL? \$\endgroup\$
    – user41805
    Commented Jan 15, 2017 at 17:11
  • \$\begingroup\$ @KritixiLithos yup, I edited it in the challenge for any further viewers. \$\endgroup\$
    – Offtkp
    Commented Jan 15, 2017 at 17:14
  • 5
    \$\begingroup\$ Bonus challenge: i.imgur.com/a0M6o9e.png and i.imgur.com/bP1TsjQ.png. \$\endgroup\$
    – orlp
    Commented Jan 15, 2017 at 17:26
  • \$\begingroup\$ May we read/write matrices of (R, G, B) triplets? \$\endgroup\$
    – lynn
    Commented Jan 15, 2017 at 17:28
  • \$\begingroup\$ @orlp I got up to the qr code \$\endgroup\$
    – user41805
    Commented Jan 15, 2017 at 17:29

18 Answers 18

20
\$\begingroup\$

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

\$\endgroup\$
15
\$\begingroup\$

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"&/@#)]&
\$\endgroup\$
1
  • 4
    \$\begingroup\$ For binary images you can use ImageDifference[#,#2]& \$\endgroup\$
    – Ian Miller
    Commented Jan 16, 2017 at 4:08
10
\$\begingroup\$

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"));
    }
}
\$\endgroup\$
11
  • 1
    \$\begingroup\$ You can save a byte by removing the space between String[] y. Just a minor little golf. \$\endgroup\$
    – hyper-neutrino
    Commented Jan 15, 2017 at 22:55
  • \$\begingroup\$ Oh dang you're right. Haven't been golfing much lately, totally overlooked that one. Cheers. \$\endgroup\$
    – Marv
    Commented Jan 15, 2017 at 23:14
  • 3
    \$\begingroup\$ You can remove the public from public class M to save 7 bytes \$\endgroup\$
    – user41805
    Commented Jan 16, 2017 at 6:35
  • \$\begingroup\$ The file extension .png shouldn't be necessary \$\endgroup\$
    – Huntro
    Commented Jan 16, 2017 at 9:25
  • \$\begingroup\$ You can save a byte by doing ..."i++ < a.getHeight();)" \$\endgroup\$
    – Tatarize
    Commented Jan 16, 2017 at 22:16
9
\$\begingroup\$

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!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Using from cv2 import* should shave off 4 characters. \$\endgroup\$
    – Blender
    Commented Jan 16, 2017 at 7:43
  • 1
    \$\begingroup\$ Here, 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 \$\endgroup\$
    – FlipTack
    Commented Jan 17, 2017 at 18:41
8
\$\begingroup\$

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.sstatic.net/UbbfM.png'
> 'https://i.sstatic.net/YyZG2.png'
\$\endgroup\$
1
  • 1
    \$\begingroup\$ This is 10 bytes. \$\endgroup\$ Commented Apr 23, 2017 at 18:18
7
\$\begingroup\$

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.sstatic.net/UbbfM.png
#https://i.sstatic.net/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

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Couldn't you use imshow() instead of imwrite()? \$\endgroup\$
    – flawr
    Commented Jan 15, 2017 at 18:55
  • \$\begingroup\$ @flawr Of course that will save some bytes:) \$\endgroup\$
    – rahnema1
    Commented Jan 15, 2017 at 18:56
  • 1
    \$\begingroup\$ Can't you use imread(a)~=imread(b) (or +(imread(a)~=imread(b)) if logical input is not allowed by imshow) instead of xor(...)? \$\endgroup\$
    – Luis Mendo
    Commented Jan 17, 2017 at 1:18
  • 1
    \$\begingroup\$ @LuisMendo Thanks, I always learn from your comments! \$\endgroup\$
    – rahnema1
    Commented Jan 17, 2017 at 3:54
7
\$\begingroup\$

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.sstatic.net/UbbfM.png"),loadImage("https://i.sstatic.net/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.
*/
}
\$\endgroup\$
7
\$\begingroup\$

JavaScript (ES6), 253 bytes

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

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

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

let func = (i,j)=>(c=i=>{with(document.createElement(C='canvas')){({width,height}=i);return getContext`2d`}},g=i=>(x=c(i),x.drawImage(i,0,0),x.getImageData(0,0,1e4,1e4)),a=g(i),b=g(j).data,d=a.data,d.forEach((e,i)=>d[i]=i%4>2?e:e^b[i]),x.putImageData(a,0,0),x[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 the input's dimension
    with(document.createElement(C='canvas')) {
      ({width, height}=i); // set the canvas size
      return getContext`2d`
    }
  },
  g = i => ( // an helper to get an ImageData object from an Image
    x = c(i),
    x.drawImage(i, 0, 0),
    x.getImageData(0, 0, 1e4, 1e4) // 1e4 x 1e4 px should be big enough
                                   // (bigger might not be supported by the browser)
  ),
  a = g(i),
  b = g(j).data,
  d = a.data,
  d.forEach((e, i) => {    // loop through all rgba values
    d[i] = i % 4 > 2       // we need to special handle the alpha channel
      ? e :                // keep the alpha of the first input
      e ^ b[i]             // xor the rgb values
  }),
  x.putImageData(a, 0, 0), // put that back on the last context we created
  x[C]                     // return its canvas
}

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

(c=i=>document.createElement(C='canvas').getContext('2d'),g=i=>(x=c(i),x.drawImage(i,0,0),x.getImageData(0,0,1e4,1e4)),a=g(i),b=g(j).data,d=a.data,d.forEach((e,i)=>d[i]=i%4>2?e:e^b[i]),x.putImageData(a,0,0),x[C])

let func = (i,j)=>(c=i=>document.createElement(C='canvas').getContext('2d'),g=i=>(x=c(i),x.drawImage(i,0,0),x.getImageData(0,0,1e4,1e4)),a=g(i),b=g(j).data,d=a.data,d.forEach((e,i)=>d[i]=i%4>2?e:e^b[i]),x.putImageData(a,0,0),x[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">

\$\endgroup\$
12
  • 1
    \$\begingroup\$ Replace the function c with c=i=>{with(document.createElement('canvas')){width=i.width,height=i.height;return getContext`2d`}} and you save 16 bytes. \$\endgroup\$ Commented Jan 16, 2017 at 15:36
  • \$\begingroup\$ Can you not xor a black rectangle over the xor of the two images to get back to 255 alpha? \$\endgroup\$
    – Neil
    Commented Jan 16, 2017 at 17:50
  • \$\begingroup\$ @IsmaelMiguel, thanks, Not used to use with but seems quite good for golfing ;-) Also, forgot the template literal saves 2 bytes... \$\endgroup\$
    – Kaiido
    Commented Jan 17, 2017 at 0:44
  • \$\begingroup\$ @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... \$\endgroup\$
    – Kaiido
    Commented Jan 17, 2017 at 0:45
  • 1
    \$\begingroup\$ Saves 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]} \$\endgroup\$ Commented Jan 17, 2017 at 13:49
3
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

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!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ @MDXF love2d.org \$\endgroup\$
    – ATaco
    Commented Sep 27, 2017 at 4:04
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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

\$\endgroup\$
2
\$\begingroup\$

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);
}
\$\endgroup\$
1
2
\$\begingroup\$

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
\$\endgroup\$
1
  • \$\begingroup\$ You could drop the token (string[] v) inside the main-declaration, as C# does not explicitly needs it to run an application \$\endgroup\$ Commented Jan 17, 2017 at 18:21
1
\$\begingroup\$

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"))))
\$\endgroup\$
1
\$\begingroup\$

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);" "https://i.sstatic.net/UbbfM.png" "https://i.sstatic.net/YyZG2.png" > output.png
\$\endgroup\$
6
  • \$\begingroup\$ 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. \$\endgroup\$
    – Titus
    Commented Jan 17, 2017 at 4:07
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Jan 17, 2017 at 4:11
  • \$\begingroup\$ ($f=func)(params) requires PHP 7. \$\endgroup\$
    – Titus
    Commented Jan 17, 2017 at 4:38
  • \$\begingroup\$ @Titus ah ok thanks. That took me down 3 bytes. \$\endgroup\$ Commented Jan 17, 2017 at 7:45
  • \$\begingroup\$ 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) \$\endgroup\$
    – Titus
    Commented Jan 17, 2017 at 15:35
0
\$\begingroup\$

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

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.