Heim >Web-Frontend >js-Tutorial >So konvertieren Sie einen einfarbigen QR-Code in einen farbigen QR-Code (JavaScript)

So konvertieren Sie einen einfarbigen QR-Code in einen farbigen QR-Code (JavaScript)

零下一度
零下一度Original
2017-04-28 10:21:483849Durchsuche

In diesem Artikel wird hauptsächlich die Lösung zum Umwandeln von JavaScript-Vollfarb-QR-Code in Farb-QR-Code vorgestellt. Es hat einen gewissen Referenzwert.

In diesem Artikel wird hauptsächlich erläutert, wie um einen einfarbigen QR-Code in Farbe umzuwandeln.

Vor einiger Zeit gab es im Unternehmen eine Nachfrage, die den durch den Hintergrund erzeugten einfarbigen QR-Codes nicht gefiel. Sie wollten farbige QR-Codes Codes. Dann fiel mir diese Aufgabe zu. Da es sich um eine Bildverarbeitung handelte, bestand die Hauptidee darin, dass Canvas Pixeloperationen ausführen kann. Daher habe ich einige Versuche unternommen und bin auf einige Fallstricke gestoßen.

Vorausgesetzte Kenntnisse

drawImage Methode kann Bilder auf Leinwand zeichnen, getImageData Die -Methode kann die Informationen aller Pixel in einem rechteckigen Bereich abrufen. Das Datenattribut des Rückgabewerts ist ein eindimensionales Array, das die Informationen aller Pixel speichert und vier Elemente darstellt jeweils r,g,b und Transparenz. Die Reihenfolge der Pixel in einem eindimensionalen Array ist von links nach rechts und von oben nach unten. Die letzte ist die Methode putImageData, die das geänderte Pixelinformationsarray zurück auf die Leinwand wirft.

Einige kleine Fallstricke

Der erste Fallstrick besteht darin, dass Canvas Attribute verwendet, um Breite und Höhe anzugeben, kein CSS verwenden

Die zweite Gefahr besteht darin, dass die Bildverarbeitung eine Serverumgebung erfordert, die lokal nicht möglich ist. Ich habe gehört, dass dies auf einigen Sicherheitsüberlegungen beruhte. Letztendlich habe ich den Canvas-Fehler durch die Einrichtung eines lokalen Servers behoben.

Die dritte Gefahr ist der Stapelüberlauf. Ich werde später noch nicht ausführlich darauf eingehen.

Die Idee des Farbwechsels.

Die Hauptidee kommt von „Aha!“ Algorithmus! „In den Kapiteln der Tiefensuche und der Breitensuche realisiert der letzte Teil des Kapitels, „Abenteuer auf der Schatzinsel“, die fortlaufende Nummerierung verschiedener Bereiche. Stellen Sie sich die Zahlen als Farben vor, aber sie sind tatsächlich gleich.

Spezifische Implementierung

Tatsächlich ist der sogenannte Farb-QR-Code nicht die Art von QR-Code, bei dem die Farbe jedes Pixels zufällig ist. Wenn Sie sich den QR-Code genau ansehen, werden Sie feststellen, dass die schwarzen Teile ein Stück nach dem anderen sind. Sie sind auf die weißen verteilt, genau wie Inseln, die im Meer verteilt sind. Wir müssen jedes schwarze Stück einzeln einfärben . Die Essenz eines schwarzen Blocks ist ein schwarzes Pixel.

Wie bereits erwähnt, verwenden wir Canvas, weil es Pixeloperationen ausführen kann. Unsere Operation besteht also tatsächlich darin, die Pixel zu färben. Wir möchten die Hintergrundfarbe offensichtlich nicht färben, daher muss die Hintergrundfarbe beurteilt werden. Vorher wurde auch erwähnt, dass die Hintergrundfarbe wie der Ozean ist, der die schwarzen Farbblöcke teilt. Das bedeutet, dass wir, nachdem wir ein Pixel gelesen und gefärbt haben, ständig die Farbe der Pixel auf der rechten Seite davon beurteilen Wenn die rechte Seite eines Pixels die Hintergrundfarbe ist, sollten wir auch die Möglichkeit anderer Richtungen ausprobieren Überprüfen Sie durch Rekursion ständig, ob die Farbe der nächsten Position des aktuellen Pixels die Hintergrundfarbe ist. Versuchen Sie es dann mit einer anderen Richtung, färben Sie sie und führen Sie sie dann aus Vier Richtungen auf dem gefärbten Pixel überprüfen.

Um festzustellen, ob es sich um eine Hintergrundfarbe handelt, müssen Sie den RGBA-Wert vergleichen. Die anderen sind ein Array von Pixelinformationen Wenn Sie also die korrekten Pixelinformationen vergleichen möchten, muss dieser Teil ebenfalls verarbeitet werden.

Es kann etwas verwirrend sein, werfen wir einen Blick auf den ersten Teil des Codes

, Leinwand

// canvas 部分
var canvas = $("canvas")[0];
var ctx = canvas.getContext("2d");

var img = new Image();
img.src = path; //这里的path就是图片的地址

den zweiten Teil , Farbverarbeitung im dritten Teil von

// 分离颜色参数  返回一个数组
var colorRgb = (function() {
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;

  return function(str) {
    var sColor = str.toLowerCase();
    if (sColor && reg.test(sColor)) {
      if (sColor.length === 4) {
        var sColorNew = "#";
        for (var i = 1; i < 4; i += 1) {
          sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
        }
        sColor = sColorNew;
      }
      //处理六位的颜色值 
      var sColorChange = [];
      for (var i = 1; i < 7; i += 2) {
        sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
      }
      return sColorChange;
    } else {
      var sColorChange = sColor.replace(/(rgb\()|(\))/g, "").split(",").map(function(a) {
        return parseInt(a);
      });
      return sColorChange;
    }
  }
})();

, gibt Anfangsparameter an

Um redundante Vorgänge zu vermeiden, verwenden wir ein Marker-Array zum Aufzeichnen Beurteilte Position

// 参数
var bg = colorRgb("#fff"); //忽略的背景色
var width = 220;
var height = 220;
var imgD; //预留给 像素信息
var colors = ["#368BFF", "#EF2767", "#F17900", "#399690", "#5aa6f7", "#fd417e", "#ffc000", "#59b6a6"];  //染色数组
// 随机colors数组的一个序号
var ranNum = (function() {
  var len = colors.length;
  return function() {
    return Math.floor(Math.random() * len);
  }
})();

// 标记数组 
var book = []; 
for (var i = 0; i < height; i++) { 
  book[i] = []; 
  for (var j = 0; j < width; j++) { 
    book[i][j] = 0; 
  } 
}

Teil 4, Erhalten Sie die Pixelinformationen, durchlaufen Sie jedes Pixel und werfen Sie es schließlich zurück auf die Leinwand

Wenn markiert, überspringen Sie es, wenn nicht markiert Dann randomisieren Sie eine Farbe, suchen Sie zuerst nach dem Zufallsprinzip und färben Sie

img.onload = function() {
  ctx.drawImage(img, 0, 0, width, height);
  imgD = ctx.getImageData(0, 0, width, height);

  for (var i = 0; i < height; i++) {
    for (var j = 0; j < width; j++) {
      if (book[i][j] == 0 && checkColor(i, j, width, bg)) { //没标记过 且是非背景色
        book[i][j] = 1;
        var color = colorRgb(colors[ranNum()]);
        dfs(i, j, color);  //深度优先搜索
      }
    }
  }

  ctx.putImageData(imgD, 0, 0);
}
// 验证该位置的像素 不是背景色为true
function checkColor(i, j, width, bg) {
  var x = calc(width, i, j);

  if (imgD.data[x] != bg[0] && imgD.data[x + 1] != bg[1] && imgD.data[x + 2] != bg[2]) {
    return true;
  } else {
    return false;
  }
}

// 改变颜色值
function changeColor(i, j, colorArr) {
  var x = calc(width, i, j);
  imgD.data[x] = colorArr[0];
  imgD.data[x + 1] = colorArr[1];
  imgD.data[x + 2] = colorArr[2];
}


// 返回对应像素点的序号
function calc(width, i, j) {
  if (j < 0) {
    j = 0;
  }
  return 4 * (i * width + j);
}

Schlüsselcode

Wir verwenden ein Richtungsarray, um die Operation zu vereinfachen. Wir haben uns darauf geeinigt. Die zu versuchende Richtung ist im Uhrzeigersinn, beginnend von rechts.

// 方向数组
var next = [
  [0, 1], //右
  [1, 0], //下
  [0, -1], // 左
  [-1, 0] //上 
];

// 深度优先搜索 
function dfs(x, y, color) {
  changeColor(x, y, color);
  for (var k = 0; k <= 3; k++) {
    // 下一个坐标
    var tx = x + next[k][0];
    var ty = y + next[k][1];

    //判断越界
    if (tx < 0 || tx >= height || ty < 0 || ty >= width) {
      continue;
    }


    if (book[tx][ty] == 0 && checkColor(tx, ty, width, bg)) {
      // 判断位置
      book[tx][ty] = 1;
      dfs(tx, ty, color);
    }

  }
  return;
}
Der letzte Fallstrick, auf den ich gestoßen bin, ist, dass der Stapel überläuft, wenn die Länge und Breite größer als 220 sind. Wenn er jedoch kleiner als dieser Wert ist, gibt es kein Problem. Der spezifische Grund ist nicht klar. Ich vermute, es liegt ein Problem vor, das eine Endlosschleife verursacht.

Alle Codes hier

// 分离颜色参数  返回一个数组
var colorRgb = (function() {
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;

  return function(str) {
    var sColor = str.toLowerCase();
    if (sColor && reg.test(sColor)) {
      if (sColor.length === 4) {
        var sColorNew = "#";
        for (var i = 1; i < 4; i += 1) {
          sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
        }
        sColor = sColorNew;
      }
      //处理六位的颜色值 
      var sColorChange = [];
      for (var i = 1; i < 7; i += 2) {
        sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
      }
      return sColorChange;
    } else {
      var sColorChange = sColor.replace(/(rgb\()|(\))/g, "").split(",").map(function(a) {
        return parseInt(a);
      });
      return sColorChange;
    }
  }
})();

// 验证该位置的像素 不是背景色为true
function checkColor(i, j, width, bg) {
  var x = calc(width, i, j);

  if (imgD.data[x] != bg[0] && imgD.data[x + 1] != bg[1] && imgD.data[x + 2] != bg[2]) {
    return true;
  } else {
    return false;
  }
}

// 改变颜色值
function changeColor(i, j, colorArr) {
  var x = calc(width, i, j);
  imgD.data[x] = colorArr[0];
  imgD.data[x + 1] = colorArr[1];
  imgD.data[x + 2] = colorArr[2];
}

// 返回对应像素点的序号
function calc(width, i, j) {
  if (j < 0) {
    j = 0;
  }
  return 4 * (i * width + j);
}
// 方向数组
var next = [
  [0, 1], //右
  [1, 0], //下
  [0, -1], // 左
  [-1, 0] //上 
];

// 深度优先搜索 
function dfs(x, y, color) {
  changeColor(x, y, color);
  for (var k = 0; k <= 3; k++) {
    // 下一个坐标
    var tx = x + next[k][0];
    var ty = y + next[k][1];

    //判断越界
    if (tx < 0 || tx >= height || ty < 0 || ty >= width) {
      continue;
    }

    if (book[tx][ty] == 0 && checkColor(tx, ty, width, bg)) {
      // 判断位置
      book[tx][ty] = 1;
      dfs(tx, ty, color);
    }

  }
  return;
}

/*****上面为封装的函数*****/

/***参数***/
var bg = colorRgb("#fff"); //忽略的背景色
var width = 220;
var height = 220;
var imgD; //预留给 像素信息数组
var colors = ["#368BFF", "#EF2767", "#F17900", "#399690", "#5aa6f7", "#fd417e", "#ffc000", "#59b6a6"];  //染色数组
// 随机colors数组的一个序号
var ranNum = (function() {
  var len = colors.length;
  return function() {
    return Math.floor(Math.random() * len);
  }
})();

// 标记数组 
var book = []; 
for (var i = 0; i < height; i++) { 
  book[i] = []; 
  for (var j = 0; j < width; j++) { 
    book[i][j] = 0; 
  } 
}
// canvas 部分
var canvas = $("canvas")[0];
var ctx = canvas.getContext("2d");

var img = new Image();
img.src = path; //这里的path就是图片的地址
img.onload = function() {
  ctx.drawImage(img, 0, 0, width, height);
  imgD = ctx.getImageData(0, 0, width, height);

  for (var i = 0; i < height; i++) {
    for (var j = 0; j < width; j++) {
      if (book[i][j] == 0 && checkColor(i, j, width, bg)) { //没标记过 且是非背景色
        book[i][j] = 1;
        var color = colorRgb(colors[ranNum()]);
        dfs(i, j, color);  //深度优先搜索
      }
    }
  }

  ctx.putImageData(imgD, 0, 0);
}

Zusammenfassung

Obwohl es etwas lang aussieht, verarbeiten die meisten Funktionen tatsächlich Pixelinformationen. Um dies zu implementieren, ist es wichtig, die Tiefensuche zu verstehen. Die gefärbten Pixel werden natürlich markiert. Wenn also ein neues, nicht markiertes Pixel erscheint, bedeutet dies natürlich, dass neue Farbblöcke vorhanden sind. Achten Sie im Detail nur auf die Übereinstimmung zwischen imgD.data und den Pixelseriennummern, und alles andere wird gut. Allerdings ist zu beachten, dass aufgrund der sehr kleinen Pixel Farbblöcke, die mit dem bloßen Auge nicht zusammenhängend zu sein scheinen, möglicherweise miteinander verbunden sind und dieselbe Farbe haben.

Ich habe vergessen, ein Bild zu posten, also habe ich hier ein paar gemacht und versehentlich den äußeren Rand abgeschnitten

Das obige ist der detaillierte Inhalt vonSo konvertieren Sie einen einfarbigen QR-Code in einen farbigen QR-Code (JavaScript). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn