[Question]
  [
[![enter image description here](https://i.stack.imgur.com/rCqky.png)](https://i.stack.imgur.com/rCqky.png)
While doodling around on square-ruled paper the other day, I came up with the above negative-space font for digits. In case you haven't spotted it yet, the spaces between the above shapes yield the golden ratio **1.618033988749**. In this challenge, your task is to take a number as input and render it exactly as the example above shows.
Here is how these are created: all lines will be on a regular grid, so that the individual digits are made up of a small number of grid cells. Here are the shapes of the 10 digits (we'll ignore the decimal point for this challenge):
[![enter image description here](https://i.stack.imgur.com/D9q3N.png)](https://i.stack.imgur.com/D9q3N.png)  
Yes, the **7** differs from the golden ratio example at the top. I kinda messed that up. We'll be going with this one.
Notice that each digit is five cells tall, and three cells wide. To render a number, you can imagine placing all its digits next to each other, such that there is exactly one empty column between each pair of digits. For example, taking `319` as input, we'd write:
[![enter image description here](https://i.stack.imgur.com/HNpZX.png)](https://i.stack.imgur.com/HNpZX.png)
Notice that we add one leading and trailing empty column. Now we invert the cells:
[![enter image description here](https://i.stack.imgur.com/izPXn.png)](https://i.stack.imgur.com/izPXn.png)
The output should then be the boundaries of the resulting polygons:
[![enter image description here](https://i.stack.imgur.com/ztpo5.png)](https://i.stack.imgur.com/ztpo5.png)
Of course you may generate the result in any other way, as long as the rendered output looks the same.
## Input
* You may write a program or function, taking input via STDIN (or closest alternative), command-line argument or function argument, as a string, or list of digits. (You can't take a number as that wouldn't allow you to support leading zeros.)
* You may assume that there will be no more than 16 digits in the input.
## Output
* Output may either be displayed on screen or written to a file in a common image format.
* You may use both raster and vector graphics.
* In either case, the aspect ratio of the cells of the underlying grid needs to be 1 (that is, the cells should be squares).
* In the case of raster graphics, each cell should cover at least 20 by 20 pixels.
* The lines must be no wider than 10% of the cell size. I'm willing to give one or two pixels leeway due to aliasing here.
* Lines and background can be any two clearly distinguishable colours, but the shapes created by the lines must not be filled (that is the insides should be the background colour as well).
* There must be no gaps within each closed loop.
* Of course, the entire result must be visible.
## Test Cases
Here are 10 inputs, which together cover all possible pairs of adjacent digits, as well as every possible leading and trailing digit:
```
07299361548
19887620534
21456837709
39284106657
49085527316
59178604432
69471338025
79581224630
89674235011
97518264003
```
And here are the expected results for those:
[![enter image description here](https://i.stack.imgur.com/UTM1a.png)](https://i.stack.imgur.com/UTM1a.png)
[![enter image description here](https://i.stack.imgur.com/Ct1sR.png)](https://i.stack.imgur.com/Ct1sR.png)
[![enter image description here](https://i.stack.imgur.com/MJzQr.png)](https://i.stack.imgur.com/MJzQr.png)
[![enter image description here](https://i.stack.imgur.com/OPK9E.png)](https://i.stack.imgur.com/OPK9E.png)
[![enter image description here](https://i.stack.imgur.com/zlqOn.png)](https://i.stack.imgur.com/zlqOn.png)
[![enter image description here](https://i.stack.imgur.com/vspRa.png)](https://i.stack.imgur.com/vspRa.png)
[![enter image description here](https://i.stack.imgur.com/NQPdG.png)](https://i.stack.imgur.com/NQPdG.png)
[![enter image description here](https://i.stack.imgur.com/ODUY8.png)](https://i.stack.imgur.com/ODUY8.png)
[![enter image description here](https://i.stack.imgur.com/Rc7R1.png)](https://i.stack.imgur.com/Rc7R1.png)
[![enter image description here](https://i.stack.imgur.com/f9Ldb.png)](https://i.stack.imgur.com/f9Ldb.png)
Make sure that your code also works when given a single digit (I don't want to include the expected results here, because they should be obvious, and the test case section is bloated enough as it is).
  
[Answer]
# Octave, ~~233 225 216~~ 213 bytes
```
o=@ones;l=z=o(5,1);for k=input('')-47;l=[l,reshape(dec2bin([448,22558,8514,10560,3936,2376,328,15840,320,2368](k),15),5,[])-48,z];end;L=~o(size(l)+2);L(2:6,2:end-1)=l;O=o(3);O(5)=-8;M=~conv2(kron(L,o(25)),O);imshow(M)
```
Here the first test case (from a resized screen capture, s.t. it fits my monitor=):
[![enter image description here](https://i.stack.imgur.com/p5gDT.png)](https://i.stack.imgur.com/p5gDT.png)
```
o=@ones;
l=z=o(5,1);                   %spacer matrices
for k=input('')-47;           %go throu all input digis
                              %decode the matrices for each digit from decimal
l=[l,reshape(dec2bin([448,22558,8514,10560,3936,2376,328,15840,320,2368](k),15),5,[])-48,z];
end
L=~o(size(l)+2);           %pad the image
L(2:6,2:end-1)=l;
O=o(3);O(5)=-8;               %create edge detection filter
imshow(~conv2(kron(L,o(25)),O)) %image resizing /edge detection (change 25 to any cell size you like)
```
The input can be arbitrary length, like e.g. `'07299361548'`
> 
> Convolution is the key to success.
> 
> 
> 
[Answer]
# Html+JavaScript ES6, 352
Test running the snippet below
```
<canvas id=C></canvas><script>s=prompt(),C.width=-~s.length*80,c=C.getContext("2d"),[...s].map(d=>[30,d*=3,++d,++d].map(w=a=>{for(a=parseInt("vhvivgtlnllv74vnltvlt11vvlvnlv0"[a],36)*2+1,p=1,y=100,i=64;i>>=1;p=b,y-=20)c.moveTo(x+20,y),b=a&i?1:0,c[b-p?'lineTo':'moveTo'](x,y),(a^q)&i&&c.lineTo(x,y-20);q=a,x+=20}),q=63,x=0),w(30),w(0),c.stroke()</script>
```
*Less golfed*
```
s=prompt(),C.width=-~s.length*80,c=C.getContext("2d"),
w=a=>{
  a=parseInt("vhvivgtlnllv74vnltvlt11vvlvnlv0"[i],36)*2+1
  for(p=1,y=100,i=32;i;p=b,y-=20,i>>=1)
    c.moveTo(x+20,y),
    b=a&i?1:0,
    c[b-p?'lineTo':'moveTo'](x,y),
    (a^q)&i&&c.lineTo(x,y-20)
  q=a 
  x+=20
},
[...s].map(d=>[30,d*=3,++d,++d].map(w),q=63,x=0),
w(30),w(0)
c.stroke()
```
[Answer]
# Javascript ES6, 506 bytes
```
a=>{with(document)with(body.appendChild(createElement`canvas`))with(getContext`2d`){width=height=(a.length+2)*80;scale(20,20);translate(1,1);lineWidth=0.1;beginPath();["oint",...a.map(i=>"05|7agd7|oint 067128a45|oicgmnt 01de25|oil9amnt 01de23fg45|oint 03fh5|68ec6|oint 03fg45|oij78knt 05|9agf9|oij78knt 01dh5|oint 05|78ed7|9agf9|oint 03fg45|78ed7|oint".split` `[i]),"05"].map(i=>{i.split`|`.map(i=>[...i].map((e,i,_,p=parseInt(e,36),l=~~(p/6),r=p%6)=>i?lineTo(l,r):moveTo(l,r)));translate(4,0)});stroke()}}
```
Ungolfed:
```
a=>{                                            // anonymous function declaration, accepts array of numbers
  with(document)                                // bring document into scope
  with(body.appendChild(createElement`canvas`)) // create canvas, drop into html body, bring into scope
  with(getContext`2d`){                         // bring graphics context into scope
    width=height=(a.length+2)*80;               // set width and height
    scale(20,20);                               // scale everything to 20x
    translate(1,1);                             // add padding so outline doesn't touch edge of canvas
    lineWidth=0.1;                              // have to scale line width since we scaled 20x
    beginPath();                                // start drawing lines
    ["oint",                                    // beginning "glyph", draws left end of negative space, see below
     ...a.map(i=>`05|7agd7|oint                 // glyphs 0-9 encoded as vertices
                  067128a45|oicgmnt             //   glyphs seperated by " "
                  01de25|oil9amnt               //   lines within each glyph seperated by "|"
                  01de23fg45|oint               //   a single vertex is stored as a base36 char
                  03fh5|68ec6|oint              //     where a number corresponds to one of the verts shown below:
                  03fg45|oij78knt               //        0  6 12 18 24
                  05|9agf9|oij78knt             //        1  7 13 19 25
                  01dh5|oint                    //        2  8 14 20 26
                  05|78ed7|9agf9|oint           //        3  9 15 21 27
                  03fg45|78ed7|oint`            //        4 10 16 22 28
       .split` `[i]),                           //        5 11 17 23 29
     "05"]                                      // end "glyph", draws right end of negative space, see above
      .map(i=>{                                 // for each glyph string
        i.split`|`                              // seperate into list of line strings
          .map(i=>[...i]                        // convert each line string into list of chars
            .map((e,i,_,p=parseInt(e,36),       // convert base36 char to number
                  l=~~(p/6),r=p%6)=>            // compute x y coords of vertex
              i?lineTo(l,r):moveTo(l,r)));      // draw segment
        translate(4,0)});                       // translate origin 4 units to right
    stroke()}}                                  // draw all lines to canvas
```
Assumes there's a `<body>` to append the canvas to, tested in Firefox 46.
Example run (assigning anonymous function to f):
```
f([1,0,3])
```
yields:
[![Example output](https://i.stack.imgur.com/efj7R.png)](https://i.stack.imgur.com/efj7R.png)
[Answer]
# Java, 768 bytes
```
import java.awt.*;import java.awt.image.*;class G{public static void main(String[]v)throws Exception{int s=20,n=v[0].length(),i=0,j,w=(n*3+n+1)*s,h=5*s,a[][]={{6,7,8},{0,2,3,10,11,12,13},{1,6,8,13},{1,3,6,8},{3,4,5,6,8,9},{3,6,8,11},{6,8,11},{1,2,3,4,6,7,8,9},{6,8},{3,6,8}};BufferedImage o,b=new BufferedImage(w,h,1);Graphics g=b.getGraphics();g.setColor(Color.WHITE);for(;i<n;i++)for(j=0;j<15;j++){int c=j;if(java.util.Arrays.stream(a[v[0].charAt(i)-48]).noneMatch(e->e==c))g.fillRect((1+i*4+j/5)*s,j%5*s,s,s);}o=new BufferedImage(b.getColorModel(),b.copyData(null),0>1,null);for(i=1;i<h-1;i++)for(j=1;j<w-1;j++)if((b.getRGB(j+1,i)|b.getRGB(j-1,i)|b.getRGB(j,i+1)|b.getRGB(j,i-1))<-1)o.setRGB(j,i,-1);javax.imageio.ImageIO.write(o,"png",new java.io.File("a.png"));}}
```
### Ungolfed
```
import java.awt.*;
        import java.awt.image.BufferedImage;
class Q79261 {
    public static void main(String[] v) throws Exception {
        int scale = 20, n = v[0].length(), i = 0, j, width = (n * 3 + n + 1) * scale, height = 5 * scale, values[][] = {{6, 7, 8}, {0, 2, 3, 10, 11, 12, 13}, {1, 6, 8, 13}, {1, 3, 6, 8}, {3, 4, 5, 6, 8, 9}, {3, 6, 8, 11}, {6, 8, 11}, {1, 2, 3, 4, 6, 7, 8, 9}, {6, 8}, {3, 6, 8}};
        BufferedImage output, temp = new BufferedImage(width, height, 1);
        Graphics g = temp.getGraphics();
        g.setColor(Color.WHITE);
        for (; i < n; i++)
            for (j = 0; j < 15; j++) {
                int finalJ = j;
                if (java.util.Arrays.stream(values[v[0].charAt(i) - 48]).noneMatch(e -> e == finalJ))
                    g.fillRect((1 + i * 4 + j / 5) * scale, j % 5 * scale, scale, scale);
            }
        output = new BufferedImage(temp.getColorModel(), temp.copyData(null), 0 > 1, null);
        for (i = 1; i < height - 1; i++)
            for (j = 1; j < width - 1; j++)
                if ((temp.getRGB(j + 1, i) | temp.getRGB(j - 1, i) | temp.getRGB(j, i + 1) | temp.getRGB(j, i - 1)) < -1)
                    output.setRGB(j, i, -1);
        javax.imageio.ImageIO.write(output, "png", new java.io.File("a.png"));
    }
}
```
### Notes
* Input is a single string as argument. How to use: `javac G.java`, `java G 80085`
* I'm starting with a black canvas, then I'm adding the numbers as white positives. I create a copy of the image and then flip every black pixel that has 4 black neighbours on the original image.
### Outputs
[![0](https://i.stack.imgur.com/PINSK.png)](https://i.stack.imgur.com/PINSK.png)
[![1](https://i.stack.imgur.com/YgW9O.png)](https://i.stack.imgur.com/YgW9O.png)
[![2](https://i.stack.imgur.com/46aMt.png)](https://i.stack.imgur.com/46aMt.png)
[![3](https://i.stack.imgur.com/PHpkk.png)](https://i.stack.imgur.com/PHpkk.png)
[![4](https://i.stack.imgur.com/M9WVy.png)](https://i.stack.imgur.com/M9WVy.png)
[![5](https://i.stack.imgur.com/hWkn4.png)](https://i.stack.imgur.com/hWkn4.png)
[![6](https://i.stack.imgur.com/CP3Sv.png)](https://i.stack.imgur.com/CP3Sv.png)
[![7](https://i.stack.imgur.com/wEfty.png)](https://i.stack.imgur.com/wEfty.png)
[![8](https://i.stack.imgur.com/waXH1.png)](https://i.stack.imgur.com/waXH1.png)
[![9](https://i.stack.imgur.com/R5otW.png)](https://i.stack.imgur.com/R5otW.png)
Some single digits:
[![enter image description here](https://i.stack.imgur.com/PKvRw.png)](https://i.stack.imgur.com/PKvRw.png) [![enter image description here](https://i.stack.imgur.com/uhyow.png)](https://i.stack.imgur.com/uhyow.png)
[Answer]
# R, too many bytes to golf (~~1530+~~ 1115)
```
library(reshape2);library(ggplot2);library(png)
M=matrix(1,5,3)
M=lapply(list(c(7:9),c(1,3,4,11:14),c(2,7,9,14),c(2,4,7,9),c(4:7,9,10),c(4,7,9,12),c(7,9,12),c(2:5,7:10),c(7,9),c(4,7,9)),function(x){M[x]=0;M})
g=function(P){
S=matrix(0,5,1)
R=NULL
for(N in P){R=Reduce(cbind2,list(R,S,M[[N+1]]))}
cbind(R,S)}
p=function(P){
o=t(apply(g(P),1,rev))
ggplot(melt(o),aes(x=Var1,y=Var2))+geom_raster(aes(fill=value))+coord_flip()+scale_fill_continuous(guide=FALSE,high="#FFFFFF",low="#000000")+scale_y_reverse()+scale_x_reverse()+theme_bw()+theme(panel.grid=element_blank(),panel.border=element_blank(),panel.background=element_blank(),axis.title=element_blank(),axis.text=element_blank(),axis.ticks=element_blank(),plot.margin=unit(c(0,0,0,0),"mm"))+ggsave("t.png",width=dim(o)[2]/2.5,height=2,units="in",dpi=99)
q=readPNG("t.png")
k=q[,,1]
b=replace(k,k==1,0)
for(i in 1:nrow(k)){
for(j in 1:ncol(k)){
u=(i==nrow(k))
v=(j==ncol(k))
if(u&v){b[i,j]=1;break}
if((i==1)|u|(j==1)|v){b[i,j]=1;next}else{if(all(k[c((i-1):(i+1)),c((j-1):(j+1))])){b[i,j]=1}else{b[i,j]=0}}}}
q[,,1:3]=abs(replace(k,b==1,0)-1)
writePNG(q,"t.png")}
# run p(c(0,1,2,3,4,5))
```
[![enter image description here](https://i.stack.imgur.com/oV58G.png)](https://i.stack.imgur.com/oV58G.png)
[![enter image description here](https://i.stack.imgur.com/I9mDB.png)](https://i.stack.imgur.com/I9mDB.png)
[![enter image description here](https://i.stack.imgur.com/VuGPp.png)](https://i.stack.imgur.com/VuGPp.png)
[![enter image description here](https://i.stack.imgur.com/zy81g.png)](https://i.stack.imgur.com/zy81g.png)
[![enter image description here](https://i.stack.imgur.com/jQzRM.png)](https://i.stack.imgur.com/jQzRM.png)
[![enter image description here](https://i.stack.imgur.com/CmBOo.png)](https://i.stack.imgur.com/CmBOo.png)
[![enter image description here](https://i.stack.imgur.com/mLFRJ.png)](https://i.stack.imgur.com/mLFRJ.png)
[![enter image description here](https://i.stack.imgur.com/GOI15.png)](https://i.stack.imgur.com/GOI15.png)
[![enter image description here](https://i.stack.imgur.com/2DN85.png)](https://i.stack.imgur.com/2DN85.png)
[![enter image description here](https://i.stack.imgur.com/jIzj4.png)](https://i.stack.imgur.com/jIzj4.png)
lol at writing to disk, then reading from disk edit away the black fill.
[Answer]
# Python 3, 326 325 bytes
```
import numpy
from skimage import io,transform as t,filters as f
r=[[1]*5,[0]*5]
for c in map(int,input()):r+=[map(float,bin(0x3f1fa7e1bd7b5aff84ff6b7fd6f087ff5ff6bf)[2:][15*c+5*i:15*c+5*-~i])for i in[0,1,2]]+[[0]*5]
r+=[[1]*5]
p=[[1]*len(r)]
r=p+list(zip(*r))+p
io.imsave("o.png",1-f.sobel((t.rescale(numpy.array(r),16,0))))
```
[Answer]
# BBC BASIC, 182 ASCII characters (tokenised filesize 175 bytes)
Download interpreter at <http://www.bbcbasic.co.uk/bbcwin/bbcwin.html>
```
I.n$
F.j=0TOLENn$*4p=ASCM."?@\@?[@_?DTP?TT@?pv@?PTD?@TD?||@?@T@?PT@",VALM.n$,j/4+1,1)*4+1+j MOD4)F.k=0TO4p*=2q=64A.p
V.537;q;0;2585;0;q;537;-q;0;2585;0;-q;25;0;64;
N.MOVEBY 64,-320N.
```
Scoring: When the above program is pasted into the editor and run, the editor will expand the abbreviated keywords into full keywords onscreen, though they are actually only 1 byte after tokenisation. (Example `I.`=`INPUT` storage space 1 byte.)
**Explanation**
I will just explain what the VDU line does: it draws a box by bit-flipping the current pixel colour on the screen. This means that (with a bit of care with the corners) it is possible simply to draw one cell next to each other, and the intervening edge will cancel out and disappear due to double drawing.
Close examination will reveal that the top right and bottom left corners of a cell are drawn but the top left and bottom right are missing ("rounded") in order to make this work.
After the cell is drawn, the graphics cursor is moved up 32 pixels ready for the next cell to be drawn.
The rest of the program is a fairly straightforward ASCII bitmap decompression. The dimensions of the cell are 64x64 units for golfing/compatability with the way the bitmap is decompressed. `q` controls the size of the cell that is plotted: 64x64 units for a cell that is present, 0x0 for a cell that is absent.
**Ungolfed code**
```
  m$="?@\@?[@_?DTP?TT@?pv@?PTD?@TD?||@?@T@?PT@" :REM bitmap for digits, including column of filled cells at left. BBC strings are 1-indexed
  INPUTn$                                       :REM user input
  FORj=0 TO LENn$*4                             :REM iterate 4 times per input digit, plus once more (plot column 0 of imaginary digit to finish)
    d=VAL MID$(n$,j/4+1,1)                      :REM extract digit from n$ (1-character string). VAL of empty string = 0, so 123->1,1,1,1,2,2,2,2,3,3,3,3,0
    p=ASC MID$(m$,d*4+1+j MOD4)                 :REM get column bitmap from m$ d*4 selects digit, j MOD4 selects correct column of digit, add 1 to convert to 1-index
    FORk=0TO4                                   :REM for each cell in the column
      p*=2                                      :REM bitshift p
      q=64ANDp                                  :REM find size of cell to draw. 64 for a filled cell, 0 for an absent cell.
      VDU537;q;0;                               :REM line q units right, inverting existing screen colour. Draw last pixel (will be inverted next line)
      VDU2585;0;q;                              :REM line q units up, inverting existing screen colour. Dont draw last pixel (will be filled in next line)
      VDU537;-q;0;                              :REM line q units left, inverting existing screen colour. Draw last pixel (will be inverted next line)
      VDU2585;0;-q;                             :REM line q units down, inverting existing screen colour. Dont draw last pixel (avoid inverting 1st pixel of 1st line)
      VDU25;0;64;                               :REM move up 64 units for cell above
    NEXT
    MOVEBY 64,-320                              :REM move right and down for next column.
  NEXT
```
**Output**
The `MOVE`s are just get the output to appropriate heights on the screen. BBC basic uses 2 units = 1 pixel in this mode, so the cells are actually 32x32 pixels.
[![enter image description here](https://i.stack.imgur.com/1FBNo.png)](https://i.stack.imgur.com/1FBNo.png)
[Answer]
## C#, 768 773 776 bytes
```
namespace System.Drawing{class P{static void Main(string[]a){uint[]l={0xEBFBFFFC,0xB89B21B4,0xABFFF9FC,0xAA1269A4,0xFFF3F9FC};var w=a[0].Length*80+20;var b=new Bitmap(w,100);var g=Graphics.FromImage(b);g.FillRectangle(Brushes.Black,0,0,w,100);for(int i=0;i<a[0].Length;i++)for(int r=0;r<5;r++)for(int c=0;c<3;c++)if((l[r]&((uint)1<<(175-a[0][i]*3-c)))>0)g.FillRectangle(Brushes.White,20*(1+i*4+c),20*r,20,20);for(int x=1;x<w-1;x++)for(int y=1;y<99;y++)if(b.GetPixel(x,y).B+b.GetPixel(x+1,y).B+b.GetPixel(x,y+1).B+b.GetPixel(x,y-1).B+b.GetPixel(x+1,y-1).B+b.GetPixel(x+1,y+1).B+b.GetPixel(x-1,y+1).B+b.GetPixel(x-1,y-1).B==0)b.SetPixel(x,y,Color.Red);for(int x=1;x<w-1;x++)for(int y=1;y<99;y++)if(b.GetPixel(x,y).R>0)b.SetPixel(x,y,Color.White);b.Save(a[0]+".bmp");}}}
```
Takes the number as command line argument. Outputs a nice, clean, non-aliased BMP image with the number as the name.
Original before golfing:
```
namespace System.Drawing
{
    class P
    {
        static void Main(string[] args)
        {
            var numbers = args[0];
            uint[] lines = {
                0xEBFBFFFC, // 111 010 111 111 101 111 111 111 111 111 00
                0xB89B21B4, // 101 110 001 001 101 100 100 001 101 101 00
                0xABFFF9FC, // 101 010 111 111 111 111 111 001 111 111 00
                0xAA1269A4, // 101 010 100 001 001 001 101 001 101 001 00
                0xFFF3F9FC  // 111 111 111 111 001 111 111 001 111 111 00
            };
            var width = numbers.Length*4 + 1;
            var bmp = new Bitmap(width*20, 5*20);
            using (var gfx = Graphics.FromImage(bmp))
            {
                gfx.FillRectangle(Brushes.Black, 0, 0, width*20+2, 5*20+2);
                // Process all numbers
                for (int i = 0; i < numbers.Length; i++)
                {
                    var number = numbers[i]-'0';
                    for (int line = 0; line < 5; line++)
                    {
                        for (int col = 0; col < 3; col++)
                        {
                            if ((lines[line] & ((uint)1<<(31-number*3-col))) >0)
                                gfx.FillRectangle(Brushes.White, 20*(1 + i * 4 + col), 20*line, 20 , 20 );
                        }
                    }
                }
                // Edge detection
                for (int x = 1; x < width*20-1; x++)
                {
                    for (int y = 1; y < 5*20-1 ; y++)
                    {
                        if (bmp.GetPixel(x,y).B +
                            bmp.GetPixel(x + 1, y).B +
                                bmp.GetPixel(x, y + 1).B +
                                bmp.GetPixel(x, y - 1).B +
                                bmp.GetPixel(x + 1, y - 1).B +
                                bmp.GetPixel(x + 1, y + 1).B + 
                                bmp.GetPixel(x - 1, y + 1).B + 
                                bmp.GetPixel(x - 1, y - 1).B == 0)
                                bmp.SetPixel(x, y, Color.Red);
                    }
                }
                // Convert red to white
                for (int x = 1; x < width * 20 - 1; x++)
                {
                    for (int y = 1; y < 5 * 20 - 1; y++)
                    {
                        if (bmp.GetPixel(x, y).R>0)
                            bmp.SetPixel(x, y, Color.White);
                    }
                }
            }
            bmp.Save(@"c:\tmp\test.bmp");
        }
    }
}
```
[Answer]
# Mathematica 328 bytes
```
j@d_:=Partition[IntegerDigits[FromDigits[d/.Thread[ToString/@Range[0,9]->StringPartition["75557262277174771717557117471774757711117575775717",5]],16],2, 20]/.{0->1,1->0},4];j@"*"=Array[{1}&,5];
w@s_:=  ColorNegate@EdgeDetect@Rasterize@ArrayPlot[Thread[Join@@Transpose/@j/@Characters@(s<>"*")],Frame->False,ImageSize->Large]
```
---
```
w["07299361548"]
w["19887620534"]
```
[![pic](https://i.stack.imgur.com/uBiqt.png)](https://i.stack.imgur.com/uBiqt.png)
---
## Explanation
Four bits will be used in each of 5 lines of cells for each input digit. 
`"75557262277174771717557117471774757711117575775717"`represents 0 to 9 as bitmaps.
The first 5 digits in the large integer above, namely `75557` indicate how each array row for zero should be displayed. `7` will represent `{0,1,1,1}`, that is, a white cell, followed, on its right, by 3 black cells; the leading `0` is a blank space to separate displayed digits. `5` corresponds to `{0,1,0,1}`, that is white, black, white, black cells.
The following produces a list of replacement rules:
```
Thread[ToString /@ Range[0, 9] -> StringPartition["75557262277174771717557117471774757711117575775717", 5]]
```
> 
> {"0" -> "75557", "1" -> "26227", "2" -> "71747", "3" -> "71717", 
>  "4" -> "55711", "5" -> "74717", "6" -> "74757", "7" -> "71111", 
>  "8" -> "75757", "9" -> "75717"}
> 
> 
> 
Note that when `3` is input, it will be replaced by `71717`
This representation is expressed in binary:
```
p = Partition[IntegerDigits[FromDigits["3" /. {"3" -> "71717"}, 16], 2, 20], 4]
```
> 
> {{0, 1, 1, 1}, {0, 0, 0, 1}, {0, 1, 1, 1}, {0, 0, 0, 1}, {0, 1, 1, 1}} 
> 
> 
> 
Its black-white inverse is found by simply exchanging the `1`s and `0`s.
```
q = p /. {0 -> 1, 1 -> 0}
```
> 
> {{1, 0, 0, 0}, {1, 1, 1, 0}, {1, 0, 0, 0}, {1, 1, 1, 0}, {1, 0, 0, 0}}
> 
> 
> 
---
Let's see what `p` and `q` look like when displayed by `ArrayPlot`:
```
ArrayPlot[#, Mesh -> True, ImageSize -> Small, PlotLegends -> Automatic] & /@ {p, q}
```
[![pis](https://i.stack.imgur.com/Q8Ikz.png)](https://i.stack.imgur.com/Q8Ikz.png)
---
This simply joins the arrays of zeros and ones for each digit before rendering the big array via `ArrayPlot`. `*` is defined in `j` as the final vertical space after the last digit.
```
Thread[Join @@ Transpose /@ j /@ Characters@(s <> "*")]
```
]