2016-08-15 69 views
0

我一直在摆弄jpeg-js模块和节点JS缓冲区,试图创建一个小的命令行程序来修改已解码的JPEG缓冲区数据,并创建一个X数量的反转扫描线和X数量的正常扫描线保存一个新的JPEG。换句话说,我正在寻找翻转图像的部分,但不是整个图像本身(当然有大量的模块可以做这样的事情,但不是我具体的使用案例)。如何使用jpeg-js模块/节点JS缓冲区反转扫描线?

为了创建反转/正常的线条图案,我一直在逐行阅读/写入,并将该线条的一部分保存到一个变量中,然后从扫描线的末端开始,并逐渐递减4字节(一个RGBA值的分配),直到我在行的开头。程序代码:

'use strict'; 
const fs = require('fs'); 
const jpeg = require('jpeg-js'); 
const getPixels = require('get-pixels'); 

let a = fs.readFileSync('./IMG_0006_2.jpg'); 
let d = Buffer.allocUnsafe(a.width * a.height * 4); 
let c = jpeg.decode(a); 

let val = false; // track whether normal or reversed scanlines 
let lineWidth = b.width * 4; 
let lineCount = 0; 
let track = 0; 
let track2 = 0; 
let track3 = 0; 
let curr, currLine; // storage for writing/reading scnalines, respectively 
let limit = { 
    one: Math.floor(Math.random() * 141), 
    two: Math.floor(Math.random() * 151), 
    three: Math.floor(Math.random() * 121) 
}; 
if (limit.one < 30) { 
    limit.one = 30; 
} 
if (limit.two < 40) { 
    limit.two = 40; 
} 
if (limit.two < 20) { 
    limit.two = 20; 
} 
let calc = {}; 
calc.floor = 0; 
calc.ceil = 0 + lineWidth; 

d.forEach(function(item, i) { 
    if (i % lineWidth === 0) { 
     lineCount++; 
     /* // alternate scanline type, currently disabled to figure out how to succesfully reverse image 
     if (lineCount > 1 && lineCount % limit.one === 0) { 
      // val = !val; 
     } 
     */ 
     if (lineCount === 1) { 
      val = !val; // setting alt scanline check to true initially 
     } else if (calc.floor + lineWidth < b.data.length - 1) { 
      calc.floor += lineWidth; 
      calc.ceil += lineWidth; 
     } 
     currLine = c.data.slice(calc.floor, calc.ceil); // current line 
     track = val ? lineWidth : 0; // tracking variable for reading from scanline 
     track2 = val ? 4 : 0; // tracking variable for writing from scanline 
    } 
    //check if reversed and writing variable has written 4 bytes for RGBA 
     //if so, set writing source to 4 bytes at end of line and read from there incrementally 
    if (val && track2 === 4) { 
     track2 = 0; // reset writing count 
     curr = currLine.slice(track - 4, track); // store 4 previous bytes as writing source 
     if (lineCount === 1 && lineWidth - track < 30) console.log(curr); //debug 
    } else { 
     curr = currLine; //set normal scanline 
    } 

    d[i] = curr[track2]; 

    // check if there is no match between data source and decoded image 
    if (d[i] !== curr[track2]) { 
     if (track3 < 50) { 
      console.log(i); 
     } 
     track3++; 
    } 
    track2++; //update tracking variable 
    track = val ? track - 1 : track + 1; //update tracking variable 



}); 


var rawImageData = { 
    data: d, 
    width: b.width, 
    height: b.height 
}; 
console.log(b.data.length); 
console.log('errors\t', track3); 
var jpegImageData = jpeg.encode(rawImageData, 100); 

fs.writeFile('foo2223.jpg', jpegImageData.data); 

唉,我写的反向扫描代码不正确。不幸的是,我只能成功地颠倒我测试图像的红色通道(见左下图),蓝色和绿色通道变成了模糊的模糊。配色方案应该看起来像正确的图像。

current color output ideal color output

我在做什么错在这里?

回答

2

对于反转行,您存储了4个字节的切片(4个字节= 1个像素),然后正确写入像素的第一个值(红色)。 但是在下一次迭代中,您用currLine覆盖片段curr,其余通道获取错误的值。

if (val && track2 === 4) { 
    track2 = 0; // reset writing count 
    curr = currLine.slice(track - 4, track); // store 4 previous bytes as writing source 
    if (lineCount === 1 && lineWidth - track < 30) console.log(curr); //debug 
} else { 
    curr = currLine; //set normal scanline 
} 
  • 迭代0:val == truetrack2 == 4,设置curr到下一像素,写入红色通道。
  • 迭代1:val == true,track2 == 1, (val && track2 === 4) == false,设置currcurrLine,写入绿色通道。

可以移动track2 === 4分支,以避免这一点:

if (val) { 
    if (track2 === 4) { 
    track2 = 0; // reset writing count 
    curr = currLine.slice(track - 4, track); // store 4 previous bytes as writing source 
    if (lineCount === 1 && lineWidth - track < 30) console.log(curr); //debug 
    } 
} else { 
    curr = currLine; //set normal scanline 
} 

固定码应该是这样的:

function flipAlt(input, output) { 
    const fs = require('fs'); 
    const jpeg = require('jpeg-js'); 

    let a = fs.readFileSync(input); 
    let b = jpeg.decode(a); 
    let d = Buffer.allocUnsafe(b.width * b.height * 4); 

    let val = false; // track whether normal or reversed scanlines 
    let lineWidth = b.width * 4; 
    let lineCount = 0; 
    let track = 0; 
    let track2 = 0; 
    let track3 = 0; 
    let curr, currLine; // storage for writing/reading scnalines, respectively 
    let limit = { 
    one: Math.floor(Math.random() * 141), 
    two: Math.floor(Math.random() * 151), 
    three: Math.floor(Math.random() * 121) 
    }; 
    if (limit.one < 30) { 
    limit.one = 30; 
    } 
    if (limit.two < 40) { 
    limit.two = 40; 
    } 
    if (limit.two < 20) { 
    limit.two = 20; 
    } 
    let calc = {}; 
    calc.floor = 0; 
    calc.ceil = 0 + lineWidth; 

    d.forEach(function(item, i) { 
    if (i % lineWidth === 0) { 
     lineCount++; 
     if (lineCount > 1) { 
     val = !val; 
     } 
     if (lineCount === 1) { 
     val = !val; // setting alt scanline check to true initially 
     } else if (calc.floor + lineWidth < b.data.length - 1) { 
     calc.floor += lineWidth; 
     calc.ceil += lineWidth; 
     } 
     currLine = b.data.slice(calc.floor, calc.ceil); // current line 
     track = val ? lineWidth : 0; // tracking variable for reading from scanline 
     track2 = val ? 4 : 0; // tracking variable for writing from scanline 
    } 
    //check if reversed and writing variable has written 4 bytes for RGBA 
    //if so, set writing source to 4 bytes at end of line and read from there incrementally 
    if (val) { 
     if (track2 === 4) { 
     track2 = 0; // reset writing count 
     curr = currLine.slice(track - 4, track); // store 4 previous bytes as writing source 
     if (lineCount === 1 && lineWidth - track < 30) console.log(curr); //debug 
     } 
    } else { 
     curr = currLine; //set normal scanline 
    } 

    d[i] = curr[track2]; 

    // check if there is no match between data source and decoded image 
    if (d[i] !== curr[track2]) { 
     if (track3 < 50) { 
     console.log(i); 
     } 
     track3++; 
    } 
    track2++; //update tracking variable 
    track = val ? track - 1 : track + 1; //update tracking variable 

    }); 

    var rawImageData = { 
    data: d, 
    width: b.width, 
    height: b.height 
    }; 
    console.log(b.data.length); 
    console.log('errors\t', track3); 
    var jpegImageData = jpeg.encode(rawImageData, 100); 

    fs.writeFile(output, jpegImageData.data); 
} 

flipAlt('input.jpg', 'output.jpg'); 

flipped image

相反跟踪数组索引,您可以使用实用程序库如lodash,它应该让事情变得更容易:

function flipAlt(input, output) { 
    const fs = require('fs'); 
    const jpeg = require('jpeg-js'); 
    const _ = require('lodash'); 

    const image = jpeg.decode(fs.readFileSync(input)); 
    const lines = _.chunk(image.data, image.width*4); 
    const flipped = _.flatten(lines.map((line, index) => { 
    if (index % 2 != 0) { 
     return line; 
    } 
    const pixels = _.chunk(line, 4); 
    return _.flatten(pixels.reverse()); 
    })); 

    const imageData = jpeg.encode({ 
    width: image.width, 
    height: image.height, 
    data: new Buffer(flipped) 
    }, 100).data; 

    fs.writeFile(output, imageData); 
} 

flipAlt('input.jpg', 'output.jpg');