C, 32-bit Windows, 987 bytes
#include <windows.h>
#define A CreateCompatibleDC(c)
#define F z=GetPixel(d,x,y);r=z;g=z>>8;b=z>>16
#define C(X,Y) (X<0||Y<0||X>=s[2]||Y>=s[3]||!GetPixel(e,X,Y))
#define D ((C(x-1,y)||C(x+1,y)||C(x,y-1)||C(x,y+1))&&!C(x,y))
#define E(X,Y) ((Z+X-Y)*(Z+X-Y)<2501)
main(int a,int*n){HDC c,d,e,f,w;int x,y,s[9],z,*o,m,t,Z;unsigned char r,g,b,R,G,B;c=GetDC(w=GetDesktopWindow());d=A;e=A;SelectObject(d,f=LoadImage(0,n[1],0,0,0,16));SelectObject(e,LoadImage(0,n[2],0,0,0,16));GetObject(f,24,s+1);o=LocalAlloc(64/*Fixed,ZeroInit*/,8*s[2]*s[3]);for(x=t=Z=s[1]=s[0]=0;x<s[2];x++)for(y=0;y<s[3];y++)if D{F;for(m=0;m<t&&o[m]!=z;m+=2);o[m]=z;o[m+1]++;t+=2*(m>=t);}for(x=y=1;x<t;x+=2)if(o[x]>o[y])y=x;z=o[y-1];R=z;G=z>>8;B=z>>16;for(x=0;x<s[2];x++)for(y=0;y<s[3];y++){F;SetPixel(c,x,s[3]-y-1,(C(x,y)||(E(r,R)&&E(g,G)&&E(b,B)))?0x232323:0x1B0DFC);}SelectObject(c,CreateFont(-(s[2]>>2),0,0,0,400,0,0,0,0,0,0,0,0,"Arial"));SetBkMode(c,1);SetTextColor(c,0xFFFFFF);DrawText(c,"-1",2,s,37);ReleaseDC(w,c);}
- The file is saved with LF as line end, not with CR+LF to save some bytes.
- The program is written in a way that compiler warnings are generated to save some more bytes.
- The file will probably not compile as 64-bit program because the array "
s[]
" is used to do some implicit castings...
- The program takes two images (file names are given via command line):
- The first image (first command line argument) is the R/G/B image in Windows .BMP format
- The second image is the Alpha channel (black means: 0%, any other colour means: not 0%); the file is also in .BMP format and must have the same size or be larger than the first image
- The output image is displayed in the left upper corner of the screen
- I couldn't reproduce the boy with the yellow hair. Yellow seems to be too far away (> 50) from white!
Ungolfed version:
#include <windows.h>
/*
* Although this line costs us 32 bytes
* Replacing "CreateCompatibleDC(c)" we'll
* save 42 bytes in the golfed version later
* so we save 10 bytes using this define!
*/
#define A CreateCompatibleDC(c)
/*
* Macro: Get a pixel value at (x,y) to z
* Also get r, g, b
*/
#define F z=GetPixel(d,x,y); \
r=z; \
g=z>>8; \
b=z>>16
/*
* Macro checking if a pixel is a
* transparent colour or lies outside the
* image
*/
#define C(X,Y) (X<0 || Y<0 || X>=s[2] || Y>=s[3] || !GetPixel(e,X,Y))
/*
* Macro checking if a pixel at (x,y) is a border pixel
*/
#define D ((C(x-1,y) || C(x+1,y) || C(x,y-1) || C(x,y+1)) && !C(x,y))
/*
* Macro checking if the difference between X and Y is less than 50
* The variable "Z" must be type "int" and zero. It is used to
* perform an implicit cast from "BYTE" to "int".
*/
#define E(X,Y) ((Z+X-Y)*(Z+X-Y)<2501)
/*
* Note that the second argument is "char **",
* not "int *".
* We ignore resulting compiler warnings...
*/
main(int a, int * n)
{
HDC c, d, e, f, w;
int x, y, s[9], z, *o, m, t, Z;
unsigned char r, g, b, R, G, B;
/*
* Get the HDC handle to the
* screen (allowing us to create HDCs
* for accessing bitmap files as well as
* drawing directly to the screen!)
*/
c=GetDC(w=GetDesktopWindow());
/*
* Create two virtual HDCs for accessing
* the bitmap files.
*/
d=A; /* Macro */
e=A; /* Macro */
/*
* Load the two images:
* The first argument is the image file with
* the R/G/B channel
* The second argument is the image file
* containing the mask defined by the Alpha
* channel:
* Black means = Alpha=0
* White means = Alpha>0
* (Any other colour means: Alpha>0)
*
* Note that "f" is of the type "HBITMAP",
* not "HDC". We save 4 bytes in the golfed
* version using HDC instead of HBITMAP and
* compile the C file with compiler warnings
* switched off!
*
* The second image should have the same size
* as the first one. However it may be larger
* than the first one. It must not be smaller!
*/
SelectObject(d,f=LoadImage(0,n[1],0,0,0,16 /* 16=LR_LOADFROMFILE */));
SelectObject(e,LoadImage(0,n[2],0,0,0,16));
/*
* Get the image information (size)
*/
GetObject(f,24,s+1);
/*
* Search all background colours
*/
o=LocalAlloc(64 /* Fixed, ZeroInit */,8*s[2]*s[3]);
for(x=t=Z=s[1]=s[0]=0;x<s[2];x++)
for(y=0;y<s[3];y++)
if D
{
F; /* Macro */
for(m=0;m<t && o[m]!=z;m+=2);
o[m]=z;
o[m+1]++;
t+=2*(m>=t);
}
/*
* Search the most common one
*/
for(x=y=1;x<t;x+=2) if(o[x]>o[y]) y=x;
z=o[y-1];
R=z;
G=z>>8;
B=z>>16;
/*
* Draw the image directly to the screen
*/
for(x=0;x<s[2];x++)
for(y=0;y<s[3];y++)
{
F; /* Macro */
/* C and E are macros: */
SetPixel(c,x,s[3]-y-1,(C(x,y) ||
(E(r,R) && E(g,G) && E(b,B)))?
0x232323:0x1B0DFC);
}
/*
* Draw the text over the image
*/
SelectObject(c,CreateFont(-(s[2]>>2),0,0,0,400,0,0,0,0,0,0,0,0,"Arial"));
SetBkMode(c,1 /* TRANSPARENT */);
SetTextColor(c,0xFFFFFF);
DrawText(c,"-1",2,s,37 /* center, vcenter, singleline */);
/*
* Unfortunately DrawText() won't work
* when not doing this!
*/
ReleaseDC(w,c);
}
6-1 First test case not an animal -_- – Geobits – 2016-11-14T01:00:14.107
10-1ˢᵗ test case not an animal either. – Adám – 2016-11-14T01:16:48.530
@Geobits okay, fine fixed – Downgoat – 2016-11-14T03:50:31.023
8Not a fan of demon dennis – downrep_nation – 2016-11-14T07:41:36.327
1You could eliminate the worry about whether it's an animal by changing "animal" to "avatar" in the title and throughout the question. – Glenn Randers-Pehrson – 2016-11-14T12:57:44.647
4What is the point of enforcing the font to use? The only thing this does is penalize languages where changing font takes more bytes – Fatalize – 2016-11-14T14:38:00.900
1@Fatalize because image input can be taken as an array of channels, I want this to be more complex than some basic array transformation and drawing a vertical line in the middle and calling that a one – Downgoat – 2016-11-14T14:40:40.397
@Downgoat You have removed the penguin image. Does this mean that the program does not need to work with image formats having an "alpha" channel? – Martin Rosenau – 2016-11-15T07:10:51.317
The background definition makes this way harder than necessary. You could also have said to provide a B/W image, or transparent/non-transparent. I thought about heading for a CSS3 solution, but like that it's simply impossible. – Cedric Reichenbach – 2016-11-15T12:27:56.537
I suspect that your example "output" for the dennis-the-menace image was generated from a different (better, without JPEG artifacts) original. I was not able to avoid getting JPEG artifacts in my result. – Glenn Randers-Pehrson – 2016-11-19T23:07:58.133
@GlennRanders-Pehrson you shouldn't have a problem with the fuzziness if the threshold is implemented correctly. Perhaps check that? – Downgoat – 2016-11-19T23:10:13.717
Well, "fuzz 8%" works better but still not an exact repro of your result. It appears that in that case my script was using 50/65k rather than 50/255 as the threshold. – Glenn Randers-Pehrson – 2016-11-20T00:16:14.163