Skip to content

Commit

Permalink
fill bitmaps with opaque black instead of opaque white
Browse files Browse the repository at this point in the history
validate coords before setting pixels
update tests to use opaque black
start on transform rect test
  • Loading branch information
Josh Marinacci committed Feb 7, 2023
1 parent 2063ef0 commit c63da82
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 17 deletions.
12 changes: 12 additions & 0 deletions .run/test.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="test" type="js.build_tools.npm" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="test" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>
26 changes: 20 additions & 6 deletions src/bitmap.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {NAMED_COLORS} from "./named_colors.js"
import {NAMED_COLORS, OPAQUE_BLACK} from "./named_colors.js"
import {Context} from "./context.js"
import {fromBytesBigEndian, getBytesBigEndian} from './uint32.js'

Expand Down Expand Up @@ -35,7 +35,9 @@ export class Bitmap {
*/
this.data = Buffer.alloc(w*h*4);

const fillval = NAMED_COLORS.transparent
// per the spec, fill it with opaque black
// https://html.spec.whatwg.org/multipage/canvas.html#output-bitmap
const fillval = OPAQUE_BLACK
for(let j=0; j<h; j++) {
for (let i = 0; i < w; i++) {
this.setPixelRGBA(i, j, fillval);
Expand Down Expand Up @@ -73,10 +75,7 @@ export class Bitmap {
* @memberof Bitmap
*/
setPixelRGBA(x,y,rgba) {
if(x < 0) return
if(y < 0) return
if(x >= this.width) return
if(y >= this.height) return
this.validate_coords(x,y)
let i = this.calculateIndex(x, y);
const bytes = getBytesBigEndian(rgba);
this.data[i+0] = bytes[0];
Expand Down Expand Up @@ -118,6 +117,7 @@ export class Bitmap {
* @memberof Bitmap
*/
getPixelRGBA(x,y) {
this.validate_coords(x,y)
let i = this.calculateIndex(x, y);
return fromBytesBigEndian(
this.data[i+0],
Expand Down Expand Up @@ -180,4 +180,18 @@ export class Bitmap {
}
}

_isValidCoords(x,y) {
if(x<0) return false
if(y<0) return false
if(x>=this.width) return false
if(y>=this.height) return false
return true
}

validate_coords(x, y) {
if(x<0) throw new Error(`Invalid Index: x ${x} <0`)
if(y<0) throw new Error(`Invalid Index: y ${y} <0`)
if(x>=this.width) throw new Error(`Invalid Index: x ${x} >= width ${this.width}`)
if(y>=this.height) throw new Error(`Invalid Index: x ${x} >= width ${this.height}`)
}
}
12 changes: 6 additions & 6 deletions src/context.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use strict";

import {Line} from "./line.js"
import {NAMED_COLORS} from './named_colors.js'
import {NAMED_COLORS, TRANSPARENT_BLACK} from './named_colors.js'
import {Bounds, calc_min_bounds, Point, toDeg, toRad} from "./point.js"
import * as TEXT from "./text.js"
import * as trans from "./transform.js"
Expand Down Expand Up @@ -332,7 +332,7 @@ export class Context {
fillRect(x,y,w,h) {
for(let i=x; i<x+w; i++) {
for(let j=y; j<y+h; j++) {
this.fillPixel(i,j);
this.fillPixelWithColor(i,j,this.calculateRGBA(i,j))
}
}
}
Expand All @@ -354,7 +354,7 @@ export class Context {
clearRect(x,y,w,h) {
for(let i=x; i<x+w; i++) {
for(let j=y; j<y+h; j++) {
this.bitmap.setPixelRGBA(i,j,0x00000000);
this.bitmap.setPixelRGBA(i,j,TRANSPARENT_BLACK);
}
}
}
Expand Down Expand Up @@ -398,11 +398,10 @@ export class Context {
if(!this.pixelInsideClip(x,y)) {
return
}

if(!this.bitmap._isValidCoords(x,y)) return
const new_pixel = this.calculateRGBA(x, y)
const old_pixel = this.bitmap.getPixelRGBA(x, y)
const final_pixel = this.composite(x, y, old_pixel, new_pixel)

this.bitmap.setPixelRGBA(x,y,final_pixel);
}

Expand Down Expand Up @@ -446,6 +445,7 @@ export class Context {
return
}

if(!this.bitmap._isValidCoords(x,y)) return
const new_pixel = col
const old_pixel = this.bitmap.getPixelRGBA(x, y)
const final_pixel = this.composite(x, y, old_pixel, new_pixel)
Expand Down Expand Up @@ -622,7 +622,7 @@ export class Context {
)
if(src_bounds.contains(src_pt)) {
const rgba = bitmap.getPixelRGBA(src_pt.x, src_pt.y)
if(this.pixelInsideClip(dst_pt.x,dst_pt.y)) {
if(this.pixelInsideClip(dst_pt.x,dst_pt.y) && this.bitmap._isValidCoords(dst_pt.x,dst_pt.y)) {
this.bitmap.setPixelRGBA(dst_pt.x, dst_pt.y, rgba)
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/named_colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,7 @@ export const NAMED_COLORS = {
yellowgreen: 0x9acd32ff
}

export const TRANSPARENT_BLACK = 0x00000000
export const OPAQUE_BLACK = 0x000000FF


3 changes: 2 additions & 1 deletion test/clipping.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as pureimage from "../src/index.js"
import fs from 'fs'
import path from 'path'
import {write_png} from './common.js'
import {OPAQUE_BLACK} from '../src/named_colors.js'

describe('clipping tests',() => {
let image
Expand All @@ -15,7 +16,7 @@ describe('clipping tests',() => {
})

it('canvas is empty and clear', (done) => {
expect(image.getPixelRGBA(0, 0)).to.eq(0x00000000)
expect(image.getPixelRGBA(0, 0)).to.eq(OPAQUE_BLACK)
done()
})

Expand Down
5 changes: 3 additions & 2 deletions test/color.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import chai, {expect} from "chai"

import * as pureimage from "../src/index.js"
import {OPAQUE_BLACK} from '../src/named_colors.js'

describe('color',() => {
let image
Expand All @@ -12,7 +13,7 @@ describe('color',() => {
})

it('canvas is empty and clear', (done) => {
expect(image.getPixelRGBA(0,0)).to.eq(0x00000000)
expect(image.getPixelRGBA(0,0)).to.eq(OPAQUE_BLACK)
done()
})

Expand All @@ -39,4 +40,4 @@ describe('color',() => {
done()
})

})
})
4 changes: 2 additions & 2 deletions test/drawimage.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('drawImage',() => {
})

it('canvas is empty and clear', (done) => {
expect(image.getPixelRGBA(0,0)).to.eq(0x00000000)
expect(image.getPixelRGBA(0,0)).to.eq(0x000000FF)
done()
})

Expand Down Expand Up @@ -52,4 +52,4 @@ describe('drawImage',() => {
expect(image.getPixelRGBA(100,0)).to.eq(0x000000FF)
done()
})
})
})
36 changes: 36 additions & 0 deletions test/transforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,39 @@ describe("transform image",()=>{
})
})
})

describe("transform rect",() => {
let image
let context

beforeEach(() => {
image = pureimage.make(20,20)
context = image.getContext('2d')
context.fillStyle = 'white'
context.fillRect(0,0,20,20)
})
function fillRect() {
context.fillStyle = 'red'
context.fillRect(0,0,10,10)
context.fillRect(10,10,10,10)
}

it("draws two rects",(done)=>{
fillRect()
expect(image.getPixelRGBA(0, 0)).to.eq(0xFF0000FF)
expect(image.getPixelRGBA(10, 0)).to.eq(0xFFFFFFFF)
expect(image.getPixelRGBA(10, 10)).to.eq(0xFF0000FF)
write_png(image,'transform_rect_plain').then(() => done())
})

it("draws translated rects",(done)=>{
context.save();
context.translate(5, 0);
fillRect()
context.restore();
// expect(image.getPixelRGBA(0, 0)).to.eq(0xFFFFFFFF)
// expect(image.getPixelRGBA(10, 0)).to.eq(0xFF0000FF)
// expect(image.getPixelRGBA(10, 10)).to.eq(0xFFFFFFFF)
write_png(image,'transform_rect_translate').then(() => done())
})
})

0 comments on commit c63da82

Please sign in to comment.