<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BLE Printer Test</title>
<script src="https://cdn.jsdelivr.net/npm/iconv-lite-umd@0.6.10/lib/iconv-lite-umd.js"></script>
</head>
<body>
<h1>BLE Printer Test 123</h1>
<button id="printTestButton">Test Print</button>
<button id="printAgain">Print Again</button>
<pre id="log"></pre>
<script>
// Function to log messages on the page
function logMessage(message) {
const logElement = document.getElementById('log');
logElement.textContent += message + '\n';
}
var device;
var server;
var service;
var characteristic;
var name = 'T58_6752'; // 藍芽設備的名稱
var uuid = 0x1800; //service UUID (用 BLE Scanner 找到的)
var characteristicUuid = 0x2A00; // characteristic UUID (用 BLE Scanner 找到的)
// Function to connect to BLE printer and send test data
async function connectAndTestPrint() {
try {
logMessage("Requesting Bluetooth device...");
// Request the BLE device
device = await navigator.bluetooth.requestDevice({
//acceptAllDevices: true,
filters: [
{ name: name }
],
optionalServices: [uuid] // Replace with the correct service UUID
});
logMessage(`Device selected: ${device.name}`);
logMessage(`Device uuid: ${device.id}`);
await printAgain();
} catch (error) {
logMessage(`Error: ${error.message}`);
}
}
// 转码方法
function stringToGbk(str) {
const ranges = [
[0xA1, 0xA9, 0xA1, 0xFE],
[0xB0, 0xF7, 0xA1, 0xFE],
[0x81, 0xA0, 0x40, 0xFE],
[0xAA, 0xFE, 0x40, 0xA0],
[0xA8, 0xA9, 0x40, 0xA0],
[0xAA, 0xAF, 0xA1, 0xFE],
[0xF8, 0xFE, 0xA1, 0xFE],
[0xA1, 0xA7, 0x40, 0xA0],
]
const codes = new Uint16Array(23940)
let i = 0
for (const [b1Begin, b1End, b2Begin, b2End] of ranges) {
for (let b2 = b2Begin; b2 <= b2End; b2++) {
if (b2 !== 0x7F) {
for (let b1 = b1Begin; b1 <= b1End; b1++) {
codes[i++] = b2 << 8 | b1
}
}
}
}
const cstr = new TextDecoder('gbk').decode(codes)
// 编码表
const table = new Uint16Array(65536)
for (let i = 0; i < cstr.length; i++) {
table[cstr.charCodeAt(i)] = codes[i]
}
const buf = new Uint8Array(str.length * 2)
let n = 0
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i)
if (code < 0x80) {
buf[n++] = code
} else {
const gbk = table[code]
buf[n++] = gbk & 0xFF
buf[n++] = gbk >> 8
}
}
u8buf = buf.subarray(0, n)
// console.log(u8buf);
return u8buf
}
async function printAgain() {
// Connect to the GATT server
server = await device.gatt.connect();
logMessage("Connected to GATT server.");
// Get the printer service
service = await server.getPrimaryService(uuid); // Replace with your printer's service UUID
logMessage("Printer service retrieved.");
// Get the characteristic for writing data
characteristic = await service.getCharacteristic(characteristicUuid); // Replace with the correct characteristic UUID
logMessage("Printer characteristic retrieved.");
// Prepare test print data
const encoder = new TextEncoder();
const testData = encoder.encode("TEST PRINT: Hello from Web Bluetooth!\n");
const finalData = encoder.encode("--\n--\n \n \n");
const setFontSize = new Uint8Array([0x1D, 0x21, 0x11]); // GS ! n
const setFontSize2 = new Uint8Array([0x1D, 0x21, 0x22]); // GS ! n
const setFontSize3 = new Uint8Array([0x1D, 0x21, 0x33]); // GS ! n
// Write test data to the printer
logMessage("Sending test data to printer...");
await characteristic.writeValue(new Uint8Array([0x1D, 0x21, 0x00]));
await characteristic.writeValue(encoder.encode("1x1!\n"));
await characteristic.writeValue(setFontSize);
await characteristic.writeValue(encoder.encode("2x2!\n"));
await characteristic.writeValue(setFontSize2);
await characteristic.writeValue(encoder.encode("3x3!\n"));
await characteristic.writeValue(setFontSize3);
await characteristic.writeValue(encoder.encode("4x4!\n"));
const initPrinter = new Uint8Array([0x1B, 0x40]); // ESC @
await characteristic.writeValue(initPrinter);
// 3. 設置字符集為 GBK
const setGBK = new Uint8Array([0x1B, 0x74, 0x11]); // ESC t 0x11 (GBK)
await characteristic.writeValue(setGBK);
const text = "繁體中文測試\n \n";
const encodedText = stringToGbk(text);
await characteristic.writeValue(encodedText);
logMessage("Test data sent successfully!");
// QrCode 列印
const qrData = "https://example.com"; // Your QR code data
const qrDataLength = qrData.length + 3;
const pL = qrDataLength & 0xFF; // Low byte
const pH = (qrDataLength >> 8) & 0xFF; // High byte
const commands = [
0x1B, 0x40, // Initialize printer
0x1D, 0x28, 0x6B, pL, pH, 0x31, 0x50, 0x30, ...new TextEncoder().encode(qrData), // Store data
0x1D, 0x28, 0x6B, 0x03, 0x00, 0x31, 0x51, 0x30 // Print QR code
];
const buffer = new Uint8Array(commands);
await characteristic.writeValue(buffer);
logMessage("QrCode sent successfully!");
await characteristic.writeValue(finalData);
logMessage("finalData sent successfully!");
// Disconnect the GATT server
server.disconnect();
logMessage("Disconnected from printer.");
}
// Bind the function to the button
document.getElementById('printTestButton').addEventListener('click', connectAndTestPrint);
document.getElementById('printAgain').addEventListener('click', printAgain);
</script>
</body>
</html>
/// <summary>
/// 取得授權的項目
/// </summary>
static string[] Scopes = { GmailService.Scope.GmailSend };
// 和登入 google 的帳號無關
// 任意值,若未來有使用者認証,可使用使用者編號或登入帳號。
string Username = "ABC";
/// <summary>
/// 存放 client_secret 和 credential 的地方
/// </summary>
string SecretPath = @"D:\project\GmailTest\Data\Secrets";
/// <summary>
/// 認証完成後回傳的網址, 必需和 OAuth 2.0 Client Id 中填寫的 "已授權的重新導向 URI" 相同。
/// </summary>
string RedirectUri = $"https://localhost:44340/Home/AuthReturn";
/// <summary>
/// 取得認証用的網址
/// </summary>
/// <returns></returns>
public async Task<string> GetAuthUrl()
{
using (var stream = new FileStream(Path.Combine(SecretPath, "client_secret.json"), FileMode.Open, FileAccess.Read))
{
FileDataStore dataStore = null;
var credentialRoot = Path.Combine(SecretPath, "Credentials");
if (!Directory.Exists(credentialRoot))
{
Directory.CreateDirectory(credentialRoot);
}
//存放 credential 的地方,每個 username 會建立一個目錄。
string filePath = Path.Combine(credentialRoot, Username);
dataStore = new FileDataStore(filePath);
IAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = GoogleClientSecrets.Load(stream).Secrets,
Scopes = Scopes,
DataStore = dataStore
});
var authResult = await new AuthorizationCodeWebApp(flow, RedirectUri, Username)
.AuthorizeAsync(Username, CancellationToken.None);
return authResult.RedirectUri;
}
}
public async Task<string> AuthReturn(AuthorizationCodeResponseUrl authorizationCode)
{
string[] scopes = new[] { GmailService.Scope.GmailSend };
using (var stream = new FileStream(Path.Combine(SecretPath, "client_secret.json"), FileMode.Open, FileAccess.Read))
{
//確認 credential 的目錄已建立.
var credentialRoot = Path.Combine(SecretPath, "Credentials");
if (!Directory.Exists(credentialRoot))
{
Directory.CreateDirectory(credentialRoot);
}
//暫存憑証用目錄
string tempPath = Path.Combine(credentialRoot, authorizationCode.State);
IAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = GoogleClientSecrets.Load(stream).Secrets,
Scopes = scopes,
DataStore = new FileDataStore(tempPath)
});
//這個動作應該是要把 code 換成 token
await flow.ExchangeCodeForTokenAsync(Username, authorizationCode.Code, RedirectUri, CancellationToken.None).ConfigureAwait(false);
if (!string.IsNullOrWhiteSpace(authorizationCode.State))
{
string newPath = Path.Combine(credentialRoot, Username);
if (tempPath.ToLower() != newPath.ToLower())
{
if (Directory.Exists(newPath))
Directory.Delete(newPath, true);
Directory.Move(tempPath, newPath);
}
}
return "OK";
}
}
public async Task<bool> SendTestMail()
{
var service = await GetGmailService();
GmailMessage message = new GmailMessage();
message.Subject = "標題";
message.Body = $"<h1>內容</h1>";
message.FromAddress = "bikehsu@gmail.com";
message.IsHtml = true;
message.ToRecipients = "bikehsu@gmail.com";
message.Attachments = new List<Attachment>();
string filePath = @"C:\Users\bike\Pictures\Vegetable_pumpkin.jpg"; //要附加的檔案
Attachment attachment1 = new Attachment(filePath);
message.Attachments.Add(attachment1);
SendEmail(message, service);
Console.WriteLine("OK");
return true;
}
async Task<GmailService> GetGmailService()
{
UserCredential credential = null;
var credentialRoot = Path.Combine(SecretPath, "Credentials");
if (!Directory.Exists(credentialRoot))
{
Directory.CreateDirectory(credentialRoot);
}
string filePath = Path.Combine(credentialRoot, Username);
using (var stream = new FileStream(Path.Combine(SecretPath, "client_secret.json"), FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
Username,
CancellationToken.None,
new FileDataStore(filePath));
}
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Send Mail",
});
return service;
}
public class GmailMessage
{
public string FromAddress { get; set; }
public string ToRecipients { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public bool IsHtml { get; set; }
public List<System.Net.Mail.Attachment> Attachments { get; set; }
}
public static void SendEmail(GmailMessage email, GmailService service)
{
var mailMessage = new System.Net.Mail.MailMessage();
mailMessage.From = new System.Net.Mail.MailAddress(email.FromAddress);
mailMessage.To.Add(email.ToRecipients);
mailMessage.ReplyToList.Add(email.FromAddress);
mailMessage.Subject = email.Subject;
mailMessage.Body = email.Body;
mailMessage.IsBodyHtml = email.IsHtml;
if (email.Attachments != null)
{
foreach (System.Net.Mail.Attachment attachment in email.Attachments)
{
mailMessage.Attachments.Add(attachment);
}
}
var mimeMessage = MimeKit.MimeMessage.CreateFromMailMessage(mailMessage);
var gmailMessage = new Google.Apis.Gmail.v1.Data.Message
{
Raw = Encode(mimeMessage)
};
Google.Apis.Gmail.v1.UsersResource.MessagesResource.SendRequest request = service.Users.Messages.Send(gmailMessage, "me");
request.Execute();
}
public static string Encode(MimeMessage mimeMessage)
{
using (MemoryStream ms = new MemoryStream())
{
mimeMessage.WriteTo(ms);
return Convert.ToBase64String(ms.GetBuffer())
.TrimEnd('=')
.Replace('+', '-')
.Replace('/', '_');
}
}
<script>
var thisPage = {
Init: function () {
thisPage.InitPageInput();
$("body")
;
thisPage.ChangeEvent();
},
ParameterByName: function (targetKey) {
var res = null;
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
for (const [key, value] of Object.entries(params)) {
if (targetKey.trim().toLocaleLowerCase() === key) {
res = value;
}
}
return res;
},
OriUrl: function () {
var arrayUrl = [];
arrayUrl.push(window.location.protocol);//https:
arrayUrl.push("//");
arrayUrl.push(window.location.hostname);//blog.uwinfo.com.tw
if (window.location.port.length > 0) {
//大多情況,不用特別指定port
arrayUrl.push(":");
arrayUrl.push(window.location.port);//80
}
arrayUrl.push(window.location.pathname);//post/Edit.aspx
//換一套寫法
//arrayUrl.push(window.location.search);//?Id=321
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
var ayyarQueryString = [];
//這邊可以加工增加額外的key值
for (const [key, value] of Object.entries(params)) {
if (value.trim().length > 0) {
//這邊要注意中文需要encode
ayyarQueryString.push(key + "=" + encodeURIComponent(value));
}
}
if (ayyarQueryString.length > 0) {
arrayUrl.push("?");
arrayUrl.push(ayyarQueryString.join('&'));
}
return arrayUrl.length > 0 ? arrayUrl.join('') : '';
},
InitPageInput: function () {
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
for (const [key, value] of Object.entries(params)) {
$('input[name=' + key + ']').val(value);
//這邊因為input有多種不同輸入方式,可以自行編輯
//$('select[name=' + key + ']').val(value);
//$('textarea[name=' + key + ']').html(value);
}
},
ChangeEvent: function () {
},
}
$(function () {
thisPage.Init();
});
</script>
namespace WWW.Controllers
{
public class UploadController : Controller
{
// GET: Upload
public void Index(string Filename)
{
//Create a stream for the file
Stream stream = null;
//This controls how many bytes to read at a time and send to the client
int bytesToRead = 10000;
// Buffer to read bytes in chunk size specified above
byte[] buffer = new Byte[bytesToRead];
string url = "http://admin-dev.nanya.bike.idv.tw/newnanyaback/Upload/" + Filename;
// The number of bytes read
try
{
//Create a WebRequest to get the file
HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create(url);
//Create a response for this request
HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
//Get the Stream returned from the response
stream = fileResp.GetResponseStream();
// prepare the response to the client. resp is the client Response
var resp = HttpContext.Response;
if (Filename.ToLower().EndsWith(".png") ||
Filename.ToLower().EndsWith(".jpg") ||
Filename.ToLower().EndsWith(".jpeg") ||
Filename.ToLower().EndsWith(".gif")
)
{
resp.ContentType = "image";
}
else
{
//Indicate the type of data being sent
resp.ContentType = "application/octet-stream";
//Name the file
resp.AddHeader("Content-Disposition", "attachment; filename=\"" + HttpUtility.UrlEncode(Filename, Encoding.UTF8) + "\"");
}
resp.AddHeader("Content-Length", fileResp.ContentLength.ToString());
int length;
do
{
// Verify that the client is connected.
if (resp.IsClientConnected)
{
// Read data into the buffer.
length = stream.Read(buffer, 0, bytesToRead);
// and write it out to the response's output stream
resp.OutputStream.Write(buffer, 0, length);
// Flush the data
resp.Flush();
//Clear the buffer
buffer = new Byte[bytesToRead];
}
else
{
// cancel the download if client has disconnected
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
}
}
}
}
}
對於PC版大尺吋的螢幕,當網站要 feed 資料到 facebook 時,可以使用 javascript SDK 的
FB.ui => method:'feed' 方式處理,參考位置。此方法會popup小視窗讓user可以分享資料出去。
但是遇到手機版網頁就有點麻煩,實測上手機版的 chrome 會出現轉不停的情況,無法分享;而iPhone則是另開新頁面處理,可以成功但是會多一個分頁。所以手機版網頁建議使用 redirect 方式處理分享機制,參考位置
var fbUrl = "https://www.facebook.com/dialog/feed?" +
"app_id=122465741241119&display=touch" +
"&link=" + encodeURIComponent("http://www.shopunt.com/tch/FixPage.aspx?id=525") +
"&picture=" + encodeURIComponent("http://www.shopunt.com/tch/event/2014-nail-enrollment/fb_200x200.jpg") +
"&description=" + encodeURIComponent("市價不斐的光療DIY教學,UNT傾囊相授!10場巡迴免費教學,讓妳輕鬆掌握光療DIY訣竅,並搶先體驗秋冬最新流行色!現場打卡,再送時尚美甲工具組") +
"&redirect_uri=" + encodeURIComponent("http://www.shopunt.com/tch/event/2014-nail-enrollment/Handler.ashx?fun=FBCallback");
當然以 redirect 處理與 javascript 方式處理是兩種不同的方式,redirect 方式的 callback 網址 (redirect_uri)要接收facebook 導回的 post_id , javascript 方式則是 callback function 處理 post_id
<appSettings>
<add key="aspnet:MaxHttpCollectionKeys" value="5000" />
</appSettings>
Dim http As Net.HttpWebRequest = Net.WebRequest.Create(Url)
http.Method = "GET"
http.ContentType = "application/x-www-form-urlencoded;"
http.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Win64; x64; Trident/5.0)"
http.CookieContainer = New Net.CookieContainer
http.Referer = Url
Public Shared Funciont AA() as string
return xxxxx
End Function
public static string aa()
{
return xxxx
}
Public Shared Sub AA()
......
End Sub
public static void AA()
{
.....
}
Try
xxxxxx
Catch ex As Exception
UW.WU.WriteErrorToLog(ex)
End Try
try
{
xxxxxx
}
catch (Exception ex)
{
tran.Rollback();
}
char[] delimiterChars = { ',' };
foreach (string tags in cbTags.Split(delimiterChars))
{
}
select case AA
case "AA"
xxx
case "BB"
bbb
case else
aaaa
end select
switch (AA) {
case "AA":
xxx();
break;
case "BB":
bbb();
break;
default:
aaaa();
break;
}