davidrusu / marker.network

Marker Network Designer
https://marker.network
31 stars 1 forks source link

Poor rasterization quality #4

Open sterlingbaldwin opened 2 years ago

sterlingbaldwin commented 2 years ago

Turning drawings in notebooks into images is a consistent hassle, and so you really cant be blamed for it, but the quality of the rasterized notebooks could probably be improved. The first image below is a screen shot of the output from running the maker.network app, the second is from the remarkable app. To note is that the remarkable app itself exports pretty bad quality pdfs as well. The best Ive seen so far is from the RCU, which I think uses all open source methods, so maybe his rendering method could be copied over.

A possible solution for this would be to allow users to specify arbitrary images from the filesystem of the computer running the maker.network app, thus allowing them to handle rastering the images themselves.

I should mention that these issues were drawn using the pencil brush, and so the issue with the quality is based on the fractional pressure level from pressing lightly with the stylus. When I take notes I always use the fineliner brush, and so I dont think its an issue since the fineliner is always at 100%.

Screen Shot 2021-12-12 at 14 21 18 Screen Shot 2021-12-12 at 14 21 35
davidrusu commented 2 years ago

I did some experimenting with how to handle pencil sketches and it's hard, even the second rendering you have their almost looks like someone used the spraycan tool in MS Paint for the shading.

I think we want to replicate the grain of the paper to get shading, I was experimenting with using perlin noise as the paper grain and pen-strokes as a mask of the grain.

Copy the following sketch into https://editor.p5js.org/ and draw (slowly) on the canvas. This is very slow code, but it shows how we might get some paper grain coming through.

let s = 2; // canvas resolution (smaller is higher resolution)
let ns = 0.2; // grain size (bigger is smaller grain)

let buffer;

function setup() {
  createCanvas(400, 400);
  buffer = createImage(width, height);
  for (let i = 0; i < buffer.width; i++) {
    for (let j = 0; j < buffer.height; j++) {
        buffer.set(i, j, color(255, 255, 255, 0));
    }
  }
}

function step(v, t) {
  if (v > t) {
    return 1;
  } else {
    return 0
  }
}

function mouseDragged() {
  buffer.loadPixels();
  for (let i = 0; i < buffer.width; i++) {
    for (let j = 0; j < buffer.height; j++) {
      let d = dist(i, j, mouseX, mouseY) / 50;
      if (d < 1) {
        let c = buffer.get(i, j);
        let a = min(255, 255 * (1 - pow(d, 0.5)) * 0.5 + alpha(c));
        buffer.set(i, j, color(255, 255, 255, a));
      }
    }
  }
  buffer.updatePixels();
  loop();
}

function draw() {
  background(255);
  buffer.loadPixels();
  let ns = 0.2;
  noStroke();
  for (var x = 0; x < width; x+=s) {
    for (var y = 0; y < height; y+=s) {
      let t = alpha(buffer.get(x, y)) / 255;
      fill(step(noise(x * ns,y * ns), t) * 255);
      rect(x, y, s, s);
    }
  }

  //image(buffer, 0, 0);
  noLoop();
}
davidrusu commented 2 years ago

Better results, still not great:

let s = 2; // canvas resolution (smaller is higher resolution)
let ns = 0.0051; // grain size (bigger is smaller grain)

let buffer;
let noiseBuf;
let compositeBuf;

// let paperBuf;
// function preload() {
//   paperBuf = loadImage("https://www.publicdomainpictures.net/pictures/110000/velka/paper-grain-texture.jpg");
// }

function paperTexture(x, y) {
  let grainS = 10;
  let grainA = noise(x * ns * 0.020, y * ns * 0.020) * PI * 2;
  let grainX = x + cos(grainA) * grainS;
  let grainY = y - sin(grainA) * grainS;
  return 1 - (noise(grainX * ns * width * 0.01, grainY * ns * height * 0.2 + grainX * 0.05) * 0.7);
}

function setup() {
  createCanvas(400, 400);
  noiseDetail(9, 0.7)
  buffer = createImage(width, height);
  noiseBuf = createImage(width, height);
  compositeBuf = createImage(width, height);

  buffer.loadPixels();
  noiseBuf.loadPixels();
  for (let x = 0; x < width; x++) {
    for (let y = 0; y < height; y++) {
        buffer.set(x, y, color(255));
        noiseBuf.set(x, y, color(paperTexture(x, y) * 255));
    }
  }
  buffer.updatePixels();
  noiseBuf.updatePixels();
}

function step(v, t) {
  if (v > t) {
    return 1;
  } else {
    return 0
  }
}

function mouseDragged() {
  buffer.loadPixels();
  let BRUSH_SIZE = 10;
  for (let x = max(0, mouseX - BRUSH_SIZE); x < min(buffer.width, mouseX + BRUSH_SIZE); x++) {
    for (let y = max(0, mouseY - BRUSH_SIZE); y < min(buffer.height, mouseY + BRUSH_SIZE); y++) {
      let d = dist(x, y, mouseX, mouseY) / BRUSH_SIZE;
      if (d < 1) {
        let c = buffer.get(x, y);
        let a = max(0, 255 * (1 - pow((255 - red(c)) / 255 + 0.2, 1.5)));
        buffer.set(x, y, color(a));
      }
    }
  }
  buffer.updatePixels();
  loop();
  print("mouse pressed")
}

function draw() {
  background(255);
  compositeBuf.loadPixels();
  buffer.loadPixels();
  noiseBuf.loadPixels();
  // arrayCopy(noiseBuf.pixels, 0, img.pixels, 0, 4)
  for (let i = 0; i < noiseBuf.pixels.length; i ++) {
    compositeBuf.pixels[i] = noiseBuf.pixels[i]
  }
  //img.pixels = noiseBuf.pixels;
  compositeBuf.updatePixels();

  compositeBuf.blend(buffer, 0, 0, width, height, 0, 0, width, height, MULTIPLY)
//   compositeBuf.mask(buffer);
   compositeBuf.filter(THRESHOLD, 0.2)
  // buffer.loadPixels();
  // let ns = 0.2;
  // noStroke();
  // for (var x = 0; x < width; x+=s) {
  //   for (var y = 0; y < height; y+=s) {
  //     let t = alpha(buffer.get(x, y)) / 255;
  //     fill(step(noise(x * ns,y * ns), t) * 255);
  //     rect(x, y, s, s);
  //   }
  // }

  image(compositeBuf, 0, 0);
  //image(buffer, 0, 0);
  // image(noiseBuf, 0, 0);
  noLoop();
}