Maison  >  Article  >  interface Web  >  Comment convertir un code QR de couleur unie en code QR coloré (JavaScript)

Comment convertir un code QR de couleur unie en code QR coloré (JavaScript)

零下一度
零下一度original
2017-04-28 10:21:483830parcourir

Cet article présente principalement en détail la solution consistant à transformer le code QR de couleur unie JavaScript en code QR couleur. Il a une certaine valeur de référence. Les amis intéressés peuvent s'y référer

Cet article présente principalement La discussion porte sur la façon dont. pour transformer un code QR de couleur unie en couleur.

Il y a quelque temps, il y avait une demande dans les activités de l'entreprise. Les clients n'aimaient pas les codes QR de couleur unie générés en arrière-plan. Ils voulaient des QR colorés. codes. Ensuite, cette tâche m'a incombé. Parce qu'il s'agissait de traitement d'image, l'idée principale était de s'appuyer sur Canvas pour effectuer des opérations sur les pixels, j'ai donc fait quelques tentatives et rencontré quelques pièges.

Connaissances préalables

drawImage permet de dessiner des images sur toile, getImageData Le peut obtenir les informations de tous les pixels dans une zone rectangulaire. L'attribut data de la valeur de retour est un tableau unidimensionnel, qui stocke les informations de tous les pixels. Les informations d'un pixel occuperont quatre éléments, représentant. respectivement r, g, b et transparence. L'ordre des pixels dans un tableau unidimensionnel est de gauche à droite et de haut en bas. La dernière est la méthode putImageData, qui renvoie le tableau d'informations de pixels modifié sur le canevas.

Quelques petits pièges

Le premier piège est que Canvas utilise des attributs pour donner la largeur et la hauteur, n'utilisez pas de CSS

Le deuxième piège Pièges, le traitement d'image semble nécessiter un environnement serveur, ce qui n'est pas possible localement. J'ai entendu dire que cela était basé sur certaines considérations de sécurité. En fin de compte, j'ai résolu l'erreur de canevas en configurant un serveur local.

Le troisième piège est le débordement de pile. La raison n'a pas encore été trouvée, j'en parlerai en détail plus tard

L'idée du changement de couleur.

L'idée principale vient de "Aha!" algorithme! "Dans les chapitres de recherche en profondeur et en largeur, la dernière partie du chapitre, "Treasure Island Adventure", implémente la numérotation de différentes zones dans l'ordre. Considérez les nombres comme une coloration, mais ils sont en réalité les mêmes.

Mise en œuvre spécifique

En fait, le code QR dit couleur n'est pas le genre de code QR où la couleur de chaque pixel est aléatoire. Si vous regardez attentivement le code QR, vous constaterez que les parties noires sont une pièce à la fois et qu'elles sont réparties parmi les blanches, tout comme les îles réparties dans la mer. Ce que nous devons faire est de teindre chaque pièce en noir. bloquer individuellement. L'essence d'un bloc noir est un pixel noir.

Comme mentionné précédemment, nous utilisons Canvas car il peut effectuer des opérations sur les pixels, donc notre opération consiste en fait à teindre les pixels. Nous ne voulons évidemment pas teindre la couleur d'arrière-plan, donc la couleur d'arrière-plan doit être jugée ; Avant, il a également été mentionné que la couleur d'arrière-plan est comme l'océan divisant les blocs de couleur noire. Cela signifie qu'après avoir lu un pixel et l'avoir teint, nous jugeons constamment la couleur des pixels sur le côté droit de celui-ci. apparaît, cela signifie que nous sommes arrivés. La frontière peut arrêter de teindre dans la bonne direction, mais chaque pixel a en fait quatre directions connectées. Lorsque le côté droit d'un pixel est la couleur d'arrière-plan, nous devrions également essayer la possibilité d'autres directions. est une recherche en profondeur d'abord. Par récursion, vérifiez constamment que la couleur de la position suivante du pixel actuel est la couleur d'arrière-plan, puis revenez et essayez une autre direction si ce n'est pas la couleur d'arrière-plan, puis colorez-la, puis effectuez ; quatre directions sur le pixel teint.

Quelques points à mentionner. Pour déterminer s'il s'agit d'une couleur d'arrière-plan, vous devez comparer la valeur rgba, donc les paramètres de couleur doivent être traités. L'autre est un tableau d'informations de pixels. Tous les quatre éléments représentent un. pixel Par conséquent, si vous souhaitez comparer les informations correctes sur les pixels, cette partie doit également être traitée.
Cela peut être un peu déroutant, jetons un œil à la première partie du code

, canvas

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

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

la deuxième partie , color Traitement de la troisième partie de

// 分离颜色参数  返回一个数组
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;
    }
  }
})();

, donne les paramètres initiaux

afin d'éviter les opérations redondantes, nous utilisons un tableau de marqueurs pour enregistrer le position jugée

// 参数
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; 
  } 
}

Partie 4, Obtenir les informations sur les pixels, parcourir chaque pixel et enfin le renvoyer sur la toile

S'il est marqué, ignorez-le, si non marqué Ensuite, randomisez une couleur, recherchez en profondeur d'abord et colorez

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);
}

Code clé

Nous utilisons un tableau de direction pour simplifier l'opération, nous sommes d'accord, la direction à essayer est dans le sens des aiguilles d’une montre, en commençant par la droite.

// 方向数组
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;
}

Le dernier piège que j'ai rencontré est que lorsque la longueur et la largeur sont supérieures à 220, la pile débordera, mais si elle est inférieure à cette valeur, il n'y aura pas de problème. pas clair. Je suppose que c'est peut-être le jugement. Il y a un problème, provoquant une boucle infinie.

Tous les codes ici

// 分离颜色参数  返回一个数组
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);
}

Résumé

Bien que cela semble un peu long, la plupart des fonctions traitent en réalité les informations sur les pixels. Pour l'implémenter, l'essentiel est de comprendre la recherche en profondeur d'abord. Chaque pixel est recherché en profondeur d'abord. Ceux qui sont teints sont naturellement marqués, donc lorsqu'un nouveau pixel non marqué apparaît, cela signifie naturellement de nouveaux blocs de couleur. En termes de détails, faites simplement attention à la correspondance entre imgD.data et les numéros de série des pixels, et tout le reste ira bien. Cependant, une chose à noter est que, comme les pixels sont très petits, les blocs de couleur qui semblent déconnectés à l'œil nu peuvent être connectés entre eux et teints de la même couleur.

J'ai oublié de publier une photo, alors en voici quelques-unes. J'ai pris une capture d'écran QQ et j'ai accidentellement coupé la bordure extérieure.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn