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

Support aspectwithbg style #137

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,17 @@ Resized images by specifying `width` and `height`. There are three resizing styl

* `aspectfill`: Default. The resulting image will be exactly the specified size, and may be cropped.
* `aspectfit`: Scales the image so that it will not have to be cropped.
* `aspectwithbg`: Scales the image and fill the rest by background color.
* `fill`: Squishes or stretches the image so that it fills exactly the specified size.

```js
fs.writeFileSync('after_resize.jpg', imagemagick.convert({
srcData: fs.readFileSync('before_resize.jpg'),
width: 100,
height: 100,
resizeStyle: 'aspectfill', // is the default, or 'aspectfit' or 'fill'
gravity: 'Center' // optional: position crop area when using 'aspectfill'
resizeStyle: 'aspectfill', // is the default, or 'aspectfit', 'aspectwithbg' or 'fill'
gravity: 'Center', // optional: position crop area when using 'aspectfill'
background: '#4d4d4d' // optional: background color when using 'aspectwithbg'
}));
```

Expand All @@ -105,9 +107,9 @@ Original:

Resized:

aspectfill | aspectfit | fill
:---: | :---: | :---:
![alt text](http://elad.github.io/node-imagemagick-native/examples/resize_aspectfill.jpg 'aspectfill') | ![alt text](http://elad.github.io/node-imagemagick-native/examples/resize_aspectfit.jpg 'aspectfit') | ![alt text](http://elad.github.io/node-imagemagick-native/examples/resize_fill.jpg 'fill')
aspectfill | aspectfit | aspectwithbg | fill
:---: | :---: | :---: | :---:
![alt text](http://elad.github.io/node-imagemagick-native/examples/resize_aspectfill.jpg 'aspectfill') | ![alt text](http://elad.github.io/node-imagemagick-native/examples/resize_aspectfit.jpg 'aspectfit') | ![alt text](http://horiuchi.github.io/node-imagemagick-native/examples/resize_aspectwithbg.jpg 'aspectwithbg') | ![alt text](http://elad.github.io/node-imagemagick-native/examples/resize_fill.jpg 'fill')

*Image courtesy of [Christoph](https://www.flickr.com/photos/scheinwelten/381994831).*

Expand Down Expand Up @@ -158,13 +160,15 @@ The `options` argument can have following values:
width: optional. px.
height: optional. px.
density optional. Integer dpi value to convert
resizeStyle: optional. default: 'aspectfill'. can be 'aspectfit', 'fill'
aspectfill: keep aspect ratio, get the exact provided size.
aspectfit: keep aspect ratio, get maximum image that fits inside provided size
fill: forget aspect ratio, get the exact provided size
resizeStyle: optional. default: 'aspectfill'. can be 'aspectfit', 'aspectwithbg', 'fill'
aspectfill: keep aspect ratio, get the exact provided size.
aspectfit: keep aspect ratio, get maximum image that fits inside provided size
aspectwithbg: keep aspect ratio, get the exact proviede size and no cropped.
fill: forget aspect ratio, get the exact provided size
gravity: optional. default: 'Center'. used to position the crop area when resizeStyle is 'aspectfill'
can be 'NorthWest', 'North', 'NorthEast', 'West',
'Center', 'East', 'SouthWest', 'South', 'SouthEast', 'None'
background: optional. default: 'Transpearental'. used to background color when resizeStle is 'aspectwithbg'
format: optional. output format, ex: 'JPEG'. see below for candidates
filter: optional. resize filter. ex: 'Lagrange', 'Lanczos'. see below for candidates
blur: optional. ex: 0.8
Expand Down
76 changes: 76 additions & 0 deletions src/imagemagick.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ struct convert_im_ctx : im_ctx_base {
std::string format;
std::string filter;
std::string blur;
std::string background;
unsigned int quality;
int rotate;
int density;
Expand Down Expand Up @@ -179,6 +180,25 @@ void DoConvert(uv_work_t* req) {

Magick::Image image;

if ( ! context->background.empty() ) {
const char* background = context->background.c_str();
try {
Magick::Color bg(background);
image.backgroundColor(bg);
if (debug) printf( "set background: %s\n", background );
}
catch (std::exception& err) {
std::string message = "image.backgroundColor failed with error: ";
message += err.what();
context->error = message;
return;
}
catch (...) {
context->error = std::string("unhandled error");
return;
}
}

if ( !ReadImageMagick(&image, srcBlob, context->srcFormat, context) )
return;

Expand Down Expand Up @@ -382,6 +402,58 @@ void DoConvert(uv_work_t* req) {
return;
}
}
else if ( strcmp ( resizeStyle, "aspectwithbg" ) == 0 ) {
// keep aspect ratio, get the maximum image which fits inside specified size
char geometryString[ 32 ];
sprintf( geometryString, "%dx%d", width, height );
if (debug) printf( "resize to: %s\n", geometryString );

Magick::Image compositeImage(image);
try {
compositeImage.zoom( geometryString );
}
catch (std::exception& err) {
std::string message = "image.resize failed with error: ";
message += err.what();
context->error = message;
return;
}
catch (...) {
context->error = std::string("unhandled error");
return;
}

sprintf( geometryString, "%dx%d!", width, height );
if (debug) printf( "set background to: %s\n", geometryString );
try {
image.erase();
image.zoom( geometryString );
}
catch (std::exception& err) {
std::string message = "image.initialize failed with error: ";
message += err.what();
context->error = message;
return;
}
catch (...) {
context->error = std::string("unhandled error");
return;
}

try {
image.composite(compositeImage, Magick::CenterGravity, Magick::OverCompositeOp);
}
catch (std::exception& err) {
std::string message = "image.composite failed with error: ";
message += err.what();
context->error = message;
return;
}
catch (...) {
context->error = std::string("unhandled error");
return;
}
}
else {
context->error = std::string("resizeStyle not supported");
return;
Expand Down Expand Up @@ -556,6 +628,10 @@ NAN_METHOD(Convert) {
context->filter = !filterValue->IsUndefined() ?
*String::Utf8Value(filterValue) : "";

Local<Value> backgroundValue = obj->Get( Nan::New<String>("background").ToLocalChecked() );
context->background = !backgroundValue->IsUndefined() ?
*String::Utf8Value(backgroundValue) : "";

uv_work_t* req = new uv_work_t();
req->data = context;
if(!isSync) {
Expand Down
4 changes: 2 additions & 2 deletions test/benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function resize (callback) {
}, function (err,stdout,stderr) {
assert( stdout.length > 0 );
// console.log( "im length: "+stdout.length );
// require('fs').writeFileSync( "./test/out.fork.jpg", stdout, 'binary' );
// require('fs').writeFileSync( "out.fork.jpg", stdout, 'binary' );
callback();
});
}
Expand All @@ -38,7 +38,7 @@ function resize_native (callback) {
});
assert( stdout.length > 0 );
// console.log( "im_native length: "+stdout.length );
// require('fs').writeFileSync( "./test/out.native.jpg", stdout, 'binary' );
// require('fs').writeFileSync( "out.native.jpg", stdout, 'binary' );
callback();
}

Expand Down
2 changes: 1 addition & 1 deletion test/leak.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ memwatch.on( 'leak', function( info ) {
memwatch.on('stats', function(stats) {
console.log( "stats: ", stats );
});
var srcData = require('fs').readFileSync( "./test/test.jpg" );
var srcData = require('fs').readFileSync( "test.jpg" );

var hd = new memwatch.HeapDiff();

Expand Down
38 changes: 38 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,44 @@ test( 'convert jpg -> jpg aspectfit', function (t) {
t.end();
});

test( 'convert png -> png aspectwithbg', function (t) {
var buffer = imagemagick.convert({
srcData: require('fs').readFileSync( "test.png" ), // 58x66
width: 100,
height: 100,
resizeStyle: 'aspectwithbg',
background: '#4d4d4d',
quality: 80,
format: 'PNG',
debug: debug
});
t.equal( Buffer.isBuffer(buffer), true, 'buffer is Buffer' );
var info = imagemagick.identify({srcData: buffer });
t.equal( info.width, 100 );
t.equal( info.height, 100 );
saveToFileIfDebug( buffer, "out.png-aspectwithbg.png" );
t.end();
});

test( 'convert png.wide -> png.wide aspectwithbg', function (t) {
var buffer = imagemagick.convert({
srcData: require('fs').readFileSync( "test.wide.png" ), // 66x58
width: 100,
height: 100,
resizeStyle: 'aspectwithbg',
background: '#4d4d4d',
quality: 80,
format: 'PNG',
debug: debug
});
t.equal( Buffer.isBuffer(buffer), true, 'buffer is Buffer' );
var info = imagemagick.identify({srcData: buffer });
t.equal( info.width, 100 );
t.equal( info.height, 100 );
saveToFileIfDebug( buffer, "out.wide.png-aspectwithbg.png" );
t.end();
});

test( 'convert broken png', function (t) {
var srcData = require('fs').readFileSync( "broken.png" )
, buffer;
Expand Down