Update and push one value into array while keeping the others static - javascript

I am working on a project where we calculate the indoor position using BLE from 3 ESP32's. I managed to scan and calculate the distance between one ESP and a bluetooth scanning device. From the library that I found it used a static distance but i want it to be able to push the distance into the array in the same index as the ESP's respected coordinates.
Code from library:
var trilateration = require('node-trilateration');
# Creating three beacons
var beacons = [
{x: 2, y: 4, distance: 5.7},
{x: 5.5, y: 13, distance: 6.8},
{x: 11.5, y: 2, distance: 6.4}
];
# Start Calculation
var pos = trilateration.calculate(beacons);
console.log("X: " + pos.x + "; Y: " + pos.y); // X: 7; Y: 6.5
As you see the distance is predetermined here but i want to keep the same structure but just where my distance that is calculated is put in the same index as their ESP. this means i can not use push() because it just creates a new index for it.
My code:
import * as trilateration from './trilateration.js';
console.log("Init");
const devices = [];
const ids = [];
const beaconuuid = [];
const distances = [];
const SCAN_TIME = 10000;
document.getElementById("scan").onclick = scan;
async function scan() {
console.log("Scanning...");
let options = {
acceptAllAdvertisements: true,
acceptAllDevices: true,
};
try {
log("Requesting Bluetooth Scan with options: " + JSON.stringify(options));
const scan = await navigator.bluetooth.requestLEScan(options);
log("Scan started with:");
log(" acceptAllAdvertisements: " + scan.acceptAllAdvertisements);
log(" active: " + scan.active);
log(" keepRepeatedDevices: " + scan.keepRepeatedDevices);
log(" filters: " + JSON.stringify(scan.filters));
navigator.bluetooth.addEventListener("advertisementreceived", (event) => {
let name = event.device.name;
if (name && name.startsWith("ESP32") && !ids.includes(event.device.id)) {
console.log("Found");
console.log(event);
//add to device list if name starts with ESP32
console.log("adding");
const obj = {
device: event.device,
uuids: event.uuids,
rssi: event.rssi,
tx: event.txPower,
distance: Math.pow(10, (-60 - event.rssi) / (10 * 2)),
};
devices.push(obj);
ids.push(event.device.id);
distances.push(obj.distance)

Related

Optimise a nested for-each loop for units on Cartesian plane

A game has a large number of unit objects held in an array.
These units have x/y coordinates locating them on a 2d map.
let units = [
{id: 1, x=3450, y = 1456},
{id: 2, x=5560, y = 2423},
{id: 3, x=1321, y = 3451}
]
Approx 50 times a second the game requires each unit to generate a list of other units within a given distance (to interact with them by fighting/avoiding etc).
As the unit count grows into the thousands the current process where each unit checks distance vs each other unit slows down dramatically as you start getting exponentially more tests required.
Looking into similar problems posted online we started grouping the units into row/column cell collections then only performing the distance tests on those that 'might' be close enough to be relevant. However we found that constructing this grouping actually takes longer to build and maintain than the gains it provided.
A testable version of the current code is below - on my fairly typical browser this takes about a second to complete and it needs to improve this substantially - suggestions for optimisations welcome.
//create the world
let mapWidth = 5000;
let mapHeight = 2000;
let releventDistance = 200;
let unitCount = 5000;
//new unit function creates a unit in a random position on the map
function newUnit(id){
let newUnit = {};
newUnit.id = id;
newUnit.x = Math.floor(Math.random()*mapWidth);
newUnit.y = Math.floor(Math.random()*mapHeight);
//this array of 'relevent' neigbours is the collection of other units close enough to interact with
newUnit.neighbours = [];
return newUnit;
}
//simple distance test
function distance (unit1, unit2){
let dx = unit1.x - unit2.x;
let dy = unit1.y - unit2.y;
return Math.sqrt(dx * dx + dy * dy);
}
//collection of units
var myUnits = [];
//populate the units
for (let i =0; i<unitCount; i++){
myUnits.push(newUnit(i));
}
console.log(unitCount + " units created");
//complete a full-scan with a nested foreach
let timeStamp1 = new Date();
myUnits.forEach(unit => {
myUnits.forEach(unit2 => {
//don't test a unit against itself
if(unit.id != unit2.id){
let unitDist = distance(unit, unit2);
if (unitDist <= releventDistance){
unit.neighbours.push({unit : unit2, distance : unitDist});
}
}
})
})
//print results
console.log((new Date() - timeStamp1) + "ms: to complete bruteforce fullscan");
//print average number of neigbours
let totalNeighbourCount = 0;
myUnits.forEach(myUnit => {totalNeighbourCount += myUnit.neighbours.length});
console.log(Math.floor(totalNeighbourCount/myUnits.length) + ": average number of neighbours");
You could iterate only from the index plus one for the inner loop and avoid visiting already visited pairs.
This approach requires to add the pair to each neighbor.
//create the world
let mapWidth = 5000;
let mapHeight = 2000;
let releventDistance = 200;
let unitCount = 5000;
//new unit function creates a unit in a random position on the map
function newUnit(id){
let newUnit = {};
newUnit.id = id;
newUnit.x = Math.floor(Math.random()*mapWidth);
newUnit.y = Math.floor(Math.random()*mapHeight);
//this array of 'relevent' neigbours is the collection of other units close enough to interact with
newUnit.neighbours = [];
return newUnit;
}
//simple distance test
function distance (unit1, unit2){
let dx = unit1.x - unit2.x;
let dy = unit1.y - unit2.y;
return Math.sqrt(dx * dx + dy * dy);
}
//collection of units
var myUnits = [];
//populate the units
for (let i =0; i<unitCount; i++){
myUnits.push(newUnit(i));
}
console.log(unitCount + " units created");
let timeStamp1 = new Date();
for (let i = 0, l1 = myUnits.length - 1; i < l1; i++) {
const unit = myUnits[i];
for (let j = i + 1, l2 = myUnits.length; j < l2; j++) {
const unit2 = myUnits[j];
let unitDist = distance(unit, unit2);
if (unitDist <= releventDistance) {
unit2.neighbours.push({ unit: unit, distance: unitDist });
unit.neighbours.push({ unit: unit2, distance: unitDist });
}
}
}
//print results
console.log((new Date() - timeStamp1) + "ms: to complete bruteforce fullscan");
//print average number of neigbours
let totalNeighbourCount = 0;
myUnits.forEach(myUnit => {totalNeighbourCount += myUnit.neighbours.length});
console.log(Math.floor(totalNeighbourCount/myUnits.length) + ": average number of neighbours");

How to calculate waypoints between multiple waypoints?

So for example I have an array with 3 waypoints:
[ [ 526, 1573, 24 ], [ 2224, 809, -1546 ], [ 6869, 96, -3074 ] ]
I also know I want to rest for lets say n times between between arriving at the first and last waypoint. So in the end I want an array of n points.
How do I go about finding those n resting-points in JS?
Thanks in advance!
EDIT: Note this is not a single object! Imagine each axis being one person. They have to stop the same amount of time and at the same time but they do not have to be at the same place obviously.
You want to use linear interpolation.
A quick example:
const POINTS = [ [ 526, 1573, 24 ], [ 2224, 809, -1546 ], [ 6869, 96, -3074 ] ];
const N = 10;
function getDistance(point1, point2) {
// speed in 3d space is mutated according only to the X distance,
// to keep speed constant in X dimension
return Math.abs(point1[0] - point2[0]);
}
function go(points, n) {
const pointDistances = points.slice(1).map((point, index) => getDistance(points[index], point));
const fullDistance = pointDistances.reduce((sum, distance) => sum + distance, 0);
const distancePerSection = fullDistance / n;
return points.slice(1)
.reduce((last, point, index) => {
const thisDistance = pointDistances[index];
const numRestPoints = Math.max(0, Math.floor(thisDistance / distancePerSection) - 1);
if (!numRestPoints) {
return last.concat([point]);
}
const thisYVector = point[1] - points[index][1];
const thisZVector = point[2] - points[index][2];
return last.concat(new Array(numRestPoints).fill(0)
.reduce((section, item, restIndex) => {
return section.concat([[
points[index][0] + (restIndex + 1) * distancePerSection,
points[index][1] + (restIndex + 1) * thisYVector * distancePerSection / thisDistance,
points[index][2] + (restIndex + 1) * thisZVector * distancePerSection / thisDistance
]]);
}, [])
.concat([point])
);
}, points.slice(0, 1));
}
function test() {
const result = go(POINTS, N);
if (result.length !== N) {
throw new Error('Must be N length');
}
if (!result[0].every((value, index) => value === POINTS[0][index])) {
throw new Error('Doesn\'t start at the first point');
}
if (!result[N - 1].every((value, index) => value === POINTS[POINTS.length - 1][index])) {
throw new Error('Doesn\'t end at the last point');
}
if (!POINTS.slice(1, N - 1).every(point =>
result.some(resultPoint => resultPoint.every((value, index) => value === point[index]))
)) {
throw new Error('Doesn\'t go through every provided point');
}
console.log(result.slice(1).map((point, index) => getDistance(point, result[index])));
console.log('The result passed the tests!');
console.log(JSON.stringify(result, null, 2));
}
test();
I'm basically going through the list of points, and determining if there should exist any rest points between them, inserting them if so.
Please comment if you want further clarification!
I also solved this problem now with linear interpolation:
My solution:
var waypoints = [[526,1573,24],[2224,809,-1546],[6869,96,-3074]];
var pauses = 20;
generateWaypopints();
function generateWaypopints(){
var newWaypoints = [];
var progressAtMainPoints = 1 / (waypoints.length - 1)
var pausesBetweenWaypoints = pauses * progressAtMainPoints;
var progressAtPauses = 1 / pausesBetweenWaypoints;
newWaypoints.push(waypoints[0]);
var sector = 0;
var pausesInSector = 0;
for(var i = 0; i < pauses; i++){
var progress = progressAtPauses * (pausesInSector + 1)
var x = Math.round(waypoints[sector][0] + (waypoints[sector + 1][0] - waypoints[sector][0]) * progress);
var y = Math.round(waypoints[sector][1] + (waypoints[sector + 1][1] - waypoints[sector][1]) * progress);
var z = Math.round(waypoints[sector][2] + (waypoints[sector + 1][2] - waypoints[sector][2]) * progress);
if(progress >= 1){
sector++;
pausesInSector = 0;
}else
pausesInSector++;
newWaypoints.push([x,y,z]);
}
console.log(newWaypoints);
return newWaypoints;
}

String and Int Array Sorting

I've got a problem sorting arrays. I'm currently trying to optimize a thing in a strategy game I play, and for that I need to calculate distance between all members of my alliance, the first towards the others and so on. No problem doing that actually. But now, what I want to do is sort the array of distance "ascending" and problem is, I need to write the corresponding nickname to match the distance. I've been searching for 2 days and I can't figure out a working solution.
I tried to copy the array before sorting it, but I need the unsorted array and with that sort function, it sorts the copy too !
Actually the code provided is good, speaking of distance accuracy but not sorted ascending. If I sort the distances, the nicknames are no longer corresponding. I don't know why they appear in the order of the pseudo_list because It's supposed to be sorted through nSort2()
This is what I've ended up with so far :
//Sorting Distance[i] Array List
function nSort(arr)
{
return arr.sort((a, b) => a - b);
}
//Calculating Distance
function calcDist(xA, yA, xB, yB)
{
return Math.sqrt(Math.pow((xB-xA), 2)+Math.pow((yB-yA), 2));
}
//Here i'm trying to retrieved unsorted position of distance by index to sort the nicknames by their respective distances
function nSort2(arr_str, arr_nbr)
{
var arr_nbr2 = arr_nbr.splice(0);
var arr_sort = nSort(arr_nbr2);
var str_sort = [];
arr_str.forEach(function(element, i)
{
j = arr_sort.indexOf(arr_nbr2[i], i);
str_sort[i] = arr_str[j];
});
console.log(str_sort);
return str_sort;
}
var pseudo_list = ["teddy95", "gabrielc", "ngozi"]; //The list (I just put the first 3 to not to write to much unnecessary code)
var x_ = [29, 26, 4]; // The X Coordinate list
var y_ = [519, 461, 143]; // The Y Coordinate list
var distance = [[]]; // The 2D Array for distance (distance[0][0] being the member's distance tower himself (which is obviously 0).
//Calculating Distances And Storing them in the 2D Array
y_.forEach(function(element, i)
{
distance[i] = [];
x_.forEach(function(element, j)
{
distance[i][j] = Math.ceil(calcDist(x_[i], y_[i], x_[j], y_[j]));
});
});
//Displaying Sorted Array ascending (Trying)
y_.forEach(function(element, i)
{
x_.forEach(function(element, j)
{
document.write(pseudo_list[i] + ' -> ' + nSort2(pseudo_list, distance[i])[j] + ': ' + distance[i][j] + '<br>');
});
});
I think your problem come from over complicating the data structures (I'm not insulting you just sharing an opinion).
In the code below all the input (pseudo, x, y) is stored in an object so player data is easier to manipulate.
Then I'm not using a matrix because you end up creating new issues namely I'd expect distance[1][2] = distance[2][1] so sorting will create duplicate results (and the diagonal doesn't help since it represents the distance from yourself). Instead I have a 1D array constructed with no duplicates, i.e. it contains the distance from the first element to all the others (i.e. second, third, ...), then the second element from the "ones on the right" (i.e. third, fourth, ...), ...
Once you have all the distance information, sorting is a trivial task so is displaying the result.
//Calculating Distance
function calcDist(xA, yA, xB, yB) {
return Math.sqrt(Math.pow((xB - xA), 2) + Math.pow((yB - yA), 2));
}
let players = [{
pseudo: "teddy95",
x: 29,
y: 519
},
{
pseudo: "gabrielc",
x: 26,
y: 461
},
{
pseudo: "ngozi",
x: 4,
y: 143
}]
let distances = []
players.forEach(function (element, i) {
for (let j = i + 1; j < players.length; ++j) {
distances.push({
player1: element,
player2: players[j],
distance: Math.ceil(calcDist(element.x, element.y, players[j].x, players[j].y))
})
}
})
distances.sort(function (a, b) { return a.distance - b.distance })
distances.forEach(function (element, i) {
document.write(element.player1.pseudo + ' - ' + element.player2.pseudo + ' dist ' + element.distance + '<br>')
})

How to make a AJAX driven board in a Snake and ladder turn based game which updates with players playing in different browsers?

I am working on developing a Multiplayer turn based Snake & Ladder game using HTML/JS(Front-end), PHP/MySQL back ended.
It is a AJAX driven game.
I have successfully done the following:
Created a login/Register page storing values in the database.
Upon Login -> Clicking on a button called 'multiplayer game': the user will be directed to a Chat-room where he can select a player with whom he needs to play.
Have implemented the AJAX driven chat system so real time chatting is achieved.
Once a user selects a player, both there pages get updated with against whom they are playing but not the board(since board is not written to implement ajax as of now)
Have been utilizing resources in the web and developing this game. But now the issue I am having is:
I have designed the board game logic in Javascript and upon rolling of dice the two players move along the board. THIS BOARD IS FOR NOW NOT AJAX DRIVEN i.e, if Player1 makes a move, the move has to be updated in the Player 2 board as well.
ABOVE SCREENSHOT: When two players I registered and logged in 'Chris' & 'Paul' for instance are in there respective boards and you can see there chats too work. But When I click on the 'Roll Dice' button, the players indicated by white and yellow move just in one board, which is logical since I have just created two players in Javascript and wrote the logic(They are not yet related to Crane and Chris).
BOARD.JS file below:
var player1 = $("#UserName").val();
var player2 = $("#Opponent").val();
var gameId = $("#GameId").val();
console.log("name of first player: ",player1);
console.log("name of second player: ",player2);
console.log("Game ID is: ",gameId);//getting above values through session variables
window.rollDice = ()=>{
const max = 6;
const roll = Math.ceil(Math.random() * max);
$('.rolledValue').html("Rolled Dice Value is: " + roll);
console.log("You rolled", roll);
let currentPlayer = players[currentPlayerTurn];
currentPlayer.position += roll;
ladders.forEach(ladder=>{
if (ladder.start === currentPlayer.position) {
console.log("You stepped on a ladder!");
currentPlayer.position = ladder.end;
}
});
if (currentPlayer.position === position) {
console.log("Player has won!");
hasWon = true;
}
if (currentPlayer.position === position) {
const diff = currentPlayer.position - position;
currentPlayerPosition = position - diff;
}
currentPlayerTurn ++;
if (currentPlayerTurn >= players.length) {
currentPlayerTurn = 0;
}
renderBoard();
}
const players = [{
name: player1,
position: 0,
color: "gold"
},{
name:player2,
position: 0,
color: "white"
}];
let currentPlayerTurn = 0;
const width = 9;
const height = 9;
const board = [];
let position = 0;
let blackSquare = false;
const ladders = [{
start: 2,
end: 22
},{
start: 50,
end: 34
},{
start: 10,
end: 44
},{
start: 61,
end: 19
},{
start: 70,
end: 83
},{
start:78,
end: 4
}];
for (var y = height; y >= 0; y--) {
let row = [];
board.push(row);
for (var x = 0; x < width; x++) {
row.push({x,y,occupied:null,position,color: blackSquare ? "steelblue" : "silver"});
blackSquare = !blackSquare;
position ++;
}
}
const boardSizeConst = 50;
const renderBoard = ()=>{
let boardHTML = ``;
board.forEach(row=>{
row.forEach(square=>{
boardHTML += `<div class=square style="top:${square.y * boardSizeConst}px; left:${square.x * boardSizeConst}px; background-color:${square.color}"></div>`
});
});
players.forEach(player=>{
let square = null;
board.forEach(row=>{
row.forEach(square=>{
if (square.position === player.position) {
boardHTML += `<div class=player style="top:${square.y * boardSizeConst + 5}px; left:${square.x * boardSizeConst + 5}px;background-color:${player.color}"></div>`;
}
});
});
});
ladders.forEach(ladder=>{
//let start = 0;
let startPos = {x:0,y:0};
let endPos = {x:0,y:0};
board.forEach(row=>{
row.forEach(square=>{
if (square.position === ladder.start) {
startPos.x = square.x * boardSizeConst;
startPos.y = square.y * boardSizeConst;
}
if (square.position === ladder.end) {
endPos.x = square.x * boardSizeConst;
endPos.y = square.y * boardSizeConst;
}
});
});
const isLadder = ladder.end > ladder.start;
drawLine({color : isLadder ? "green" : "red",startPos,endPos});
});
document.getElementById("board").innerHTML = boardHTML;
}
However, for now circles are not related to them. But I want to create a mechanism 'When Chris rolls dice in his board, it has to get updated in Crane board & vice-versa.
Need help. I am newbie to php but kind of have come till this point.

Get the color of one pixel at Photoshop scripts

I am trying to figure out how to get the color of one defined Pixel.
In my imagination its shoud look like:
color = get.color.Pixel(x,y);
Maybe someone can help me with this piece of code?
Photoshop's JavaScript API doesn't provide a mechanism like you imagine in your question.
You'll need to utilize the Document.colorSamplers.add([x, y]) method, then read each component color value via its properties:
The following gist shows how to obtain either rgb or cmyk values for a given x,y coordinate:
#target photoshop
// Define the x and y coordinates for the pixel to sample.
var x = 1;
var y = 1;
// Add a Color Sampler at a given x and y coordinate in the image.
var pointSample = app.activeDocument.colorSamplers.add([(x - 1),(y - 1)]);
// Obtain array of RGB values.
var rgb = [
pointSample.color.rgb.red,
pointSample.color.rgb.green,
pointSample.color.rgb.blue
];
// Obtain array of rounded CMYK values.
var cmyk = [
Math.round(pointSample.color.cmyk.cyan),
Math.round(pointSample.color.cmyk.magenta),
Math.round(pointSample.color.cmyk.yellow),
Math.round(pointSample.color.cmyk.black)
];
// Remove the Color Sampler.
pointSample.remove();
// Display the complete RGB values and each component color.
alert('RGB: ' + rgb)
alert('red: ' + rgb[0])
alert('green: ' + rgb[1])
alert('blue: ' + rgb[2])
// Display the complete CMYK values and each component color.
alert('CMYK: ' + cmyk)
alert('cyan: ' + cmyk[0])
alert('magenta: ' + cmyk[1])
alert('yellow: ' + cmyk[2])
alert('black: ' + cmyk[3])
Here's a simple script using a ColorSampler. It's set up to return RGB values.
function PixelSampler(doc) {
this.doc = doc
this.doc.colorSamplers.removeAll();
this.sampler = this.doc.colorSamplers.add([0, 0]);
}
// Return an array of R, G, B pixel values for a particular coordinate.
PixelSampler.prototype.get = function (x, y) {
this.sampler.move([x, y]);
const R = this.sampler.color.rgb.red;
const G = this.sampler.color.rgb.green;
const B = this.sampler.color.rgb.blue;
return [R, G, B];
}
////////////////////////////////////////////////////////
/// SOME TESTS /////////////////////////////////////////
////////////////////////////////////////////////////////
const p = new PixelSampler(app.activeDocument);
alert("Pixel 0 =\n\n" + p.get(0, 0));
$.hiresTimer;
var n = 1000; //p.width * p.height;
for (var i = 0; i < n; i++) p.get(i, 0);
sec = ($.hiresTimer / 1000 / 1000);
alert("Got " + (n / 1000) + " kilopixels in " + sec.toFixed(2) + " seconds.");
This gives me pixel values at about 100 pixels per second on my machine.
I found this and cleaned up the script a bit. Basically, the idea is to:
Save the current image as a raw bitmap.
Read it back in, but on the javascript side.
Do all access to pixels on the javascript side.
This gives me pixel values at about 72,000 pixels per second, not including the overhead of writing the raw data to disk and reading it back in. It has the added benefit that you can set pixel values, too.
// Adapted from https://community.adobe.com/t5/photoshop/get-index-of-each-pixel/td-p/10022899?page=1
// The purpose is to query (and change) pixel values quickly.
//
// The secret to speed is doing everything on the script side rather than ask Photoshop to do things.
// We use files on disk as an intermediary; on the script side, we read / write it as a binary file; on the
// Photoshop side, we save / open it as a raw bitmap.
//
// Only works on RGB 8bpp images, but this could be easily extended to support others.
function RawPixels(doc) {
this.doc = doc;
const currentActiveDoc = app.activeDocument;
// Obtain the width and height in pixels of the desired document.
const currentRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
app.activeDocument = doc;
this.width = Number(doc.width.value);
this.height = Number(doc.height.value);
this.length = this.width * this.height;
this.pixelData = "";
// Return the ruler to its previous state.
app.preferences.rulerUnits = currentRulerUnits;
try {
// We're going to save this document as a raw bitmap to be able to read back in the pixel values
// themselves.
const file = new File(Folder.temp.fsName + "/" + Math.random().toString().substr(2) + ".raw");
// Set up the save action.
// See https://helpx.adobe.com/photoshop/using/file-formats.html#photoshop_raw_format for some info,
// and more technical at https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
var rawFormat = new ActionDescriptor();
rawFormat.putString(stringIDToTypeID("fileCreator"), "8BIM");
rawFormat.putBoolean(stringIDToTypeID("channelsInterleaved"), true);
var saveAction = new ActionDescriptor();
saveAction.putObject(stringIDToTypeID("as"), stringIDToTypeID("rawFormat"), rawFormat);
saveAction.putPath(stringIDToTypeID("in"), file);
saveAction.putBoolean(stringIDToTypeID("copy"), false);
executeAction(stringIDToTypeID("save"), saveAction, DialogModes.NO);
// File is saved; now read it back in as raw bytes.
file.open("r");
file.encoding = "BINARY";
this.pixelData = file.read();
const err = file.error;
file.close();
file.remove();
file = null;
if (err) alert(err);
}
catch (e) { alert(e); }
// Return focus to whatever the user had.
app.activeDocument = currentActiveDoc;
}
// Calculate offset from x, y coordinates. Does not check for valid bounds.
getOffset = function(x, y) {
if (y == undefined) {
// allow linear indices too
y = Math.floor(x / this.width);
x = x - y * this.width;
}
return (y * this.width + x) * 3;
}
// Return an array of R, G, B pixel values for a particular coordinate.
RawPixels.prototype.get = function (x, y) {
const off = getOffset(x, y);
const R = this.pixelData.charCodeAt(off + 0);
const G = this.pixelData.charCodeAt(off + 1);
const B = this.pixelData.charCodeAt(off + 2);
return [R, G, B];
}
// Set the pixel at x, y to the values in RGB.
RawPixels.prototype.set = function (RGB, x, y) {
const off = getOffset(x, y);
// note: note checking that length of p = 3!
const R = String.fromCharCode(RGB[0]);
const G = String.fromCharCode(RGB[1]);
const B = String.fromCharCode(RGB[2]);
this.pixelData = this.pixelData.substr(0, off) + R + G + B + this.pixelData.substr(off + 3);
}
// If any changes were made to the pixels, we need to save them to disk and have Photoshop read that file back in.
// We do that by creating a new layer in the desired document.
RawPixels.prototype.create_layer = function () {
try {
const file = new File(Folder.temp.fsName + "/" + Math.random().toString().substr(2) + ".raw");
file.open("w");
file.encoding = "BINARY";
file.write(this.pixelData);
const err = file.error;
file.close();
if (err) { file.remove(); alert(err); return; }
var rawFormat = new ActionDescriptor();
rawFormat.putInteger(stringIDToTypeID("width"), this.width);
rawFormat.putInteger(stringIDToTypeID("height"), this.height);
rawFormat.putInteger(stringIDToTypeID("channels"), 3);
rawFormat.putBoolean(stringIDToTypeID("channelsInterleaved"), true);
rawFormat.putInteger(stringIDToTypeID("depth"), 8);
var openAction = new ActionDescriptor();
openAction.putPath(stringIDToTypeID("null"), file);
openAction.putObject(stringIDToTypeID("as"), stringIDToTypeID("rawFormat"), rawFormat);
executeAction(stringIDToTypeID("open"), openAction, DialogModes.NO);
file.remove();
// The new active document is the file we just opened. Duplicate its contents into
// a new layer in our desired document, then close this temporary file.
app.activeDocument.activeLayer.duplicate(this.doc.layers[0], ElementPlacement.PLACEBEFORE);
const tempDoc = app.activeDocument;
app.activeDocument = this.doc;
this.doc.layers[0].name = "Pixels";
app.activeDocument = tempDoc;
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
app.activeDocument = this.doc;
}
catch (e) { alert(e); }
}
////////////////////////////////////////////////////////
/// SOME TESTS /////////////////////////////////////////
////////////////////////////////////////////////////////
$.hiresTimer;
const p = new RawPixels(app.activeDocument);
var sec = ($.hiresTimer / 1000 / 1000);
alert("Init RawPixels in " + sec.toFixed(2) + " seconds");
alert("Pixel 0 =\n\n" + p.get(0));
var a = new Array();
for (var i = 0; i < 100; i++) a.push(p.get(i));
alert("Pixel 0-99 = \n\n" + a.toSource());
p.set(0, [1, 200, 3]);
alert("New Pixel 0=\n\n" + p.get(0));
$.hiresTimer;
var n = p.width * p.height;
for (var i = 0; i < n; i++) p.get(i);
sec = ($.hiresTimer / 1000 / 1000);
alert("Got " + (n / 1000 / 1000) + " megapixels in " + sec.toFixed(2) + " seconds.");
$.hiresTimer;
n = 10;
for (var i = 0; i < n; i++) p.set([255, i * 20, i * 10], 1 + i * 2);
sec = ($.hiresTimer / 1000 / 1000);
//alert("Set " + n + " pixels in " + sec.toFixed(2) + " seconds");
p.create_layer();
alert("New layer created with new pixels");

Categories

Resources