diff --git a/lib/Dither.dart b/lib/Dither.dart new file mode 100644 index 0000000..7f1cdb9 --- /dev/null +++ b/lib/Dither.dart @@ -0,0 +1,176 @@ +import 'dart:html'; +import 'dart:typed_data'; + +class Pixed { + static PixelArray greyscale(PixelArray image) { + PixelArray pxArr = new PixelArray.fromPixelArray(image); + + for (var y = 0; y < pxArr.getHeight(); y++) { + for (var x = 0; x < pxArr.getWidth(); x++) { + var px = pxArr.getPixel(x, y); + int average = ((px.r+px.g+px.b) / 3).round(); + px.r = average; + px.g = average; + px.b = average; + } + } + return pxArr; + } + + static PixelArray quantize(PixelArray image, [int steps=1]) { + PixelArray pxArr = new PixelArray.fromPixelArray(image); + for (var y = 0; y < pxArr.getHeight(); y++) { + for (var x = 0; x < pxArr.getWidth(); x++) { + var px = pxArr.getPixel(x, y); + px.r = (steps * px.r / 255).round() * (255 ~/ steps); + px.g = (steps * px.g / 255).round() * (255 ~/ steps); + px.b = (steps * px.b / 255).round() * (255 ~/ steps); + } + } + return pxArr; + } + + static PixelArray calcQuantizeError(PixelArray original, PixelArray quantized) { + PixelArray pxArr = new PixelArray.fromPixelArray(original); + for (var y = 0; y < pxArr.getHeight(); y++) { + for (var x = 0; x < pxArr.getWidth(); x++) { + Pixel px = pxArr.getPixel(x, y); + Pixel quant = quantized.getPixel(x, y); + px.r = px.r - quant.r; + px.g = px.g - quant.g; + px.b = px.b - quant.b; + } + } + return pxArr; + } +} + +class Pixel { + int x; + int y; + int r; + int g; + int b; + int a; + + Pixel(this.x, this.y, this.r, this.g, this.b, this.a); + + int getBytePos(int imageWidth) { + return (x+y*imageWidth)*4; + } + + void setRGB(int r, int g, int b) { + this.r = r; + this.g = g; + this.b = b; + } + + @override + String toString() { + return 'Pixel at $x, $y: {r: $r, g: $g, b: $b, a: $a}'; + } + + +} + +class PixelArray { + //TODO Implement iterable + List> pixels; + + PixelArray(int width, int height) { + pixels = new List(height); + for (int y = 0; y < height; y++) { + pixels[y] = new List(width); + for (int x = 0; x < height; x++) { + pixels[y][x] = new Pixel(x, y, 0, 0, 0, 0); + } + } + } + + PixelArray.fromByteArray(Uint8ClampedList array, int imageWidth) { + pixels = new List(array.length~/imageWidth~/4); + int y = 0; + int x = 0; + pixels[y] = new List(imageWidth); + print(pixels[0].length.toString() + ","+ pixels.length.toString()); + for (var pos = 0; pos < array.length; pos = pos + 4) { + if (x >= imageWidth) { + x = 0; + y++; + pixels[y] = new List(imageWidth); + } + pixels[y][x] = new Pixel(x, y, array[pos], array[pos+1], array[pos+2], array[pos+3]); + x++; + } + } + + PixelArray.fromImageData(ImageData imagedata, int imageWidth): this.fromByteArray(imagedata.data, imageWidth); + + PixelArray.fromPixelArray(PixelArray pixelArray) { + pixels = new List>.from(pixelArray.pixels); + } + + Uint8ClampedList toByteArray() { + //TODO: look for longest array, or each line separately. Only gets width from line 1 currently. + Uint8ClampedList result = new Uint8ClampedList(getHeight()*getWidth()*4); + int x = 0; + int y = 0; + for (var i = 0; i < result.length; i = i + 4) { + if (x >= getWidth()) { + y++; + x = 0; + } + result[i] = pixels[y][x].r; + result[i+1] = pixels[y][x].g; + result[i+2] = pixels[y][x].b; + result[i+3] = pixels[y][x].a; + + x++; + } + + return result; + } + + ImageData toImageData() { + return new ImageData(this.toByteArray(), this.getWidth(), this.getHeight()); + } + + Pixel getPixel(int x, int y) { + return pixels[y][x]; + } + + void setPixel(Pixel pixel, [int x, int y]) { + if (x != null && y != null && getHeight() < y && getWidth() < x) { + pixel.x = x; + pixel.y = y; + pixels[y][x] = pixel; + return; + } else if (getHeight() <= pixel.y || getWidth() <= pixel.x) { + return; + } else { + pixels[pixel.y][pixel.x] = pixel; + return; + } + } + + int getWidth() { + //TODO find longest/shortest width not at 0 (support for non square img) + return pixels[0].length; + } + + int getHeight() { + return pixels.length; + } + + PixelArray clone() { + PixelArray pxArr = new PixelArray(getWidth(), getHeight()); + for (var y = 0; y < getHeight(); y++) { + for (var x = 0; x < getWidth(); x++) { + Pixel px = getPixel(x, y); + Pixel newPix = new Pixel(x, y, px.r, px.g, px.b, px.a); + pxArr.setPixel( newPix, x, y ); + } + } + return pxArr; + } +} \ No newline at end of file diff --git a/lib/dither.dart b/lib/dither.dart new file mode 100644 index 0000000..7c5d5e3 --- /dev/null +++ b/lib/dither.dart @@ -0,0 +1,3 @@ +library dither; + +export 'Dither.dart'; \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 522ef38..02840b1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,6 @@ environment: sdk: '>=1.20.1 <2.0.0' dependencies: - image: "^1.1.29" # path: ^1.4.1 dev_dependencies: diff --git a/web/main.dart b/web/main.dart index 23f277c..ef830c7 100644 --- a/web/main.dart +++ b/web/main.dart @@ -1,56 +1,31 @@ import 'dart:html'; -import 'package:image/image.dart'; +import 'package:dart_floyd_steinberg_dithering/Dither.dart'; CanvasElement input; CanvasElement output; ImageElement inputImg; +ImageElement outputImg; void main() { inputImg = new ImageElement(src: 'kitten.jpg', width: 712, height: 470); input = document.querySelector('#input'); - print(input); - inputImg.onLoad.listen(imgLoaded); - output = document.querySelector('#output'); - output.context2D.fillRect(0, 0, output.width, output.height); + inputImg.onLoad.listen(imgLoaded); } void imgLoaded(Event e) { print("image loaded"); input.context2D.drawImage(inputImg, 0, 0); - Image outputImg = editImage( getImageFromCanvas(input) ); + PixelArray px = new PixelArray.fromImageData(getImageData(input), 712); + px = Pixed.greyscale(px); - drawImageToCanvas(output, outputImg ) ; + output.context2D.putImageData(px.toImageData(), 0, 0); } -Image getImageFromCanvas(CanvasElement input) { - ImageData data = input.context2D.getImageData(0, 0, input.width, input.height); - return new Image.fromBytes(input.width, input.height, data.data); -} - -void drawImageToCanvas(CanvasElement canvas, Image image) { - var imageData = canvas.context2D.createImageData(image.width, image.height); - imageData.data.setRange(0, imageData.data.length, image.getBytes()); - - canvas.context2D.putImageData(imageData, 0, 0); -} - -Image editImage(Image image) { - - - image = contrast( image, 200); - - for (var y = 0; y < image.height; y++) { - for (var x = 0; x < image.width; x++) { -// print(image.getPixel(x, y)); - } - } - - - - return image; +ImageData getImageData(CanvasElement canvas) { + return canvas.context2D.getImageData(0, 0, canvas.width, canvas.height); } \ No newline at end of file diff --git a/web/styles.css b/web/styles.css index 6a88d3b..b8742bc 100644 --- a/web/styles.css +++ b/web/styles.css @@ -6,11 +6,11 @@ html, body { margin: 0; padding: 0; font-family: 'Roboto', sans-serif; - background: gainsboro; + background: black; } canvas { - padding: 00px; + padding: 0px; text-align: center; }