raspberry pi 5 調換左右螢幕
首先確定使用 X11 的配置
[terminal] echo $XDG_SESSION_TYPE
若顯示 X11 ,那就對了。若顯示為 wayland ,那就錯了。
若為 X11 則可用下面指令即時變更左右位置,
[terminal] xrandr --output HDMI-1 --left-of HDMI-2 (把 HDMI-1 搬到 HDMI-2 的左邊)
若要一開機就套用的話
[terminal] cd /etc/X11/Xsession.d/
[terminal] sudo geany 99-xrandr
新增下面兩行並儲存
#!/bin/bash
xrandr --output HDMI-2 --left-of HDMI-1
[terminal] sudo chmod +x 99-xrandr
[terminal] sudo reboot
從網路攝影機讀取QRCODE
執行看看
<!doctype html>
<html lang="zh-Hant-TW">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>QR Code Scanner From Webcam</title>
<style>
#myVideo
{
width: 300px;
height: 200px;
border: 1px solid black;
}
</style>
</head>
<body>
<div>引用 https://github.com/cozmo/jsQR/blob/master/dist/jsQR.js</div>
<div>純粹 JavaScript 解碼 QRCode</div>
<br>
<h1>QR Code Scanner with Webcam</h1>
<video id="myVideo" autoplay playsinline></video>
<p id="pResult">Waiting for QR Code...</p>
<textarea id="ta1" rows="20" cols="80"></textarea>
<!-- <script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js"></script> -->
<script src="jsQR.js"></script>
<script>
const oVideo = document.getElementById('myVideo');
const pResultElement = document.getElementById('pResult');
var strLastCode="";
// 獲取使用者的攝像頭
navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } })
.then(
function(oStream)
{
oVideo.srcObject = oStream;
oVideo.play();
window.requestAnimationFrame(processOneFrame);
})
.catch(
function(oErr)
{
console.error('Error accessing webcam: ', oErr);
});
function processOneFrame()
{
if(oVideo.readyState===oVideo.HAVE_ENOUGH_DATA)
{
// 建立 canvas 用於獲取影像數據
const oCanvas = document.createElement('canvas');
const oCtx = oCanvas.getContext('2d');
oCanvas.width = oVideo.videoWidth;
oCanvas.height = oVideo.videoHeight;
oCtx.drawImage(oVideo, 0, 0, oCanvas.width, oCanvas.height);
// 從 oCanvas 中獲取影像數據
const oImageData = oCtx.getImageData(0, 0, oCanvas.width, oCanvas.height);
const oCode = jsQR(oImageData.data, oCanvas.width, oCanvas.height);
if(oCode)
{
pResultElement.textContent = 'QR Code 內容: ' + oCode.data;
pResultElement.style.color = 'green';
if(oCode.data!=strLastCode)
{
strLastCode=oCode.data;
document.getElementById("ta1").value
=oCode.data+"\r\n"
+document.getElementById("ta1").value;
}
}
else
{
pResultElement.textContent = 'No QR Code detected.';
pResultElement.style.color = 'red';
}
}
// 繼續下一幀的掃描
window.requestAnimationFrame(processOneFrame);
}
</script>
</body>
</html>
從檔案讀取QRCODE
執行看看
<!doctype html>
<html lang="zh-Hant-TW">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>QR Code Scanner From File</title>
</head>
<body>
<div>引用 https://github.com/cozmo/jsQR/blob/master/dist/jsQR.js</div>
<div>純粹 JavaScript 解碼 QRCode</div>
<br>
<input type="file" id="inpFile" accept="image/*">
<canvas id="myCanvas" style="display: none;"></canvas>
<p id="pResult">QR Code 內容將顯示在此處</p>
<!-- <script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js"></script> -->
<script src="jsQR.js"></script>
<script>
document.getElementById('inpFile').addEventListener(
'change',
function(oEvent1)
{
const oFile = oEvent1.target.files[0];
const oFileReader = new FileReader();
oFileReader.onload =
function(oEvent2)
{
const oImg = new Image();
oImg.src = oEvent2.target.result;
oImg.onload =
function()
{
const oCanvas = document.getElementById('myCanvas');
const oCtx = oCanvas.getContext('2d');
oCanvas.width = oImg.width;
oCanvas.height = oImg.height;
oCtx.drawImage(oImg, 0, 0, oImg.width, oImg.height);
const oImageData = oCtx.getImageData(0, 0, oCanvas.width, oCanvas.height);
const oCode = jsQR(oImageData.data, oCanvas.width, oCanvas.height);
if(oCode)
{
document.getElementById('pResult').textContent = 'QR Code 內容: ' + oCode.data;
}
else
{
document.getElementById('pResult').textContent = '無法辨識 QR Code';
}
};
};
oFileReader.readAsDataURL(oFile);
}
);
</script>
</body>
</html>
html basic template 網頁基本樣板 part 04 - 最簡版本
語法驗證 https://validator.w3.org/
<!doctype html>
<html lang="zh-Hant-TW">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>your title</title>
<link rel="stylesheet" href="a.css">
</head>
<body>
</body>
</html>
資料庫常用類別設計 MSSQL,MicrosoftSQLServer,PHP,sqlsrv or odbc
<?php
{ // 範例
//
// 範例 insUpdDel
//
// $oMSSQL=new CMSSQL_v3_sqlsrv(); 或 $oMSSQL=new CMSSQL_v3_odbc();
// $oStatement=$oMSSQL->insUpdDel('default', "insert into tb1(nc1) values('用JSON測試。')");
//
// echo '------html------<br>';
// echo 'booInsUpdDel:' . ($oStatement->booInsUpdDel ? 'true' : 'false') . '<br>';
// echo 'booSuccess:' . ($oStatement->booSuccess ? 'true' : 'false') . '<br>';
// echo 'strErrorMessage:' . htmlspecialchars($oStatement->strErrorMessage) . '<br>';
// echo 'iAffectedRows:' . $oStatement->iAffectedRows . '<br>';
//
// echo '------json------<br>';
// echo json_encode($oStatement, JSON_UNESCAPED_UNICODE);
//
//
// 範例 bigQuery
//
// $oMSSQL=new CMSSQL_v3_sqlsrv(); 或 $oMSSQL=new CMSSQL_v3_odbc();
// $oStatement=$oMSSQL->bigQuery('default', "select 1 as x,* from tb1");
//
// echo '------html------<br>';
// echo 'booInsUpdDel:' . ($oStatement->booInsUpdDel ? 'true' : 'false') . '<br>';
// echo 'booSuccess:' . ($oStatement->booSuccess ? 'true' : 'false') . '<br>';
// echo 'strErrorMessage:' . htmlspecialchars($oStatement->strErrorMessage) . '<br>';
// echo 'iResultAmount:' . $oStatement->iResultAmount . '<br>';
// echo 'oaUnitResult:' . htmlspecialchars(json_encode($oStatement->oaUnitResult, JSON_UNESCAPED_UNICODE)) . '<br>';
//
// echo '------json------<br>';
// echo json_encode($oStatement, JSON_UNESCAPED_UNICODE);
//
}
{ // [customvalue]
// [customvalue] for sqlsrv
$aryConn_db1_20240920153500=array('ServerName'=>'192.168.0.99,1433', 'ConnInfo'=>['Database'=>'db1', 'UID'=>'username', 'PWD'=>'password', 'CharacterSet'=>'UTF-8', 'LoginTimeout'=>180]);
$aryConn_db2_20240920153600=array('ServerName'=>'192.168.0.88,1433', 'ConnInfo'=>['Database'=>'db2', 'UID'=>'username', 'PWD'=>'password', 'CharacterSet'=>'UTF-8', 'LoginTimeout'=>180]);
// [customevalue] for odbc
$aryConn_db1_20240923110600=array('dsn'=>'Driver={FreeTDS};Server=192.168.0.99;Port=1433;Database=db1;ClientCharset=UTF-8;TDS_Version=7.4;', 'uid'=>'username', 'pwd'=>'password');
$aryConn_db2_20240924100600=array('dsn'=>'Driver={FreeTDS};Server=192.168.0.88;Port=1433;Database=db2;ClientCharset=UTF-8;TDS_Version=7.4;', 'uid'=>'username', 'pwd'=>'password');
}
class CSQLUnitResult_v3
{
public $straFieldName=array();
public $booaTextType=array();
public $iRows=0;
public $iCols=0;
public $aryRawData=array();
public function getVal($iRow, $strFieldName)
{
$iCol=array_search($strFieldName, $this->straFieldName);
if($iCol===false) { return 'field name not found!'; }
if($iRow>=$this->iRows) { return 'row index out of range!'; }
return $this->aryRawData[$iRow][$iCol];
}
}
class CSQLStatement_v3
{
public $booInsUpdDel=false; // 增修刪=true, 大查詢=false
public $booSuccess=false;
public $strErrorMessage='';
// 增修刪↓
public $iAffectedRows=0;
// 大查詢↓
public $iResultAmount=0;
public $oaUnitResult=array(); // 裝載 CSQLUnitResult_v3 的陣列,用 array_push()
}
class CMSSQL_v3_sqlsrv
{
private function getAryConnection($strWho)
{
global $aryConn_db1_20240920153500, $aryConn_db2_20240920153600;
if($strWho=='db2') { return $aryConn_db2_20240920153600; }
else { return $aryConn_db1_20240920153500; }
}
// 參數正規化,避免 SQL Injection
public function getStrNum($value) { return strval(floatval($value)); }
public function getStrNormalizedString($value) { return str_replace("'","''",$value); }
public function getStrAnsiTxt($value) { return "'" . $this->getStrNormalizedString($value) . "'"; }
public function getStrUniTxt($value) { return "N'" . $this->getStrNormalizedString($value) . "'"; }
public function getStrAnsiLikeTxt($value) { return "'" . '%' . $this->getStrNormalizedString($value) . '%' . "'"; }
public function getStrUniLikeTxt($value) { return "N'" . '%' . $this->getStrNormalizedString($value) . '%' . "'"; }
public function getStrFreeText($value) { return $value; }
public function insUpdDel($strWho, $strSQL, $iQueryTimeout=600)
{
$oStatement=new CSQLStatement_v3();
$oStatement->booInsUpdDel=true;
while(true)
{
// 連線到資料庫
$aryConn=$this->getAryConnection($strWho);
$oConn=sqlsrv_connect($aryConn['ServerName'], $aryConn['ConnInfo']);
if($oConn==false)
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage='資料庫連線失敗!ErrMsg:' . print_r(sqlsrv_errors(),true);
break;
}
while(true)
{
// 執行 SQL 指令劇本
$oStmt=sqlsrv_query($oConn, $strSQL, NULL, array('QueryTimeout'=>$iQueryTimeout));
if($oStmt===false)
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage='資料庫異動失敗!ErrMsg:' . print_r(sqlsrv_errors(),true);
break;
}
// 取得資訊
$oStatement->booSuccess=true;
$oStatement->iAffectedRows=sqlsrv_rows_affected($oStmt);
// 釋放資源
sqlsrv_free_stmt($oStmt);
break;
}
// 釋放連線
sqlsrv_close($oConn);
break;
}
return $oStatement;
}
public function bigQuery($strWho, $strSQL, $iQueryTimeout=600)
{
$oStatement=new CSQLStatement_v3();
$oStatement->booInsUpdDel=false;
while(true)
{
// 連線到資料庫
$aryConn=$this->getAryConnection($strWho);
$oConn=sqlsrv_connect($aryConn['ServerName'], $aryConn['ConnInfo']);
if($oConn==false)
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage='資料庫連線失敗!ErrMsg:' . print_r(sqlsrv_errors(),true);
break;
}
while(true)
{
// 執行 SQL 指令劇本
$oStmt=sqlsrv_query($oConn, $strSQL, NULL, array('QueryTimeout'=>$iQueryTimeout));
if($oStmt===false)
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage='資料庫查詢失敗!ErrMsg:' . print_r(sqlsrv_errors(),true);
break;
}
// 逐個結果集檢視
$oStatement->booSuccess=true;
while(true)
{
// 新增一個單元
$oStatement->iResultAmount++;
$oUnit=new CSQLUnitResult_v3();
$oUnit->iCols=sqlsrv_num_fields($oStmt);
$aryMetaData=sqlsrv_field_metadata($oStmt);
for($i=0; $i<$oUnit->iCols; $i++)
{
$oUnit->straFieldName[]=$aryMetaData[$i]['Name'];
$oUnit->booaTextType[]=in_array($aryMetaData[$i]['Type'], array(-10,-9,-8,-1,1,12));
}
while($oStatementow=sqlsrv_fetch_array($oStmt, SQLSRV_FETCH_NUMERIC))
{
$oUnit->iRows++;
$oUnit->aryRawData[]=$oStatementow;
}
$oStatement->oaUnitResult[]=$oUnit;
$oNextResult=sqlsrv_next_result($oStmt);
if($oNextResult===null) { break; } // 沒有資料集了。
if($oNextResult===false) // 發生錯誤!
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage=$oStatement->strErrorMessage . '。資料庫查詢意外!ErrMsg:' . print_r(sqlsrv_errors(),true);
break;
// 2015-08-18
// 實務經驗,有錯誤發生之後,後面的結果記錄集通通都消失,不會回饋!
// 所以有可能會漏掉錯誤結果集之後的成功結果集喔!
//
// 2023-02-09
// 因此,最好的實作就是在劇本中用(transaction),有任何問題,全部復原(rollback)!
}
}
// 釋放資源
sqlsrv_free_stmt($oStmt);
break;
}
// 釋放連線
sqlsrv_close($oConn);
break;
}
return $oStatement;
}
}
class CMSSQL_v3_odbc
{
private function getAryConnection($strWho)
{
global $aryConn_db1_20240923110600, $aryConn_db2_20240924100600;
if($strWho=='db2') { return $aryConn_db2_20240924100600; }
else { return $aryConn_db1_20240923110600; }
}
// 參數正規化,避免 SQL Injection
public function getStrNum($value) { return strval(floatval($value)); }
public function getStrNormalizedString($value) { return str_replace("'","''",$value); }
public function getStrAnsiTxt($value) { return "'" . $this->getStrNormalizedString($value) . "'"; }
public function getStrUniTxt($value) { return "N'" . $this->getStrNormalizedString($value) . "'"; }
public function getStrAnsiLikeTxt($value) { return "'" . '%' . $this->getStrNormalizedString($value) . '%' . "'"; }
public function getStrUniLikeTxt($value) { return "N'" . '%' . $this->getStrNormalizedString($value) . '%' . "'"; }
public function getStrFreeText($value) { return $value; }
public function insUpdDel($strWho, $strSQL)
{
$oStatement=new CSQLStatement_v3();
$oStatement->booInsUpdDel=true;
while(true)
{
// 連線到資料庫
$aryConn=$this->getAryConnection($strWho);
$oConn=odbc_connect($aryConn['dsn'], $aryConn['uid'], $aryConn['pwd']);
if($oConn==false)
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage='資料庫連線失敗!';
break;
}
while(true)
{
// 執行 SQL 指令劇本
$oStmt=odbc_exec($oConn, $strSQL);
if($oStmt===false)
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage='資料庫異動失敗!ErrMsg:' . odbc_errormsg($oConn);
break;
}
// 取得資訊
$oStatement->booSuccess=true;
$oStatement->iAffectedRows=odbc_num_rows($oStmt);
// 釋放資源
odbc_free_result($oStmt);
break;
}
// 釋放連線
odbc_close($oConn);
break;
}
return $oStatement;
}
public function bigQuery($strWho, $strSQL)
{
// 注意,語法中只能有一個 go 指令。
//
// 注意,若你的語法有三個 select,但若只有兩個有傳回資料,則只會出現兩個結果集!!!
// odbc 這個行為跟 sqlsrv 的行為,完全不同,千萬要留意!
$oStatement=new CSQLStatement_v3();
$oStatement->booInsUpdDel=false;
while(true)
{
// 連線到資料庫
$aryConn=$this->getAryConnection($strWho);
$oConn=odbc_connect($aryConn['dsn'], $aryConn['uid'], $aryConn['pwd']);
if($oConn==false)
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage='資料庫連線失敗!';
break;
}
while(true)
{
// 執行 SQL 指令劇本
$oStmt=odbc_exec($oConn, $strSQL);
if($oStmt===false)
{
$oStatement->booSuccess=false;
$oStatement->strErrorMessage='資料庫查詢失敗!ErrMsg:' . odbc_errormsg($oConn);
break;
}
// 逐個結果集檢視
$oStatement->booSuccess=true;
while(true)
{
// 新增一個單元
$oStatement->iResultAmount++;
$oUnit=new CSQLUnitResult_v3();
$oUnit->iCols=odbc_num_fields($oStmt);
for($i=0; $i<$oUnit->iCols; $i++)
{
$oUnit->straFieldName[]=odbc_field_name($oStmt, $i+1);
$oUnit->booaTextType[]=in_array(odbc_field_type($oStmt, $i+1), array('text','ntext','char','nchar','varchar','nvarchar'));
}
$aryBuffer=array();
while($booSuccess=odbc_fetch_into($oStmt, $aryBuffer))
{
$oUnit->iRows++;
$oUnit->aryRawData[]=$aryBuffer;
}
$oStatement->oaUnitResult[]=$oUnit;
$oNextResult=odbc_next_result($oStmt);
if($oNextResult===false) { break; }
}
// 釋放資源
odbc_free_result($oStmt);
break;
}
// 釋放連線
odbc_close($oConn);
break;
}
return $oStatement;
}
}
?>