-
Notifications
You must be signed in to change notification settings - Fork 607
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
base: master
Are you sure you want to change the base?
Conversation
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. |
If you want faster iteration on this lint stuff you can just run |
That probably would have been a good idea :) |
@cozmo It looks like the tests are failing due to how the objects are getting serialized? Not sure how to fix that... |
Yeah, I'm not sure how to fix that. it seems to be caused by data type issues... |
There was a problem hiding this 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.
src/color-retriever/index.ts
Outdated
import { Point } from "../Point"; | ||
|
||
// Stores two RGBA values (0-255, [r, g, b, a]) | ||
export interface QRColors { |
There was a problem hiding this comment.
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.
src/color-retriever/index.ts
Outdated
// 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[] { |
There was a problem hiding this comment.
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.
src/color-retriever/index.ts
Outdated
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; }, |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
Those all sound good, I'll update it soon. |
For testing I added some checks for the color space transformations and effectively |
There was a problem hiding this 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; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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*]). |
There was a problem hiding this comment.
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]). |
There was a problem hiding this comment.
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"); | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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]) | ||
} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 :)
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
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. |
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. |
@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? |
Implementation for #73.