Home > other >  encrypt and decrypt image using javascript
encrypt and decrypt image using javascript

Time:11-22

My server using this python function to encrypt and decrypt images in a bytearray format. I want to do the same encryption in the frontend and send to this function in the backend. how to convert this method into JavaScript

def encrypted_decrypted_image(image):
    key = 48
    count = 0
    for index, value in enumerate(image):
        count  = 1
        image[index] = value ^ key
        if count == 10:
            break
    return image

CodePudding user response:

Here's how to do it with Array.reduce(),

// def encrypted_decrypted_image(image):
//    key = 48
//    count = 0
//    for index, value in enumerate(image):
//        count  = 1
//        image[index] = value ^ key
//        if count == 10:
//            break
//    return image

function xorImage(imageBuffer, key=48){
  return imageBuffer.reduce((acc, value, index) => {
    if(index == 10) return acc;
    acc.push(value ^ key);
    return acc;
  }, [])
}

console.log(xorImage([1, 20, 3, 4, 5, 6, 7, 8, 9]))
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

To get individual pixels components from an image, you would first draw that image to a canvas:

const image = document.getElementById('image');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = image.width;
const height = image.height;

canvas.width = width;
canvas.height = height;

// Draw original image: 
context.drawImage(image, 0, 0, width, height);

Then, get the values for the pixels you are going to update:

const data = context.getImageData(0, 0, width, height).data;

Note the shape and type of the data returned by the CanvasRenderingContext2D.getImageData() function:

ImageData ctx.getImageData(sx, sy, sw, sh);
  • sx: The x coordinate of the upper left corner of the rectangle from which the ImageData will be extracted.
  • sy: The y coordinate of the upper left corner of the rectangle from which the ImageData will be extracted.
  • sw: The width of the rectangle from which the ImageData will be extracted.
  • sh: The height of the rectangle from which the ImageData will be extracted.

You can see it returns an ImageData object, whatever that is. The important part here is that that object has a .data property which contains all our pixel values.

However, note that .data property is a 1-dimension Uint8ClampedArray, which means that all the pixel's components have been flattened, so you are getting something that looks like this:

Let's say you have a 2x2 image like this:

 RED PIXEL |       GREEN PIXEL
BLUE PIXEL | TRANSPARENT PIXEL

Then, you will get them like this:

[ 255, 0, 0, 255,    0, 255, 0, 255,    0, 0, 255, 255,    0, 0, 0, 0          ]
|   RED PIXEL   |    GREEN PIXEL   |     BLUE PIXEL   |    TRANSPAERENT  PIXEL |
|   1ST PIXEL   |      2ND PIXEL   |      3RD PIXEL   |             4TH  PIXEL | 

You can then transform these values however you'd like, and in your specific use case, that would be all you need to do on the frontend before sending the transformed data to the server:

const transformedData = encryptedDecryptedImage(data);

fetch('httsp://', { ... });

If you want to draw the transformed data back on the page, you first need to convert it back to ImageData using CanvasRenderingContext2D.createImageData() and CanvasRenderingContext2D.putImageData():

const imageData = context.createImageData(width, height);

imageData.data.set(new Uint8ClampedArray(transformedData));

context.putImageData(transformedData, 0, 0);

Working example:

const image = document.getElementById('image');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = image.width;
const height = image.height;

canvas.width = width;
canvas.height = height;

// Draw original image: 
context.drawImage(image, 0, 0, width, height);

// Transform the top half of the image (each pixel has 4 coordinates, RGB and alpha):
const maxTransformedCoords = width * Math.round(height / 2) * 4; 

// Avoid processing more than needed:
const requiredRows = Math.ceil(maxTransformedCoords / (width * 4));

// Get the pixel component values as an array:
const data = context.getImageData(0, 0, width, requiredRows).data;

// Your transform logic (with some changes):

const key = 48;

let count = 0;

const transformedData = data.map((value, i) => {    
  if (  count > maxTransformedCoords) return value;

  // Turn alpha coordinates opaque:
  // if ((i   1) % 4 === 0) return 255;

  // Your logic:
  return value ** key;
});

// Turn the transformed data into an ImageData object:
const imageData = context.createImageData(width, requiredRows);
imageData.data.set(new Uint8ClampedArray(transformedData));

// Draw the transformed pixels:
context.putImageData(imageData, 0, 0);

// Display it on the page:
canvas.id = 'canvas';
document.body.append(canvas);
body {
  margin: 0;
  height: 100vh;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  font-family: monospace;
  overflow: hidden;
}

#image,
#canvas {
  border: 4px solid white;
  border-radius: 2px;
  box-shadow: 0 0 32px 0 rgba(0, 0, 0, .25);
  width: 150px;
  box-sizing: border-box;
  display: block;
  background: cyan;
}

#canvas {
  margin-left: 32px;
}
<img id="image" src="data:image/gif;base64,R0lGODlhSwBLAPEAACMfIO0cJAAAAAAAACH/C0ltYWdlTWFnaWNrDWdhbW1hPTAuNDU0NTUAIf4jUmVzaXplZCBvbiBodHRwczovL2V6Z2lmLmNvbS9yZXNpemUAIfkEBQAAAgAsAAAAAEsASwAAAv Uj6mb4A QY7TaKxvch MPKpC0eeUUptdomOzJqnLUvnFcl7J6Pzn9I l2IdfII8DZiCnYsYdK4qRTptAZwQKRVK71CusOgx2nFRrlhMu 33o2NEalC6S9zQvfi3Mlnm9WxeQ396F2 HcQsMjYGEBRVbhy5yOp6OgIeVIHpEnZyYCZ6cklKBJX Kgg2riqKoayOWl2 VrLmtDqBptIOjZ6K4qAeSrL8PcmHExsgMs2dpyIxPpKvdhM/YxaTMW2PGr9GP76BN3VHTMurh7eoU14jsc P845Vn6OTb/P/I68iYOfwGv JOmRNHBfsV5ujA1LqM4eKDoNvXyDqItTxYX/DC9irKBlIhkKGPtFw1JDiMeS7CqWqySPZcKGHH/JHGgIpb6bCl1O0LmT57yCOqoI5UcU0YKjPXmFjMm0ZQ4NIVdGBdZRi9WrjLxJNMY1Yr4dYeuNxWApl1ALHb KDHrTV1owlriedJgSr4Cybu/9dFiWYAagsqAGVkkzaZTAuqD9ywKWMUG9dCO3u2zWpVzIhpW122utZlrHnTN Bq2Mqrlnqh8CQ 0Mrq3Kc  q7eo6dlB3rLuh3abPVbbbI2mxBdhWdsZhid8cr0oy9F08q0k5FXSadiyL1mF5z51a8VsQOp3/LlodkBfzmzWf2bOrtfzr48k/1hupDaLa9rUbO zlwndfaOCURAXRNaCBqBT2BncJakWfTzSYkmCEFr60RX0V8sKaHOltCBJ1tAAFYhHaVVbig3jxp0IBADs=" >
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

⚠️ Note I'm using a small data URI to avoid Cross-Origin issues if I include an external image or an answer that is larger than allowed if I try to use a longer data URI.

  • Related