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

.stats() implementation #915

Merged
merged 14 commits into from
Dec 9, 2017
Merged

.stats() implementation #915

merged 14 commits into from
Dec 9, 2017

Conversation

rn4391
Copy link

@rn4391 rn4391 commented Aug 18, 2017

Please review the code. Especially the C++ part as I am not very confident with the language. Let me know if something else or some other helper value like isOpaque needs to be exposed in the output.

@coveralls
Copy link

coveralls commented Aug 18, 2017

Coverage Status

Coverage decreased (-10.009%) to 89.309% when pulling cd97d38 on rnanwani:feature_stats_implementation into 791fd35 on lovell:master.

@lovell
Copy link
Owner

lovell commented Aug 19, 2017

Looks great, and with lots of tests too, thank you very much Rahul!

In terms of the sporadically failing values, perhaps there should be a margin of error for these? For example the difference in the sum of pixel values appears to be <0.1% across all platforms.

I realise the min and max coords will vary across test runs. Perhaps we could verify their values are positive integers that fall within the bounds of the image?

readable.pipe(pipeline);
});

it('Stream in, Promise out', function (done) {
Copy link
Owner

Choose a reason for hiding this comment

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

This test should be able to return the Promise instance, which will then remove the need to use done and catch.

Copy link
Author

Choose a reason for hiding this comment

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

.stats() does return a promise in this test. I am not sure if I got your point. A similar test exists for metadata() as well.

Copy link
Owner

Choose a reason for hiding this comment

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

mocha deals with tests that return (and reject) a Promise, e.g.:

  it('Stream in, Promise out', function () {
    const pipeline = sharp();

    fs
      .createReadStream(fixtures.inputJpg)
      .pipe(pipeline);

    return pipeline
      .stats()
      .then(function (stats) {
        ...
      });
  });

src/stats.cc Outdated
(baton->err).append(err.what());
}
if (imageType != sharp::ImageType::UNKNOWN) {
stats = image.stats();
Copy link
Owner

@lovell lovell Aug 19, 2017

Choose a reason for hiding this comment

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

Can stats() throw? This might need to live inside the try/catch block.

Copy link
Author

Choose a reason for hiding this comment

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

Copy link
Owner

Choose a reason for hiding this comment

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

libvips' C++ wrapper passes through call_option_string that can throw.

@coveralls
Copy link

coveralls commented Sep 21, 2017

Coverage Status

Coverage decreased (-1.0%) to 98.355% when pulling 8850096 on rnanwani:feature_stats_implementation into 3511723 on lovell:master.

readable.pipe(pipeline);
});

it('Stream in, Promise out', function (done) {
Copy link
Owner

Choose a reason for hiding this comment

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

mocha deals with tests that return (and reject) a Promise, e.g.:

  it('Stream in, Promise out', function () {
    const pipeline = sharp();

    fs
      .createReadStream(fixtures.inputJpg)
      .pipe(pipeline);

    return pipeline
      .stats()
      .then(function (stats) {
        ...
      });
  });

src/stats.cc Outdated
(baton->err).append(err.what());
}
if (imageType != sharp::ImageType::UNKNOWN) {
stats = image.stats();
Copy link
Owner

Choose a reason for hiding this comment

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

libvips' C++ wrapper passes through call_option_string that can throw.

@coveralls
Copy link

coveralls commented Nov 8, 2017

Coverage Status

Coverage decreased (-0.1%) to 99.186% when pulling 30540a0 on rnanwani:feature_stats_implementation into aad16ac on lovell:master.

@rn4391
Copy link
Author

rn4391 commented Nov 9, 2017

Is there anything I can do to fix this build?

@coveralls
Copy link

coveralls commented Nov 9, 2017

Coverage Status

Coverage decreased (-0.1%) to 99.186% when pulling 7ef26b1 on rnanwani:feature_stats_implementation into aad16ac on lovell:master.

Copy link
Owner

@lovell lovell left a comment

Choose a reason for hiding this comment

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

Hello, thanks for all the updates to this PR, I've added a few comments inline that should hopefully solve that final test failure.

src/stats.cc Outdated
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;

try {
std::tie(image, imageType) = OpenInput(baton->input, VIPS_ACCESS_SEQUENTIAL);
Copy link
Owner

Choose a reason for hiding this comment

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

Probably best to use the configured baton->accessMode instead of VIPS_ACCESS_SEQUENTIAL as this defaults to random, which avoids over-computation from the source decoder (and should fix those libtiff test errors).

src/stats.cc Outdated
int bands = image.bands();
double const max = MaximumImageAlpha(image.interpretation());
for (int b = 1; b <= bands; b++) {
ChannelStats cStats(stats.getpoint(STAT_MIN_INDEX, b).front(), stats.getpoint(STAT_MAX_INDEX, b).front(),
Copy link
Owner

Choose a reason for hiding this comment

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

I think the values returned by getpoint are double precision so some of these will require static_cast<int> conversion.


const fs = require('fs');
const assert = require('assert');
// const exifReader = require('exif-reader');
Copy link
Owner

Choose a reason for hiding this comment

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

These unused imports can be removed.

assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 83061892917));
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 101.44954540768993));
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 58.373870588815414));
assert.strictEqual(true, isInteger(stats.channels[0]['minX']) && isInRange(stats.channels[0]['minX'], 0, 2725));
Copy link
Owner

Choose a reason for hiding this comment

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

Perhaps split these assert(true, x && y) statements into two separate assert statements to aid debugging and remove conditional logic from tests.

@@ -4,6 +4,7 @@

- [clone](#clone)
- [metadata](#metadata)
- [stats](#stats)
Copy link
Owner

Choose a reason for hiding this comment

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

The docs/api-*.md files are autogenerated so this content needs to live in the jsdocs above the new stats function.

@coveralls
Copy link

coveralls commented Nov 14, 2017

Coverage Status

Coverage decreased (-0.1%) to 99.186% when pulling 2aea940 on rnanwani:feature_stats_implementation into aad16ac on lovell:master.

@coveralls
Copy link

coveralls commented Nov 14, 2017

Coverage Status

Coverage increased (+0.02%) to 99.349% when pulling 2aea940 on rnanwani:feature_stats_implementation into aad16ac on lovell:master.

@coveralls
Copy link

coveralls commented Nov 14, 2017

Coverage Status

Coverage increased (+0.02%) to 99.349% when pulling c8d01fe on rnanwani:feature_stats_implementation into aad16ac on lovell:master.

@lovell
Copy link
Owner

lovell commented Nov 14, 2017

This all looks great, thank you for the updates Rahul. As soon as the suit WIP branch is merged into master we can look at getting this merged in too for the v0.19.0 release.

@lovell lovell added this to the v0.19.0 milestone Nov 14, 2017
@lovell lovell merged commit d6aee8e into lovell:master Dec 9, 2017
@lovell
Copy link
Owner

lovell commented Dec 9, 2017

Merged to master, thanks Rahul, this will be in v0.19.0.

@sebastienbarre
Copy link

Hi. I'm having issues getting the stats from a PNG image converted to LCH space.

  sharp(file)
    .toColorspace('lch')
    .toBuffer()
    .then(data => sharp(data).stats())
    .then(stats => console.log(stats))
    .catch(error => signale.error('Failed getting stats. ' + error.message));

This returns the same stats, whether I convert to 'srgb', or 'lch', or 'lab'. Am I not understanding the stats function correctly? I thought it would give me the stats for the L, C, H channels, which would be different than the stats for R, G, B channels.

Thanks

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

Successfully merging this pull request may close these issues.

None yet

5 participants