<commit_before>var ATI = {

    $fields: {
        brightness: undefined,
        contrast: undefined
    },
    sourceImages: {
        full: undefined,
        scaled: undefined
    },
    currentSourceImage: undefined,
    imageCanvas: undefined,

    init: function(sourceImages) {
        ATI.$fields.brightness = $('#id_brightness');
        ATI.$fields.contrast = $('#id_contrast');
        ATI.sourceImages = sourceImages;

        // When the show image tools button is clicked, show image tools;
        // when the hide image tools button is clicked, hide image tools.
        $('#id_button_show_image_tools').click(ATI.showImageTools);
        $('#id_button_hide_image_tools').click(ATI.hideImageTools);

        ATI.imageCanvas = $("#imageCanvas")[0];
        ATI.imageCanvas.width = ATI.sourceImages.scaled.width;
        ATI.imageCanvas.height = ATI.sourceImages.scaled.height;

        // Create a new img element.
        ATI.sourceImages.scaled.imgBuffer = new Image();
        // When the img element's src has loaded, draw it onto the image canvas.
        ATI.sourceImages.scaled.imgBuffer.onload = function(){
            ATI.imageCanvas.getContext("2d").drawImage(ATI.sourceImages.scaled.imgBuffer, 0, 0);
            ATI.currentSourceImage = ATI.sourceImages.scaled;

            // TODO: Check if there are separate scaled and full versions.
            ATI.preloadAndSwapFullImage();
        };
        // Set the img element's src to make it start loading.
        ATI.sourceImages.scaled.imgBuffer.src = ATI.sourceImages.scaled.url;

        ATI.$fields.brightness.change( function() {
            ATI.updateBrightnessAndContrast();
        });
        ATI.$fields.contrast.change( function() {
            ATI.updateBrightnessAndContrast();
        });
    },

    showImageTools: function() {
        $('#id_image_tools_wrapper').show();
        $('#id_button_show_image_tools').hide();
    },
    hideImageTools: function() {
        $('#id_image_tools_wrapper').hide();
        $('#id_button_show_image_tools').show();
    },

    /*
     * Preload the full image; once it's loaded, swap it in as the annotation image.
     * Code from: http://stackoverflow.com/a/1662153/859858
     */
    preloadAndSwapFullImage: function() {
        // Create an Image object.
        ATI.sourceImages.full.imgBuffer = new Image();

        // When image preloading is done, swap images.
        ATI.sourceImages.full.imgBuffer.onload = function() {
            ATI.imageCanvas.width = ATI.sourceImages.full.width;
            ATI.imageCanvas.height = ATI.sourceImages.full.height;
            ATI.imageCanvas.getContext("2d").drawImage(ATI.sourceImages.full.imgBuffer, 0, 0);

            ATI.currentSourceImage = ATI.sourceImages.full;

            ATI.updateBrightnessAndContrast();
        };

        // Image preloading starts as soon as we set this src attribute.
        ATI.sourceImages.full.imgBuffer.src = ATI.sourceImages.full.url;

        // For debugging, it sometimes helps to load an image that
        // (1) has different image content, so you can tell when it's swapped in, and/or
        // (2) is loaded after a delay, so you can zoom in first and then
        //     notice the resolution change when it happens.
        // Here's (2) in action.  The second parameter to setTimeout() is milliseconds
        // (thousandths of seconds) until the first parameter function is called.
        // NOTE: only use this for debugging, not for production code.
        //setTimeout(function() {
        //    ATI.sourceImages.full.imgBuffer.src = ATI.sourceImages.full.url;
        //}, 10000);
    },

    updateBrightnessAndContrast: function() {
        // Get the values in the brightness and contrast fields.
        var brightnessValue = ATI.$fields.brightness.val();
        var contrastValue = ATI.$fields.contrast.val();

        // TODO: Make sure that the initial image (the scaled one) is already drawn on the canvas.
        // Perhaps make a boolean variable that is set to true onload?
        // Also, shouldn't we prevent the image processing changes from being
        // attempted while the image is still loading?  Like gray out the "apply"
        // button or whatever it is.

        // Revert the canvas to pre-image-processing by re-drawing
        // from the source image.
        // (Pixastic has a revert function, but it's not really flexible
        // enough for our purposes, so we're reverting manually.)
        ATI.imageCanvas.getContext("2d").drawImage(ATI.currentSourceImage.imgBuffer, 0, 0);

        // Apply the Pixastic operations to the canvas.
        ATI.imageCanvas = Pixastic.process(
            ATI.imageCanvas,
            'brightness',
            {'brightness': brightnessValue, 'contrast': contrastValue}
        );
    }
};<commit_msg>Annotation tool: brightness/contrast and image loading code has been cleaned up slightly.  Also, the bri/con operation now does nothing if no image is loaded yet; then once an image does load, the bri/con parameters are applied to the image.<commit_after>var ATI = {

    $fields: {
        brightness: undefined,
        contrast: undefined
    },
    sourceImages: {
        full: undefined,
        scaled: undefined
    },
    currentSourceImage: undefined,
    imageCanvas: undefined,

    init: function(sourceImages) {
        ATI.$fields.brightness = $('#id_brightness');
        ATI.$fields.contrast = $('#id_contrast');
        ATI.sourceImages = sourceImages;

        // When the show image tools button is clicked, show image tools;
        // when the hide image tools button is clicked, hide image tools.
        $('#id_button_show_image_tools').click(ATI.showImageTools);
        $('#id_button_hide_image_tools').click(ATI.hideImageTools);

        ATI.imageCanvas = $("#imageCanvas")[0];

        // TODO: Check if there are separate scaled and full versions.
        ATI.preloadAndUseSourceImage('scaled');

        ATI.$fields.brightness.change( function() {
            ATI.updateBrightnessAndContrast();
        });
        ATI.$fields.contrast.change( function() {
            ATI.updateBrightnessAndContrast();
        });
    },

    showImageTools: function() {
        $('#id_image_tools_wrapper').show();
        $('#id_button_show_image_tools').hide();
    },
    hideImageTools: function() {
        $('#id_image_tools_wrapper').hide();
        $('#id_button_show_image_tools').show();
    },

    /* Preload a source image; once it's loaded, swap it in as the image
     * used in the annotation tool.
     *
     * Parameters:
     * code - Which version of the image it is: 'scaled' or 'full'.
     *
     * Basic code pattern from: http://stackoverflow.com/a/1662153/859858
     */
    preloadAndUseSourceImage: function(code) {
        // Create an Image object.
        ATI.sourceImages[code].imgBuffer = new Image();

        // When image preloading is done, swap images.
        ATI.sourceImages[code].imgBuffer.onload = function() {
            ATI.imageCanvas.width = ATI.sourceImages[code].width;
            ATI.imageCanvas.height = ATI.sourceImages[code].height;
            ATI.imageCanvas.getContext("2d").drawImage(ATI.sourceImages[code].imgBuffer, 0, 0);

            ATI.currentSourceImage = ATI.sourceImages[code];

            ATI.applyBrightnessAndContrast();

            // If we just finished loading the scaled image, then start loading
            // the full image.
            if (code === 'scaled') {
                ATI.preloadAndUseSourceImage('full');
            }
        };

        // Image preloading starts as soon as we set this src attribute.
        ATI.sourceImages[code].imgBuffer.src = ATI.sourceImages[code].url;

        // For debugging, it sometimes helps to load an image that
        // (1) has different image content, so you can tell when it's swapped in, and/or
        // (2) is loaded after a delay, so you can zoom in first and then
        //     notice the resolution change when it happens.
        // Here's (2) in action: uncomment the below code and comment out the
        // preload line above to try it.  The second parameter to setTimeout()
        // is milliseconds until the first-parameter function is called.
        // NOTE: only use this for debugging, not for production.
        //setTimeout(function() {
        //    ATI.sourceImages[code].imgBuffer.src = ATI.sourceImages[code].url;
        //}, 10000);
    },

    /* Revert previous brightness/contrast operations, then apply bri/con
       with the new parameters. */
    updateBrightnessAndContrast: function() {
        // If we haven't loaded any image yet, don't do anything.
        if (ATI.currentSourceImage === undefined)
            return;

        // Revert the canvas to pre-image-processing by re-drawing
        // from the source image.
        // (Pixastic has a revert function, but it's not really flexible
        // enough for our purposes, so we're reverting manually.)
        ATI.imageCanvas.getContext("2d").drawImage(ATI.currentSourceImage.imgBuffer, 0, 0);

        ATI.applyBrightnessAndContrast();
    },

    /* Just apply bri/con, no reverting beforehand. */
    applyBrightnessAndContrast: function() {
        // Get the values in the bri/con fields.
        var brightnessValue = ATI.$fields.brightness.val();
        var contrastValue = ATI.$fields.contrast.val();

        // Apply the Pixastic bri/con operations to the canvas.
        // TODO: Don't hang the browser while doing this.
        // TODO: Have some progress text as this goes: "Applying..."
        ATI.imageCanvas = Pixastic.process(
            ATI.imageCanvas,
            'brightness',
            {'brightness': brightnessValue, 'contrast': contrastValue}
        );
    }
};
{'fraction_non_alphanumeric': 0.10804997951659157, 'fraction_numerical': 0.0060426054895534615, 'mean_word_length': 2.367241379310345, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4663387', 'n_tokens_mistral': 2782, 'n_tokens_neox': 2643, 'n_words': 785}