﻿#target photoshop

var docRef;
try {
    docRef = app.activeDocument;
}
catch (e) {
    ;
}
finally {
    docRef.suspendHistory("Ground Height Map", "main()");
}

function adjCurve(inPoints){
    var c_ADJ_LAYER = charIDToTypeID( "AdjL" );
    var c_ADJUSTMENT = charIDToTypeID( "Adjs" );
    var c_CHANNEL = charIDToTypeID( "Chnl" );
    var c_COMPOSITE = charIDToTypeID( "Cmps" );
    var c_RED = charIDToTypeID( "Rd  " );
    var c_CURVE = charIDToTypeID( "Crv " );
    var c_CURVE_A = charIDToTypeID( "CrvA" );
    var c_CURVES = charIDToTypeID( "Crvs" );
    var c_HORIZONTAL = charIDToTypeID( "Hrzn" );
    var c_MAKE = charIDToTypeID( "Mk  " );
    var c_NULL = charIDToTypeID( "null" );
    var c_POINT = charIDToTypeID( "Pnt " );
    var c_TYPE = charIDToTypeID( "Type" );
    var c_USING = charIDToTypeID( "Usng" );
    var c_VERTICAL = charIDToTypeID( "Vrtc" );

							
		var d_CURVES_LAYER = new ActionDescriptor();
		// Contains all the information necessary to perform the "MAKE" action
			var r_CLASS = new ActionReference();
			r_CLASS.putClass( c_ADJ_LAYER );
		d_CURVES_LAYER.putReference( c_NULL, r_CLASS );
		// Class of make action is of an ajdustment layer
			var d_TYPE_CURVES = new ActionDescriptor();
			// Contains all the information about all the curves
				var d_CHANNEL_CURVES = new ActionDescriptor();
					var l_CHANNEL_CURVES = new ActionList();
					// Contains a list of channel curves
						var d_CHANNEL_CURVE = new ActionDescriptor();
						// Information for 1 channel curve
							var r_CHANNEL = new ActionReference();
							//r_CHANNEL.putEnumerated( c_CHANNEL, c_CHANNEL, c_COMPOSITE );
                                r_CHANNEL.putEnumerated( c_CHANNEL, c_CHANNEL, c_RED );
							// This curve is for the composite channel - VARIES
						d_CHANNEL_CURVE.putReference( c_CHANNEL, r_CHANNEL );
						// Contains the point list
							var l_POINTS = new ActionList();
							// List of points for this channel - LENGTH VARIES
								var d_POINT = new ActionDescriptor();
								// One point on the curve, has INPUT and OUTPUT value
								d_POINT.putDouble( c_HORIZONTAL, 0.000000 );
								d_POINT.putDouble( c_VERTICAL, 0.000000 );
							l_POINTS.putObject( c_POINT, d_POINT );
								//var d_POINT2 = new ActionDescriptor();
								d_POINT.putDouble( c_HORIZONTAL, inPoints[0][0] );
								d_POINT.putDouble( c_VERTICAL, inPoints[0][1] );
							l_POINTS.putObject( c_POINT, d_POINT );
								//var d_POINT2 = new ActionDescriptor();
								d_POINT.putDouble( c_HORIZONTAL, inPoints[1][0] );
								d_POINT.putDouble( c_VERTICAL, inPoints[1][1] );
							l_POINTS.putObject( c_POINT, d_POINT );
								//var d_POINT3 = new ActionDescriptor();
								d_POINT.putDouble( c_HORIZONTAL, 255.000000 );
								d_POINT.putDouble( c_VERTICAL, 255.000000 );
							l_POINTS.putObject( c_POINT, d_POINT );
							// Made the list of points
						d_CHANNEL_CURVE.putList( c_CURVE, l_POINTS );
						// Now have a list of points for a specific channel
					l_CHANNEL_CURVES.putObject( c_CURVE_A, d_CHANNEL_CURVE );
					// Add to the list of channel curves
				d_CHANNEL_CURVES.putList( c_ADJUSTMENT, l_CHANNEL_CURVES );
				// All the channel curves are inside here
			d_TYPE_CURVES.putObject( c_TYPE, c_CURVES, d_CHANNEL_CURVES );
			// .....
		d_CURVES_LAYER.putObject( c_USING, c_ADJ_LAYER, d_TYPE_CURVES );
		// package the curves and definition of the adjustment layer type
	executeAction( c_MAKE, d_CURVES_LAYER, DialogModes.NO );

    var desc = new ActionDescriptor();
    var ref = new ActionReference();
    ref.putEnumerated(charIDToTypeID("Chnl"), charIDToTypeID("Chnl"), charIDToTypeID("Msk "));
    desc.putReference(charIDToTypeID("null"), ref);
    desc.putBoolean(charIDToTypeID("MkVs"), false);
    executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
    
    var desc2 = new ActionDescriptor();
    var ref2 = new ActionReference();
    ref2.putEnumerated(charIDToTypeID("Chnl"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
    desc2.putReference(charIDToTypeID("null"), ref2);
    executeAction(charIDToTypeID("Dlt "), desc2, DialogModes.NO);
}

function main() {

        // Set document to RGB mode if it isn't already - a few of the height maps are saved as indexed.
        if (docRef.mode != DocumentMode.RGB) {
            docRef.changeMode(ChangeMode.RGB);
        }
    
        // Get red channel histogram.
        histoRef = docRef.channels[0].histogram;

        // Get median value.
        var pixels = 0;
        for (var m = 0; m < histoRef.length; m++) {
            pixels += histoRef[m];
        };
   
        var median = 0;
        var total = 0;
        var check = true;
        for (var n = 0; n < histoRef.length; n++) {
            total += histoRef[n];
            if (check && total >= (pixels / 2)) {
                median = n;
                check = false;
            }
        };

        // Set up curves...
        var curves = new Array();
        // ...addorrective point.
        curves[0] = new Array(median, 127);
        // ...add point to help stop curve maxing at 255 output before hitting the 255 input mark.
        curves[1]  = new Array(127 + (median / 2), 191);
    
        // Create and set up the curves layer and remove it's layer mask.
        adjCurve(curves);
        // Rename the curve layer.
        docRef.activeLayer.name = "Ground Height Map";
        
        //alert("Median: " + median);
}