ホームページ ウェブフロントエンド jsチュートリアル 単色の QR コードをカラーの QR コードに変換する方法 (JavaScript)

単色の QR コードをカラーの QR コードに変換する方法 (JavaScript)

Apr 28, 2017 am 10:21 AM

この記事では主にJavaScriptのソリッドカラーQRコードをカラーQRコードに変換する解決策を詳しく紹介しますので、興味のある方は参考にしてください

この記事では主にJavaScriptのQRコードをカラーQRコードに変換する方法について説明します。単色の QR コードが色付きになります。

少し前に、顧客は背景によって生成された単色の QR コードが気に入らず、色付きの QR コードを求めていました。そこで、このタスクは画像処理であるため、Canvas を使用してピクセル操作を実行することが主な目的でした。そのため、いくつかの試みを行いましたが、いくつかの落とし穴に遭遇しました。具体的な記録は次のとおりです。

前提知識

drawImageメソッドはキャンバス上に絵を描くことができ、getImageDataメソッドは長方形領域内のすべてのピクセルの情報を取得することができ、戻り値のdata属性はone-次元配列 には、すべてのピクセルの情報が格納されます。1 つのピクセルの情報は、それぞれ r、g、b、透明度を表す 4 つの要素を占めます。 1 次元配列内のピクセルの順序は、左から右、上から下です。最後は putImageData メソッドで、変更されたピクセル情報配列をキャンバスに返します。

いくつかの小さな落とし穴

1 つ目の落とし穴は、キャンバスが CSS を使用する代わりに属性を使用して幅と高さを指定することです

2 つ目の落とし穴は、画像処理にはサーバー環境が必要であるように見えることです。ローカルで可能だと聞きましたが、セキュリティ上の考慮事項に基づいて、ローカルサーバーをセットアップすることで最終的にキャンバスエラーを解決しました。

3番目のピットはスタックオーバーフローです。これについては、後で詳しく説明します

主なアイデアは「ああ!」から来ています。アルゴリズム! 「深さ優先検索と幅優先検索の章では、章の最後の部分「宝島の冒険」で、異なるエリアに順番に番号を付ける実装が行われています。番号は色分けのようなものだと考えられていますが、実際には同じです。

具体的な実装

実際、いわゆるカラーQRコードは、各ピクセルの色がランダムな種類のQRコードではありません。 QRコードをよく見てみると、海の中に点在する島のように、黒い部分が一つ一つ、白い部分の中に分布していることが分かります。個別にブロックします。黒ブロックの本質は黒ピクセルです。

前に述べたように、キャンバスはピクセル操作を実行できるので使用します。そのため、実際の操作は明らかに背景色を染めたくないため、前述したように背景色を判断する必要があります。背景色は、黒い色のブロックを区切る海のようなものです。つまり、ピクセルを読み込んで染色した後、その右側のピクセルの色を常に判断します。境界に到達したため、正しい方向の色付けを停止できますが、実際には各ピクセルに 4 つの方向が接続されています。ピクセルの右側が背景色である場合、これは深さ優先探索です。再帰により、現在のピクセルの次の位置の色が背景色であることを継続的に確認し、背景色でない場合は戻って別の方向を試し、染色したピクセルを 4 つ検証します。方向。

背景色かどうかを判断するには、RGBA 値を比較する必要があるため、もう 1 つはピクセル情報の配列です。したがって、正しいピクセル情報を比較する場合は、この部分も処理する必要があります。

少しわかりにくいかもしれません、コードを見てみましょう


パート1

、キャンバス

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

var img = new Image();
img.src = path; //这里的path就是图片的地址
ログイン後にコピー
パート2、

色処理

// 分离颜色参数  返回一个数组
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;
    }
  }
})();
ログイン後にコピー
パート3、

初期パラメータを与える

冗長な操作では、マーク配列を使用して判定された位置を記録します

// 参数
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; 
  } 
}
ログイン後にコピー

パート 4、

ピクセル情報を取得し、各ピクセルを走査し、最後にそれをキャンバスに戻します

マークされている場合はスキップします。マークされていない場合は、ランダムな色、深さ優先検索、および色付けを使用します

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);
}
ログイン後にコピー

キーコード

操作を簡素化するために方向配列を使用します。試行する方向は時計回りであることに同意しました。右から。

// 方向数组
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;
}
ログイン後にコピー

最後に遭遇した落とし穴は、長さと幅が220を超えるとスタックがオーバーフローするということですが、これより小さい場合は問題ありません。具体的な理由は不明です。そこに問題があり、無限ループが発生している可能性があります。

すべてのコードはここにあります

// 分离颜色参数  返回一个数组
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);
}
ログイン後にコピー

概要

少し長く感じますが、ほとんどの関数は実際にピクセル情報を処理します。これを実装するには、深さ優先検索を理解することが重要です。染色されたピクセルは自然にマークされるため、新しいマークされていないピクセルが表示されると、それは当然新しいカラー ブロックを意味します。細かいところでは、imgD.dataとピクセルシリアル番号の対応に気をつければ、あとは大丈夫です。ただし、ピクセルが非常に小さいため、肉眼ではバラバラに見える色のブロックがつながって同じ色に染まる場合があることに注意してください。

写真を投稿するのを忘れたので、QQ で撮ったものをいくつか載せておきます。うっかり外枠を切り取ってしまいました。まあ、見てみましょう

以上が単色の QR コードをカラーの QR コードに変換する方法 (JavaScript)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

wpsを使ってQRコードを作成する方法 wpsを使ってQRコードを作成する方法 Mar 28, 2024 am 09:41 AM

1. ソフトウェアを開き、wps テキスト操作インターフェイスに入ります。 2. このインターフェースで挿入オプションを見つけます。 3. [挿入] オプションをクリックし、編集ツール領域で [QR コード] オプションを見つけます。 4. [QR コード] オプションをクリックして、[QR コード] ダイアログ ボックスをポップアップ表示します。 5. 左側のテキスト オプションを選択し、テキスト ボックスに情報を入力します。 6. 右側で、QR コードの形状と QR コードの色を設定できます。

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

Enterprise WeChat の QR コードを読み込めない場合はどうすればよいですか? Enterprise WeChat の QR コードを読み込めない場合はどうすればよいですか? Mar 14, 2024 pm 10:46 PM

Enterprise WeChat の QR コードを読み込めない場合はどうすればよいですか? Enterprise WeChat のコンピューター版にログインするときに、QR コードが読み込めず、表示できない場合はどうすればよいですか? ここでは、Enterprise の QR コードが表示されない問題の解決策を編集者が詳しく紹介します。 WeChat をロードできません。必要な方はぜひお友達、見に来てください!方法 1. ネットワークの理由 1. ネットワーク速度が遅いため、読み込みが遅く表示されない可能性があります。切断して再接続できます。 2. コンピュータ自体のネットワークの問題を調べて、ネットワークに接続されているかどうかを確認し、ネットワーク デバイスを再起動します。方法 2: メンテナンスと更新: Enterprise WeChat のバージョンが低すぎるため、QR コードが生成されない可能性がありますが、ソフトウェアを最新バージョンにアップグレードできます。方法 3、ファイアウォール 1

See all articles