Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added option to retrieve the colors used in the QR code from the image. #76

Open
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

david-boles
Copy link

@david-boles david-boles commented Jul 13, 2018

Implementation for #73.

@cozmo
Copy link
Owner

cozmo commented Jul 18, 2018

Awesome work on the PR. It's been a pretty busy week for me, but I'll give it a look soon.

Meanwhile in #77 I've added the options object for another option we needed to add, so you may be able to leverage some of the work there.

@cozmo
Copy link
Owner

cozmo commented Jul 19, 2018

If you want faster iteration on this lint stuff you can just run npm run-script lint locally.

@david-boles
Copy link
Author

That probably would have been a good idea :)

@david-boles
Copy link
Author

@cozmo It looks like the tests are failing due to how the objects are getting serialized? Not sure how to fix that...

@david-boles
Copy link
Author

Yeah, I'm not sure how to fix that. it seems to be caused by data type issues...

Copy link
Owner

@cozmo cozmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! Thanks for submitting this, and sorry for the slight delay in review, been a busy week.

In general things look pretty good, I left some small comments on a few things.

As for testing, my thinking is that instead of modifying the end to end tests (which mostly serve to make sure changes don't drastically decrease the average success rate) I'd add a few specific hand crafted tests to src/color-retriever/test.ts - In the style of decoder. Take a few images and write descriptive test cases, feeding them into and out of the retrieve color function. This allows us to test retrieve colors carefully, where as the end to end tests are pretty noisy so probably wouldn't serve to catch any bugs/changes that changed retrieve colors.

Does that make sense? If not happy to discuss.

import { Point } from "../Point";

// Stores two RGBA values (0-255, [r, g, b, a])
export interface QRColors {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference would be to return a color as

interface Color { r: number; g: number; b: number; }

As I think it's a better API for the user, and I don't think we get many gains for using typed arrays for this small of data. I also don't think we care about alpha - we ignore it everywhere else.

// Color space conversions from http://www.easyrgb.com/en/math.php

// Converts an RGB color ([r, g, b] or [r, g, b, a] - a is ignored) to CIELab ([L*, a*, b*]).
function rgbToLab(rgb: Uint8ClampedArray): number[] {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference would be that these functions took in and returned named params, either in the form of an object, or as named arguments like (function(r: number, g:number, b:number){}` I think this makes them clearer to read and also less prone to error.

color space for averaging (with no regard for alpha), and then converted back to RGB. Alpha values are simply averaged
directly. */
export function retrieveColors(location: QRLocation,
extracted: {matrix: BitMatrix; mappingFunction: (x: number, y: number) => Point; },
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of defining this here, might make sense to define an Extracted type in extractor and then reference it here, I feel like that would be a little cleaner per se.

src/index.ts Outdated
}

function scan(matrix: BitMatrix): QRCode | null {
function scan(matrix: BitMatrix, sourceData: Uint8ClampedArray, sourceWidth: number, scanOptions: Options): QRCode | null {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this makes sense or not, but the width and the height are already available on the binarized bitMatrix. Not sure we need to pass them in again.

@david-boles
Copy link
Author

david-boles commented Jul 22, 2018

Those all sound good, I'll update it soon.

@david-boles
Copy link
Author

For testing I added some checks for the color space transformations and effectively end-to-end-tests.ts but that only looks at color. For populating the test data I just added on to generate-test-data.ts but that might want to be broken out into a separate script.

Copy link
Owner

@cozmo cozmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some very basic comments but this looks great! Sorry again for the delay, been awhile since I've been able to sit down and go through PRs/issues. Hope I haven't been blocking you.

}

interface CIELabColor {
L: number;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it expected that the L is capitalized but the other attribute aren't?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the reference material I've seen generally capitalizes them that way... Up to you though, obviously it doesn't follow javascript conventions.


// Color space conversions from http://www.easyrgb.com/en/math.php

// Converts an RGB color ([r, g, b] or [r, g, b, a] - a is ignored) to CIELab ([L*, a*, b*]).
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment isn't strictly correct anymore I don't think - Can probably just remove the array descriptions from it?

return {L: l, a, b};
}

// Converts a CIELab color ([L*, a*, b*] - ignores additional values) to RGB ([r, g, b]).
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same re: this comment no longer needing the array descriptions.

const output = jsQR(imageData.data, imageData.width, imageData.height, {retrieveColors: true});

await fs.writeFile(path.join("src", "color-retriever", "test-data", t, "output.json"), JSON.stringify(output.colors, null, 2), "utf8");
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't think we strictly need this, since I think the test cases are sort of...stand alone. Now that we've created them I would expect them to not break as we change the library? If they do we can re-visit needing to autogen them, but for now would be fine leaving them standalone?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems useful to leave for adding more color tests but splitting it out makes sense. I'll make it a separate file in the color retrieving folder?

function roundComponents(color) {
for(var component in color) {
color[component] = Math.round(color[component])
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function doesn't return anything so I don't actually think the tests are doing anything, since they're always comparing undefined to undefined

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should work (given the mutability of arrays) but definitely not intentional :)

Copy link
Owner

@cozmo cozmo Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mutability doesn't matter here I don't think. This function has no return, and so as such returns undefined. We use it in the assertions above, so they all become expect(undefined).toBe(undefined). Unless I'm missing something?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh boy, I must have been reeeealy out of it. NVM

@cozmo
Copy link
Owner

cozmo commented Aug 15, 2018

Just left one final comment since I tried to merge this. but realized the conversions tests weren't actually doing anything. Right now there's a merge conflict on master, but feel free to ignore that, I'll handle it since I caused it. That said not really sure how best to fix these tests so would rather defer to you.

@david-boles
Copy link
Author

No problem, I've just been using a build of my repo for now. I've gotten a bit busier myself but I'll try to sit down and implement your comments today or tomorrow. A replied to a couple of things immediately, I'll leave the capitalization of L up to you.

@david-boles
Copy link
Author

@cozmo Sorry for disappearing for so long! It's been a busy school year... If I finish up this pull request (I think I had more to do even though you approved it...), still up for merging it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants