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

Images are scaled up when using with imagemagick 6 (Ubuntu 14.04) #45

Open
JostBaron opened this issue May 4, 2014 · 16 comments
Open
Labels

Comments

@JostBaron
Copy link

When I have defined this size

{
    name:   '1000',
    width:  3000,
    suffix: '-3x',
    upscale:false
}

an 800x600 image is upscaled to 3000x2250. My other options are:

options: {
    engine: 'im',
     quality: 70
}
@andismith
Copy link
Owner

Could you provide your full Grunt file please?

@andismith andismith added the bug label May 11, 2014
@JostBaron
Copy link
Author

Ok, here are:

  • My configuration.json (referenced in the gruntfile)
  • The package.json
  • The gruntfile

The gruntfile is a bit longish, sorry for that.

configuration.json:

{
    "distribution": {
        "root":             "distribution",
        "pages":            "distribution",
        "styles":           "distribution",
        "scripts":          "distribution",
        "images":           "distribution/images",
        "contentimages":    "distribution/content/images"
    },
    "build": {
        "absRefPrefix":     "/",
        "root":             "build",
        "pages":            "build",
        "styles":           "build/styles",
        "scripts":          "build/scripts",
        "images":           "build/images",
        "contentimages":    "build/content/images"
    },
    "source": {
        "root":             "source",
        "styles":           "source/styles",
        "images":           "source/images",
        "markup":           "source/markup"
    },
    "content": {
        "images":           "source/content/images",
        "data":             "source/content/data",
        "pages":            "source/markup/pages"
    },
    "deployment": {
        "host":             "doesnt-matter",
        "port":             21,
        "authkey":          "somekey",
        "targetdir":        "/",
        "contentimages":    "/content/images"
    }
}

package.json:

{
  "name": "doesnt-matter",
  "version": "0.1.0",
  "dependencies": {},
  "devDependencies": {
    "grunt": "latest",
    "grunt-contrib-less": "latest",
    "grunt-contrib-copy": "latest",
    "grunt-contrib-uglify": "latest",
    "grunt-contrib-cssmin": "latest",
    "grunt-ftp-deploy": "latest",
    "swig": "latest",
    "grunt-swig2": "latest",
    "grunt-contrib-compress": "latest",
    "grunt-contrib-watch": "latest",
    "grunt-contrib-connect": "latest",
    "grunt-modernizr": "latest",
    "grunt-responsive-images": "^0.1.2",
    "markdown": "^0.5.0",
    "grunt-contrib-clean": "latest"
  },
  "engines": {
    "node": ">=0.8.0"
  }
}

Gruntfile.js

"use strict";

module.exports = function (grunt) {

    var path = require('path');

    var LIVERELOAD_PORT = 12345;

    var swig = require('swig');
    var markdown = require( "markdown" ).markdown;

    var configuration = grunt.file.readJSON('configuration.json');


    function getContentImageFileNames() {
        var result = {};

        grunt.file.recurse(
                configuration.content.images,
                function(abspath, rootdir, subdir, filename) {
                    subdir = subdir || '';

                    if (!(subdir in result)) {
                        result[subdir] = [];
                    }

                    if ('data.json' === filename) {
                        var data = grunt.file.readJSON(abspath);

                        for (var i = 0; i < data.length; i++) {
                            var imagedata = data[i];

                            filename = imagedata.name;
                            result[subdir].push(
                                {
                                    subdirectory:   path.relative(configuration.distribution.root, configuration.distribution.contentimages) + '/' + subdir,
                                    extension:      path.extname(filename),
                                    name:           path.basename(filename, path.extname(filename)),
                                    slideshowlink:  'referenzen/' + subdir + '.html',
                                    alttext:        imagedata.alttext,
                                    title:          imagedata.title,
                                    caption:        imagedata.caption
                                }
                            )
                        }
                    }
                }
        )

        return result;
    }

    function getImageSizes() {
        return [
            {
                name:   '320',
                width:  320,
                suffix: '-1x'
            },
            {
                name:   '320',
                width:  480,
                suffix: '-1.5x'
            },
            {
                name:   '320',
                width:  640,
                suffix: '-2x'
            },
            {
                name:   '320',
                width:  960,
                suffix: '-3x'
            },
            {
                name:   '480',
                width:  480,
                suffix: '-1x'
            },
            {
                name:   '480',
                width:  720,
                suffix: '-1.5x'
            },
            {
                name:   '480',
                width:  960,
                suffix: '-2x'
            },
            {
                name:   '480',
                width:  1440,
                suffix: '-3x'
            },
            {
                name:   '720',
                width:  720,
                suffix: '-1x'
            },
            {
                name:   '720',
                width:  1080,
                suffix: '-1.5x'
            },
            {
                name:   '720',
                width:  1440,
                suffix: '-2x'
            },
            {
                name:   '720',
                width:  2160,
                suffix: '-3x'
            },
            {
                name:   '1000',
                width:  1000,
                suffix: '-1x'
            },
            {
                name:   '1000',
                width:  1500,
                suffix: '-1.5x'
            },
            {
                name:   '1000',
                width:  2000,
                suffix: '-2x'
            },
            {
                name:   '1000',
                width:  3000,
                suffix: '-3x'
            },
            {
                name:   'thumb-130',
                width:  130,
                height: 130,
                aspectRatio: false,
                suffix: '-1x'
            },
            {
                name:   'thumb-130',
                width:  185,
                height: 185,
                aspectRatio: false,
                suffix: '-1.5x'
            },
            {
                name:   'thumb-130',
                width:  260,
                height: 260,
                aspectRatio: false,
                suffix: '-2x'
            },
            {
                name:   'thumb-130',
                width:  390,
                height: 390,
                aspectRatio: false,
                suffix: '-3x'
            }
        ];
    }

    grunt.initConfig({
        configuration: configuration,

        less: {
            options: {
                modifyVars: {
                    // example: assetBasePath: '"/test"' (mind the inner quotes)
                }
            },
            all: {
                options: {
                    paths: [
                        'bower_components'
                    ]
                },
                files: {
                    '<%= configuration.build.styles %>/main.css': '<%= configuration.source.styles %>/main.less'
                }
            }
        },

        modernizr: {
            build: {
                "devFile" : "remote",
                "outputFile" : "<%= configuration.build.scripts %>/modernizr-custom.js",

                "extra" : {
                    "shiv" : false,
                    "printshiv" : false,
                    "load" : false,
                    "mq" : false,
                    "cssclasses" : true
                },
                "extensibility" : {
                    "addtest" : false,
                    "prefixed" : false,
                    "teststyles" : false,
                    "testprops" : false,
                    "testallprops" : false,
                    "hasevents" : false,
                    "prefixes" : false,
                    "domprefixes" : false
                },
                "uglify" : false,
                "tests" : [],
                "parseFiles" : false,
                "matchCommunityTests" : false,
                "customTests" : []
            }

        },

        uglify: {
            options: {
                mangle: {
                    except: ['jQuery']
                }
            },
            head: {
                files: {
                    '<%= configuration.build.scripts %>/head.js': [
                        '<%= configuration.build.scripts %>/modernizr-custom.js',
                        'bower_components/html5shiv/dist/html5shiv.js'
                    ]
                }
            },
            body: {
                files: {
                    '<%= configuration.build.scripts %>/body.js': [
                        'bower_components/respond/dest/respond.src.js',
                        'bower_components/picturefill/dist/picturefill.js',
                        'bower_components/swiper/dist/idangerous.swiper.js',
                        'source/scripts/slideshow.js',
                        'source/scripts/menu.js'
                    ]
                }
            }
        },

        swig: {
            options: {
                data: function() {
                    var path = require('path');
                    var result = {};
                    grunt.file.recurse(
                            process.cwd() + '/' + configuration.content.data,
                            function(abspath, rootdir, subdir, filename) {
                                result[path.basename(filename, '.json')] = grunt.file.readJSON(abspath);
                            }
                    );

                    if ('contentimages' in result) {
                        console.warn('Name conflict. The data key \'contentimages\' is reserved.');
                    }
                    result['contentimages'] = getContentImageFileNames();

                    if ('imagesizes' in result) {
                        console.warn('Name conflict. The data key \'imagesizes\' is reserved.');
                    }
                    result['imagesizes'] = getImageSizes();

                    return result;
                },
                filters: {
                    markdown: function(input) {
                        return markdown.toHTML(input, 'Maruku');
                    }
                },
                swigOptions: {
                    loader: swig.loaders.fs(__dirname)
                }
            },
            pages: {
                files: [
                    {
                        expand: true,
                        cwd:    '<%= configuration.content.pages %>',
                        src:    ['**/*.html'],
                        dest:   '<%= configuration.build.pages %>'
                    }
                ]
            }
        },

        copy: {
            images: {
                files: [
                    {
                        expand: true,
                        dot: true,
                        cwd: '<%= configuration.source.images %>',
                        dest: '<%= configuration.build.images %>',
                        src: [
                            '**',
                            '!background/**'
                        ]
                    }
                ]
            },
            htaccess: {
                files: [
                    {
                        expand: true,
                        dot: true,
                        cwd: '<%= configuration.source.root %>',
                        dest: '<%= configuration.build.root %>',
                        src: [
                            '.htaccess'
                        ]
                    }
                ]
            },
            distribution: {
                files: [
                    {
                        expand: true,
                        dot: true,
                        cwd:    '<%= configuration.build.root %>',
                        dest:   '<%= configuration.distribution.root %>',
                        src: [
                            '**',
                            '!styles/**',
                            '!scripts/**'
                        ]
                    }
                ]
            }
        },

        compress: {
            options: {
                mode:       'gzip',
                level:      9,
                pretty:     true
            },
            distribution: {
                files: [
                    {
                        src:    '<%= configuration.build.scripts %>/head.js',
                        dest:   '<%= configuration.distribution.scripts %>/head.gz.js',
                        ext:    '.gz.js',
                        filter: 'isFile'
                    },
                    {
                        src:    '<%= configuration.build.scripts %>/body.js',
                        dest:   '<%= configuration.distribution.scripts %>/body.gz.js',
                        ext:    '.gz.js',
                        filter: 'isFile'
                    },
                    {
                        src:    '<%= configuration.build.styles %>/**',
                        dest:   '<%= configuration.distribution.styles %>/styles.gz.css',
                        ext:    '.gz.css',
                        filter: 'isFile'
                    }
                ]
            }
        },

        watch: {
            livereload: {
                options: {
                    livereload: LIVERELOAD_PORT
                },
                files: [
                    '<%= configuration.source.root %>/**'
                ],
                tasks: ['default']
            }
        },

        connect: {
            options: {
                port: 9010,
                // change this to '0.0.0.0' to access the server from outside
                hostname: '127.0.0.1'
            },
            livereload: {
                options: {
                    livereload: LIVERELOAD_PORT,
                    base: '<%= configuration.distribution.root %>',
                    middleware: function(connect, options, middlewares) {

                        middlewares.unshift(function(req, res, next) {
                            if (-1 !== req.url.search('.gz')) {
                                res.setHeader('Content-Encoding', 'gzip');
                            }
                            next();
                        });

                        return middlewares;
                    }
                }
            }
        },

        responsive_images: {
            contentimages: {
                options: {
                    engine: 'im',
                    quality: 70,
                    sizes: getImageSizes()
                },
                files: [
                    {
                        expand: true,
                        dot: true,
                        cwd: '<%= configuration.content.images %>',
                        dest: '<%= configuration.build.contentimages %>',
                        filter: 'isFile',
                        src: [
                            '**',
                            '!**/data.json'
                        ]
                    }
                ]
            }
        },

        'ftp-deploy': {
            'no-images': {
                auth: {
                    host: '<%= configuration.deployment.host %>',
                    port: '<%= configuration.deployment.port %>',
                    authKey: '<%= configuration.deployment.authkey %>'
                },
                src: '<%= configuration.distribution.root %>',
                dest: '<%= configuration.deployment.targetdir %>',
                exclusions: [
                    '<%= configuration.distribution.contentimages %>/**'
                ]
            },
            'images': {
                auth: {
                    host: '<%= configuration.deployment.host %>',
                    port: '<%= configuration.deployment.port %>',
                    authKey: '<%= configuration.deployment.authkey %>'
                },
                src: '<%= configuration.distribution.contentimages %>',
                dest: '<%= configuration.deployment.contentimages %>'
            }
        },
        clean: {
            options: {
//                'no-write': true
            },
            build: [
                '<%= configuration.build.root %>/**'
            ],
            distribution: [
                '<%= configuration.distribution.root %>/**'
            ]
        }
    });

    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-compress');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-modernizr');
    grunt.loadNpmTasks('grunt-responsive-images');
    grunt.loadNpmTasks('grunt-swig2');
    grunt.loadNpmTasks('grunt-ftp-deploy');

    grunt.registerTask(
            'build',
            [
                'less:all',
                'modernizr:build',
                'uglify:head',
                'uglify:body',
                'swig:pages',
                'copy:images',
                'copy:htaccess',
                'copy:distribution',
                'compress:distribution'
            ]
    );

    grunt.registerTask(
            'server',
            [
                'build',
                'connect:livereload',
                'watch'
            ]
    );

    grunt.registerTask(
            'images',
            [
                'responsive_images:contentimages'
            ]
    );

    grunt.registerTask(
            'full',
            [
                'images',
                'build'
            ]
    );

    grunt.registerTask(
            'deploy',
            [
                'build',
                'ftp-deploy:no-images'
            ]
    );

    grunt.registerTask(
            'deploy-images',
            [
         //       'images',
                'ftp-deploy:images'
            ]
    );

    grunt.registerTask(
            'deploy-full',
            [
                'full',
                'ftp-deploy:no-images',
                'ftp-deploy:images'
            ]
    );

    grunt.registerTask(
            'default',
            [
                'build'
            ]
    );
};

@andismith
Copy link
Owner

What type of image file is it?
Is it an animated GIF?

@JostBaron
Copy link
Author

No, all of the images were JPEGs (file extension differed, either jpg or JPG).

@andismith
Copy link
Owner

I've released a new version that changes the internals for how options work. Does this still happen with v0.1.4?
Have you tried running Grunt in verbose mode?

@JostBaron
Copy link
Author

The problem is not fixed - upscale: false is respected when using GraphicsMagick, but not when using ImageMagick.

I ran Grunt in verbose mode, but that did not reveal anything.

@hamsterbacke23
Copy link

Seems like
sizingMethod = '\>';
would work

At least I tried it and it seems to stop upscaling..
See also:
http://stackoverflow.com/questions/3504931/cli-imagemagick-resize-downscale-only

@nestordeharo
Copy link

I have the same problem...using a simple configuration file it upscale the image (e.g. 80px to 400px)

'use strict';

module.exports = function(grunt){

  grunt.initConfig({
    responsive_images: {
      options: {
        sizes: [{
          name: "small",
          width: 480,
          upscale: false
        }]
      },
      files:{
        expand: true,
        src: ['**.{jpg,gif,png}'],
        cwd: 'images/',
        dest:'ejemplo/'
      }
    }
  })

  grunt.loadNpmTasks('grunt-responsive-images');
  grunt.registerTask('default', ['responsive_images']);
}

@isaacchansky
Copy link

If you adjust the tests to start with a small image, you'll see it get upscaled in the default options test.

I also got it to work (with imagemagick 6 ) thanks to @hamsterbacke23 by changing this upscale bit of code on line 337 to:

 if (sizeOptions.upscale) {
       // upscale
      if (sizeOptions.aspectRatio) {
         sizingMethod = '^';
      } else {
        sizingMethod = '!';
      }
  }else { 
      sizingMethod= '>';
}

which is just setting the sizing method to '>' if options.upscale is set to false. Which is described here as:

"Another commonly used option is to restrict IM so that it will only shrink images to fit into the size given. Never enlarge. This is the '>' resize option. Think of it only applying the resize to images 'greater than' the size given (its a little counter intuitive)."

Happy to open a PR!

@hal-gh
Copy link

hal-gh commented Mar 6, 2015

This issue is also affecting me.

Environment:

@malducin-vfxfan
Copy link

I had the same problem, fixed it last year somehow, but can't find that project. This also affects GraphicsMagic on Windows. There is an undocumented option that fixes the problem: createNoScaledImage. Set it to true in your options like:

options: {
    // Task-specific options go here.
    createNoScaledImage: true,
    sizes: [{
        ...
    }]
},

maybe that option is not getting set correctly?

@hal-gh
Copy link

hal-gh commented Apr 15, 2015

@malducin-vfxfan

I suppose it depends on what people here want. As the name implies, createNoScaledImage:true skips over creating any files that would be upscaled. This causes a problem when there are references in static code, with no if/then/else constructs (like css), to images that don't exist (because they were skipped because they would have been upscaled).

Personally, I'd like a new file to be created, which is effectively just the original image duplicated but with a filename that uses the naming convention specified in the options.

@JostBaron - would you clarify which problem you were describing in the ticket?

@malducin-vfxfan
Copy link

Thanks, that makes sense. In my case I'm handling the images with code (PHP/Python) so I can check their presence, or just creating a ton of thumbnails (for galleries or contact sheets), so I hadn't considered the CSS case. I'm fine if it keeps working that same way. Maybe just indicate createNoScaledImage:true in the README or a wiki entry for those hitting this problem.

Now I have to check my setup on Windows, because I do have both ImageMagick and GraphicsMagic installed, and even when specifying GraphicsMagic explicitly, it still upscales, so it might be a case where it's finding IM first (maybe because of the registry).

@hal-gh
Copy link

hal-gh commented Apr 16, 2015

Awaiting response from @JostBaron - possibly this can be closed as issue #82 requests documentation enhancement.

@iparr
Copy link

iparr commented Jun 17, 2015

I do hope that @isaacchansky commit can be merged, as the suggestion in #82 requires a more complicated Grunt setup involving additional copying of those images that are not resized.

@heavysixer
Copy link

another potential fix is to expose sizingMethod as a config variable.

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

No branches or pull requests

9 participants