头像

小小蒟蒻




离线:7小时前



小小蒟蒻
8小时前
openCV4+MFC(vs2019)环境搭建
a) 新建MFC程序
b) 配置vs2019工程属性
     1) vc++目录 -> 包含目录 添加:
        D:\Program Files\opencv\build\include
        D:\Program Files\opencv\build\include\opencv2
     2) vc++目录 -> 库目录 添加
        D:\Program Files\opencv\build\x64\vc15\bin
     3) 链接器 -> 常规 -> 附加库目录
        D:\Program Files\opencv\build\x64\vc15\lib
        链接器 -> 输入-> 附加依赖项 
        opencv_world440d.lib(debug版本) 或者 opencv_world440.lib(release版本) 
     4) 找到安装目录\opencv\build\x64\vc15\bin目录下,以下的dll文件复制到 C:\Windows\System32 系统目录
        open_videoio_ffmpeg440_64.dll
        opencv_world440.dll
        opencv_world440d.dll


分享 备忘

#pragma once
#define NULL  0 
#include <stdio.h>
#include <stdlib.h>

typedef int type;

struct node {
    node* next;
    type data;
};

static node* h;
static int n;

node* head();

int size();

void ins_node(node* curr, node* succ);

void del_node(node* curr);

node* tail();

node* before_tail();

node* create_node(type data);

void insert(type data, int nInsHead = 1);

void remove(type data, int nDelSame = 1);

void find(type data, int nFindMulti = 1);

void remove_all_form_head();

void remove_all_from_tail();

void remove_all(int nDelFromHead = 1);

// list.cpp
#include "list.h"

node* head() {
    return h;
}

int size() {
    return n;
}

void ins_node(node* curr, node* succ) {
    if (!curr) {
        succ->next = h;
        h = succ;
    }
    else {
        succ->next = curr->next;
        curr->next = succ;
    }
    n++;
}

void del_node(node* curr) {
    if (!head()) return;
    node* succ = NULL;
    if (!curr) {
        succ = h;
        h = h->next;
    }
    else {
        if (!(succ = curr->next)) return;
        curr->next = succ->next;
    }
    free(succ);
    n--;
}

node* tail() {
    node* tail = NULL;
    for (tail = head(); tail && tail->next; tail = tail->next);
    return tail;
}

node* before_tail() {
    node* before = NULL;
    for (before = head(); before && before->next && before->next->next; before = before->next);
    return before;
}

node* create_node(type data) {
    node* succ = (node*)malloc(sizeof(node));
    if (!succ) return NULL;
    succ->next = NULL;
    succ->data = data;
    return succ;
}

void insert(type data, int nInsHead) {
    node* succ = create_node(data);
    if (!succ) return;
    nInsHead ? ins_node(NULL, succ) : ins_node(tail(), succ);
}

void remove(type data, int nDelSame) {
    if (!head()) return;
    for (node* curr = head(); curr->next; curr = curr->next) {
        while (curr->data == data || curr->next->data == data) {
            if (curr->data == data) {
                del_node(NULL);
                if (!nDelSame || !(curr == head())) return;
            }
            else if (curr->next->data == data) {
                del_node(curr);
                if (!nDelSame || !curr->next) return;
            }
        }
    }
}

void find(type data, int nFindMulti) {
    int cnt = 0;
    for (node* curr = head(); curr; curr = curr->next) {
        if (curr->data == data) {
            cnt++;
            if (!nFindMulti) return;
            printf("data = [%2d] in list and node address = [%p]\n", curr->data, curr);
        }
    }
    printf("find [%d]'s data = [%d]\n", cnt, data);
}

void modify(type found, type data, int nModifyMulti) {
    int cnt = 0;
    for (node* curr = head(); curr; curr = curr->next) {
        if (curr->data == found) {
            cnt++;
            curr->data = data;
            if (!nModifyMulti) return;
        }
    }
    printf("modified [%d]'s datas\n", cnt);
}

void remove_all_form_head() {
    while (size()) del_node(NULL);
    n = 0, h = NULL;
}

void remove_all_from_tail() {
    while (size()) {
        node* p = before_tail();
        if (!p) return;
        del_node(p);
    }
    n = 0, h = NULL;
}

void remove_all(int nDelFromHead) {
    nDelFromHead ? remove_all_form_head() : remove_all_from_tail();
}

#pragma once
#include <stdio.h>
#include <stdlib.h>
#define nil 0

typedef int type;

struct node {
    node* proir;
    node* next;
    type data;
};

node* head();

node* tail();

int size();

void insert(type data, int nInsHead = 1);

void remove(type data, int nDelSame = 1);

void remove_all();

void del_succ(node* curr);

// Dlist.cpp
#include "dlist.h"

static node *h, *t;
static int n;

node* head() { return h; }

node* tail() { return t; }

int size() { return n; }

int empty() { return !n; }

void ins_node(node* curr, node* succ) { // 插入时显然后继节点一定不为空
    if (!curr) {                        // 但是前驱节点有可能是空的
        succ->next = h;
        head() == nil ? 
            h = t = succ : h->proir = succ, h = succ;
    }
    else if (!curr->next) {
        curr->next = succ;
        succ->proir = curr;
        succ->next = nil;
        t = succ;
    }
    else {
        succ->next = curr->next;
        curr->next->proir = succ;
        succ->proir = curr;
        curr->next = succ;
    }
    n++;
}

void del_succ(node* curr) {
    if (!head()) return;
    node* succ = NULL;
    if (!curr) {  // 前驱节点为空,删除表头节点
        succ = h;
        h = h->next;
        h ? h->proir = nil : h = t = nil, n = 0;

    }
    else {  // 否者删除非表头得节点
        if (!(succ = curr->next)) return;  // 后继节点为空,退出
        curr->next = succ->next;           // 前驱的后继是后继的后继
        if (succ->next) succ->next->proir = curr; // 后继的后继为不为空,后继的后继的前驱是前驱节点
        else t = curr;    // 否则,后继就是尾节点,让尾指针指向前驱节点
    }
    if (succ) {     // 后继节点非空才做释放动作
        free(succ);
        n--;
    }
    else {   // 后继为空

        free(curr);
        n--;
        h = t = NULL;  
    }
}

void remove_all() {
    while(size()) {
        node* tmp = h;
        if (h) {
            h = h->next;
            free(tmp);
            n--;
        }
    }
    if (!n) t = h = nil;
} 

node* create_node(type data) {
    node* succ = (node*)malloc(sizeof(node));
    if (!succ) return NULL;
    succ->next = NULL;
    succ->proir = NULL;
    succ->data = data;
    return succ;
}

void insert(type data, int nInsTail) {
    node* succ = create_node(data);
    if (!succ) return;
    !nInsTail ? ins_node(nil, succ) : ins_node(tail(), succ);
}

void remove(type data, int nDelSame) {
    if (!head()) return;
    bool flag = false;
    for (node* p = head(); p->next; p = p->next) {
        while (p->next->data == data) {
                del_succ(p);
                if (!p->next) {
                    flag = true;
                    break;
                }
        }
        if (flag) break;
    }

    for (node* p = head(); p; p = p->next) {
        while (p->data == data) {
                del_succ(NULL);
                p = head();
                if (!p) return;
        }
    }

}



void CAttachImShowDlg::Resize(const std::string strPath, Mat& dst)
{
    CRect rect;
    GetDlgItem(IDC_PIC)->GetClientRect(rect);
    int height = rect.bottom - rect.top;
    int width = rect.right - rect.left;

    Mat src = imread(strPath); //从路径名中读取图片
    resize(src, dst, Size{ width, height }, (0, 0), (0, 0), INTER_LINEAR);//重新调整图像大小
}

BOOL CAttachImShowDlg::AttachMfcWindow()
{
    Mat img;
    Resize("D:\\123.jpg", img);
    namedWindow("Resize");
    HWND hWnd = (HWND)cvGetWindowHandle("Resize");
    if (!hWnd) return FALSE;
    HWND hParent = ::GetParent(hWnd);
    if (!hParent) return FALSE;
    ::ShowWindow(hParent, SW_HIDE);
    ::SetParent(hWnd, GetDlgItem(IDC_PIC)->GetSafeHwnd());
    imshow("Resize", img);
    waitKey(1);
    return TRUE;
}
在OnInitDialog中调用


分享 Mat2Bitmap

        using namespace cv;

        int width, height;
        Mat image = imread("D:\\123.jpg");

        width = image.cols;
        height = image.rows;

        if (width % 4) width = (width + 3) / 4 * 4;

        Size winSize(width, height);
        Mat cvImgTmp(winSize, CV_8UC3);
        if (image.size() != winSize)
            resize(image, cvImgTmp, winSize);
        else
            cvImgTmp = image.clone();
        CRect rect;
        GetDlgItem(IDC_STATIC_IMAGE)->GetClientRect(&rect);

        BITMAPINFO bitmapInfo;
        BITMAPINFOHEADER* bmiHeader;

        bmiHeader = &bitmapInfo.bmiHeader;
        memset(bmiHeader,0, sizeof(BITMAPINFOHEADER));
        bmiHeader->biSize = sizeof(BITMAPINFOHEADER);
        bmiHeader->biWidth = width;
        bmiHeader->biHeight = -height;
        bmiHeader->biPlanes = 1;
        bmiHeader->biBitCount = 24;
        bmiHeader->biCompression = BI_RGB;
        bitmapInfo.bmiHeader.biSizeImage = width * height;
        bmiHeader->biXPelsPerMeter = 0;
        bmiHeader->biYPelsPerMeter = 0;
        bmiHeader->biClrUsed = 0;
        bmiHeader->biClrImportant = 0;

        auto pDC = GetDlgItem(IDC_STATIC_ORG)->GetDC();
        pDC->SetStretchBltMode(HALFTONE);
        StretchDIBits(pDC->GetSafeHdc()
            , 0, 0, std::min(rect.Width(), rect.Height()), std::min(rect.Width(), rect.Height())
            , 0, 0, cvImgTmp.cols, cvImgTmp.rows, cvImgTmp.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);



// mysingal.h
#ifndef MYSINGAL_H
#define MYSINGAL_H

#include <QObject>

class MySingal : public QObject
{
    Q_OBJECT
public:
    explicit MySingal(QObject *parent = nullptr) : QObject(parent) { }

signals:
    void TextSingal(int n);
public slots:
};

#endif // MYSINGAL_H

// myslot.h
#ifndef MYSLOT_H
#define MYSLOT_H

#include <QObject>

class MySlot : public QObject
{
    Q_OBJECT
public:
    explicit MySlot(QObject *parent = nullptr) : QObject(parent) { }

signals:

public slots:
};

#endif // MYSLOT_H

// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    bool bAttach = false;
private:
    QPushButton* CreateBtn(const QString& btnName, const QSize& sz);
    void Close(const QString& btnName, const QSize& sz);
    void Switch(const QString& btnName, const QSize& sz, int n);
};
#endif // MAINWINDOW_H

// mainwindow.cpp
#include "mainwindow.h"
#include <QPushButton>
#include "mysingal.h"
#include "myslot.h"
#include <QDebug>


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setFixedSize(600, 400);
    Close("关闭", { 50, 50 });
    Switch("输出", { 150, 50 }, 10);
}

MainWindow::~MainWindow()
{
}

QPushButton* MainWindow::CreateBtn(const QString &btnName, const QSize& sz)
{
    if(btnName.toUtf8().data() == nullptr) return nullptr;
    QPushButton* btn = new QPushButton(btnName, this);
    if(!btn) return nullptr;
    btn->move(sz.width(), sz.height());
    btn->show();
    return btn;
}

void MainWindow::Close(const QString& btnName, const QSize& sz)
{
    QPushButton* btn = CreateBtn(btnName, sz);
    connect(btn, &QPushButton::clicked, this, [this]() {
        qDebug() << "CLose my window\n";
        close();
    });
}

void MainWindow::Switch(const QString& btnName, const QSize& sz, int n)
{
    QPushButton* btn = CreateBtn(btnName, sz);
    MySingal* pSingal = new MySingal(this);
    if(!pSingal) return;
    // 将输出按钮与信号关联, 需要捕获this的成员bAttach, 信号对象的地址, 信号函数的参数, 无需传参
    connect(btn, &QPushButton::clicked, this, [this, pSingal, n] () mutable {
        if(!bAttach) // bAttach为false 按钮无需关联信号函数
        {
            qDebug() << "*************";
            qDebug() << "信号与槽断开连接";
            qDebug() << "*************";
        }
        else        // 否则, 发送信号
        {
            qDebug() << "*************";
            qDebug() << "信号发送有参信号";
            emit pSingal->TextSingal(n);
        }
        bAttach = !bAttach; // 反转关联变量的值
    });
    MySlot* mySlot = new MySlot(this);
    if(!mySlot) return;
    // 关联信号与槽, 只需传递参数
    connect(pSingal, &MySingal::TextSingal, mySlot, [] (int n) mutable {
        qDebug() << "槽函数接收到有参信号: " << n;
        qDebug() << "*************";
    });
}

// main.cpp
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}



MemoryDC.png

#ifndef __MEMORYDC_H__
#define __MEMORYDC_H__

class CMemoryDC : public CDC
{
public:
    CMemoryDC() { }
    CMemoryDC(int cx, int cy, CDC* pDC = nullptr);
    CMemoryDC(int nID, CDC* pDC = nullptr);
    CMemoryDC(LPCTSTR szBitmapFile, CDC* pDC = nullptr);
    ~CMemoryDC();
public:
    inline int GetWidth() const { return m_size.cx; }
    inline int GetHeight() const { return m_size.cy; }
public:
    BOOL DeleteDC();
    BOOL CreateBitmap(int cx, int cy, CDC* pDC = nullptr);
    BOOL LoadBitmap(LPCTSTR szBitmapFile, CDC* pDC = nullptr);
    BOOL LoadBitmap(int nID, CDC* pDC = nullptr);
    void MakeRgn(CRgn& rgn, COLORREF clTrans);
    void BitTrans(int nXDest, int nYDest, int nWidthDest, int nHeightDest, CDC* pDestDC, int nXSrc, int nYSrc, COLORREF clTrans);
    void StretchTrans(int nXDest, int nYDest, int nWidthDest, int nHeightDest, CDC* pDestDC, int nXSrc, int nYSrc, int nWidthSrc, 
        int nHeightSrc, COLORREF clTrans);
private:
    CSize m_size;
};

#endif // __MEMORYDC_H__

#include "MemoryDC.h"

#include "MemoryDC.h"

CMemoryDC::CMemoryDC(int cx, int cy, CDC* pDC)
{
    CreateBitmap(cx, cy, pDC);
}

CMemoryDC::CMemoryDC(int nID, CDC* pDC)
{
    LoadBitmap(nID, pDC);
}

CMemoryDC::CMemoryDC(LPCTSTR szBitmapFile, CDC* pDC)
{
    LoadBitmap(szBitmapFile, pDC);
}

CMemoryDC::~CMemoryDC()
{
    DeleteDC();
}

BOOL CMemoryDC::DeleteDC()
{
    if (!GetSafeHdc()) return TRUE;
    CBitmap* pBitmap = GetCurrentBitmap();
    pBitmap->DeleteObject();
    return CDC::DeleteDC();
}

BOOL CMemoryDC::CreateBitmap(int cx, int cy, CDC* pDC)
{
    CClientDC dc(nullptr);
    if (!pDC) pDC = &dc;

    CBitmap bmp;
    if (!bmp.CreateCompatibleBitmap(pDC, cx, cy))
        return FALSE;

    if (!GetSafeHdc() && !pDC->CreateCompatibleDC(pDC))
        return FALSE;

    SelectObject(&bmp);
    m_size = { cx, cy };
    return TRUE;
}

BOOL CMemoryDC::LoadBitmap(int nID, CDC* pDC)
{
    CBitmap bmp;
    if (!bmp.LoadBitmap(nID))
        return FALSE;

    if (!GetSafeHdc() && !pDC->CreateCompatibleDC(pDC))
        return FALSE;
    BITMAP bm;
    bmp.GetBitmap(&bm);
    m_size = { bm.bmWidth, bm.bmHeight };
    return TRUE;
}

void CMemoryDC::MakeRgn(CRgn& rgn, COLORREF clTrans)
{
    rgn.DeleteObject();
    rgn.CreateRectRgn(0, 0, 0, 0); // 在窗口(0, 0)出创建一个面积为0的区域
    int i = GetWidth(); // 获取PaintDC的宽度
    while (i-- > 0)
    {
        int j = GetHeight(); // 获取PaintDC的高度
        while (j-- > 0)
        {   // PaintDC上像素颜色与将要转化为透明区域的颜色一致, 到下一处像素点比较颜色
            if (GetPixel(i, j) == clTrans) continue; 
            CRgn r;
            r.CreateRectRgn(i, j, i + 1, j + 1); // 建立一个像素点大小的区域
            r.CombineRgn(&r, &rgn, RGN_OR);      // 将该像素点并入区域r
        }
    }
}

BOOL CMemoryDC::LoadBitmap(LPCTSTR szBitmapFile, CDC* pDC)
{
    CClientDC dc(nullptr);
    if (!pDC) pDC = &dc;

    if (!szBitmapFile) return FALSE;

    HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, szBitmapFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    if (!hBitmap) return FALSE;
    BITMAP bm;
    GetObject(hBitmap, sizeof(bm), &bm);
    CreateCompatibleDC(pDC);
    SelectObject(hBitmap);
    DeleteObject(hBitmap);
    m_size = { bm.bmWidth, bm.bmHeight };
    return TRUE;
}

void CMemoryDC::BitTrans(int nXDest, int nYDest, int nWidthDest, int nHeightDest, CDC* pDestDC, int nXSrc, int nYSrc, COLORREF clTrans)
{
    // 产生前景图的兼容DC 前景图紫色背景彩色图形
    CMemoryDC dcFrontImage(nWidthDest, nHeightDest, pDestDC);
    dcFrontImage.SetBkColor(clTrans);
    dcFrontImage.BitBlt(0, 0, nWidthDest, nHeightDest, this, nXSrc, nYSrc, SRCCOPY);

    // 产生前景掩码图的兼容DC  掩码图 (要消去的区域为白色, 要留下的区域为黑色)
    CBitmap bmpMask;
    bmpMask.CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 构造单色掩码图(像素点非黑即白)
    CDC dcMask;
    dcMask.CreateCompatibleDC(pDestDC);
    dcMask.SelectObject(&bmpMask);
    dcMask.BitBlt(0, 0, nWidthDest, nHeightDest, &dcFrontImage, nXSrc, nYSrc, SRCCOPY);

    // 指定前景图的背景颜色与前景颜色
    dcFrontImage.SetBkColor(RGB(0, 0, 0));         // 前景图要消去的区域设置黑色 0x000000
    dcFrontImage.SetTextColor(RGB(255, 255, 255)); // 前景图要保留的区域设置白色 0xFFFFFF
    // 掩码图同前景图做与运算 
    // 掩码图白色区域与前景图要消去的黑色区域 0xFFFFFF & 0x000000 = 0 黑白抵消, 前景图要消去的区域变为黑色  
    // 掩码图黑色区域与前景图要保留的偏白区域 0x000000 & 0xFFFFFF = 0 黑白抵消, 前景图要保留的彩色区域恢复原色
    dcFrontImage.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMask, nXSrc, nYSrc, SRCAND); // 前景图黑色背景彩色图形

    // 掩码图同背景图做与运算 背景图被前景图覆盖的区域,每个像素的颜色为0xXXXXXX
    // 掩码图的白色区域与背景图 0xFFFFFF & 0xXXXXXX = 0xXXXXXX, 白色区域消去, 被白色遮罩的背景显露出来
    // 掩码图的黑色区域与背景图 0x000000 & 0xXXXXXX = 0x000000, 黑色区域保留, 背景的一部分被黑色遮罩住 
    pDestDC->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcMask, nXSrc, nYSrc, SRCAND); // 背景图被掩码图黑色图形遮罩
    // 前景图要消去的区域为黑色, 背景图对应的区域为任意颜色 0x000000 | 0xXXXXXX = 0xXXXXXX 保留对应区域的背景颜色
    // 前景图要保留的区域为彩色, 背景图对应的区域为黑色     0xXXXXXX | 0x000000 = 0xXXXXXX 保留对应区域的前景颜色
    pDestDC->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcFrontImage, nXSrc, nYSrc, SRCPAINT); // 背景图被前景图的彩色图形遮罩
}

void CMemoryDC::StretchTrans(int nXDest, int nYDest, int nWidthDest, int nHeightDest, CDC* pDestDC, int nXSrc, int nYSrc, 
    int nWidthSrc, int nHeightSrc, COLORREF clTrans)
{
    // 产生前景图的兼容DC
    CMemoryDC dcFrontImage(nWidthDest, nHeightDest, pDestDC);
    dcFrontImage.SetBkColor(clTrans);
    if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
        dcFrontImage.BitBlt(0, 0, nWidthDest, nHeightDest, this, nXSrc, nYSrc, SRCCOPY);
    else
        dcFrontImage.StretchBlt(0, 0, nWidthDest, nHeightDest,
            this, nXSrc, nYSrc, nWidthSrc, nHeightSrc, SRCCOPY);

    // 产生前景掩码图的兼容DC  掩码图 (要消去的区域为白色, 要留下的区域为黑色)
    CBitmap bmpMask;
    bmpMask.CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 构造单色掩码图(像素点非黑即白)
    CDC dcMask;
    dcMask.CreateCompatibleDC(pDestDC);
    dcMask.SelectObject(&bmpMask);
    dcMask.BitBlt(0, 0, nWidthDest, nHeightDest, &dcFrontImage, nXSrc, nYSrc, SRCCOPY);

    // 指定前景图的背景颜色与前景颜色
    dcFrontImage.SetBkColor(RGB(0, 0, 0));         // 前景图要消去的区域设置黑色 0x000000
    dcFrontImage.SetTextColor(RGB(255, 255, 255)); // 前景图要保留的区域设置白色 0xFFFFFF
    // 掩码图同前景图做与运算 
    // 掩码图白色区域与前景图要消去的黑色区域 0xFFFFFF & 0x000000 = 0 黑白抵消, 前景图要消去的区域变为黑色  
    // 掩码图黑色区域与前景图要保留的白色区域 0x000000 & 0xFFFFFF = 0 黑白抵消, 前景图要保留的彩色区域恢复原色
    dcFrontImage.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMask, nXSrc, nYSrc, SRCAND);
    // 掩码图同背景图做与运算 背景图视为非黑色即为非零
    // 掩码图的白色区域与背景图 0xFFFFFF & 0xXXXXXX = 0xXXXXXX, 白色区域消去, 被白色遮罩的背景显露出来
    // 掩码图的黑色区域与背景图 0x000000 & 0xXXXXXX = 0x000000, 黑色区域保留, 背景的一部分被黑色遮罩住 
    pDestDC->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcMask, nXSrc, nYSrc, SRCAND);
    // 前景图要消去的区域为黑色, 背景图对应的区域为任意颜色 0x000000 | 0xXXXXXX = 0xXXXXXX 保留对应区域的背景颜色
    // 前景图要保留的区域为彩色, 背景图对应的区域为黑色     0xXXXXXX | 0x000000 = 0xXXXXXX 保留对应区域的前景颜色
    pDestDC->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcFrontImage, nXSrc, nYSrc, SRCPAINT);
}




小小蒟蒻
1个月前
#include <algorithm>

class CNotePadDlg : public CDialogEx
{
private: 
    void AddMainMenu();
    void MoveEditContrl(int cx, int cy);
    CString GetDragFileName(HDROP hDrop);
    BOOL IsTextUnchanged();
    CString GetTitle() const;
    void ReadText(const CString& strFileName);
private:  // 转码函数
    void BEToLE(char* pStr, int nLength);
    int GetCodePage(unsigned char* pStr);
    BOOL CheckUtf8WithoutBom(unsigned char* pStr);
    BOOL CheckUnicode(unsigned char* pStr, int nBytes);
    LPWSTR ToUnicode(const char* pStr, DWORD nCode);
private:
    enum class CodeType { ANSI = 0x01, UTF_BE, UTF_LE, UTF8, UTF8_BOM };
    static TCHAR BASED_CODE m_szFilter[];
    CString m_sFile = _T("");
    DWORD m_nCode = 0;
};

TCHAR BASED_CODE CNotePadDlg::m_szFilter[] =
    _T("Char Files (*.txt; *.ini; *.inf)\0*.txt; *.ini; *.inf\0")
    _T("All Files (*.*)\0*.*\0\0");

//////////////////////////////////////
// 编码转化相关函数族

void CNotePadDlg::BEToLE(char* pStr, int nLength)
{
    for (char* p = pStr + nLength - 2; p >= pStr; p -= 2)
        std::swap(*p, *(p + 1));
}

LPWSTR CNotePadDlg::ToUnicode(const char* pStr, DWORD nCode)
{
    int nBytes = MultiByteToWideChar(nCode, 0, pStr, -1, NULL, 0);
    auto p = new WCHAR[nBytes + 1];
    MultiByteToWideChar(nCode, 0, pStr, -1, p, nBytes);
    p[nBytes] = '\0';
    return p;
}
BOOL CNotePadDlg::CheckUnicode(unsigned char* pStr, int nBytes)
{
    if (pStr[0] == 0xFE && pStr[1] == 0xFF)
    {
        BEToLE((char*)pStr, nBytes);
        m_nCode = (DWORD)CodeType::UTF_BE;
        return TRUE;
    }
    else if (pStr[0] == 0xFF && pStr[1] == 0xFE)
    {
        m_nCode = (DWORD)CodeType::UTF_LE;
        return TRUE;
    }
    return FALSE;
}

int CNotePadDlg::GetCodePage(unsigned char* pStr)
{
    if ((pStr[0] == 0xEF && pStr[1] == 0xBB && pStr[2] == 0xBF) || CheckUtf8WithoutBom(pStr))
    {
        (pStr[0] == 0xEF && pStr[1] == 0xBB && pStr[2] == 0xBF)
            ? m_nCode = (DWORD)CodeType::UTF8_BOM
            : m_nCode = (DWORD)CodeType::UTF8;
        return CP_UTF8;
    }
    m_nCode = (DWORD)CodeType::ANSI;
    return CP_ACP;
}

/*
unicode符号范围 16进制      |       TUF8编码方式 2进制
----------------------------------------------------------------------------------------
1 | 0000 0000 0000 007F     |                                                   0XXXXXXX
2 | 0000 0000 0000 07FF     |                                          110XXXXX 10XXXXXX
3 | 0000 0000 0000 FFFF     |                                 1110XXXX 10XXXXXX 10XXXXXX
4 | 0000 0000 0010 FFFF     |                        11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
5 | 0000 0000 03FF FFFF     |               111110XX 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX
6 | 0000 0000 7FFF FFFF     |      1111110X 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX

按字节顺序遍历字符串 (使用循环的原因: 要按字节为单位检测完所有字节才能确定该字符串是否为TUF编码的字符串)
1)  单字节的UTF8字符, 字节的最高位为0, 继续检测相邻的下一个字节的最高位
2)  获取一个UTF8字符的长度, 单位为字节 (使用循环的原因: 不清楚当前TUF8下的字符占用一个字节还是多个字节)
3)  UTF8字符是单个字节, 错误的UTF8编码
4)  检测一个UTF8字符的非首字节,最高两位(截取的掩码是0xC0),不等于0x80, 错误的UTF8编码 (使用循环的原因: 不清楚当前TUF8下的字符出来首字节外还占用了几个字节)
循环结束, 正确的UTF8编码
*/

BOOL CNotePadDlg::CheckUtf8WithoutBom(unsigned char* pStr)
{
    auto p = pStr;
    int nCount = 0; // 字符的个数
    int nLength = strlen((LPCSTR)pStr);   // 原始字符串的字节长度
    // 按字节顺序遍历字符串
    while (*p)  // '\0'是字符串的结束标记
    {
        auto c = *p++;   // 获取当前字节, 指针指向相邻的下一个字节
        // 1) 单字节的UTF8字符, 字节的最高位为0, 继续检测相邻的下一个字节的最高位, 默认单字节的字符为UTF8编码的字符
        if ((c & 0x80) == 0)
            if (++nCount == nLength)  // 区分ANSI与UTF8编码, ANSI的字符总个数等于字节总数, UTF8的字符总数不等于字节总数
                return FALSE;
            else continue;

        // 2) 获取一个UTF8字符的长度, 单位为字节
        int nBytes = 0;                             // 一个UTF8字符的长度, 单位为字节
        do nBytes++; while ((c = c << 1) & 0x80);   // 当前字节左移一位后,最高位为0, 停止循环
        if (nBytes == 1) return FALSE;              // 单字节的UTF8在前面处理过. 这里出现就是缺损的编码字符,错误的UTF8编码
        // 4) 检测一个UTF8字符的非首字节,最高两位(截取的掩码是0xC0),不等于二进制的10(0x80), 就是错误的UTF8编码
        for (int i = 1; i < nBytes; i++)            // 检测字符串中某一个UTF8字符的非首字节 
            if ((*p++ & 0xC0) != 0x80)
                return FALSE;
    }
    // 循环结束, 正确的UTF8编码
    return TRUE;
}

void CNotePadDlg::ReadText(const CString& strFileName)
{
    CFile file;
    int nReadMask = CFile::modeRead | OF_SHARE_DENY_WRITE;
    if (!file.Open(strFileName, nReadMask, NULL))
    {
        MessageBox(_T("打开文件失败"));
        return;
    }
    int nBytes = 0;
    if ((nBytes = (int)file.GetLength()) <= 0)
    {
        MessageBox(_T("打开空文件"));
        SetDlgItemText(IDC_TEXT, _T(""));
        return;
    }
    unsigned char* p = new unsigned char[nBytes + 2];
    nBytes = file.Read(p, nBytes);
    p[nBytes] = p[nBytes + 1] = 0;
    if (CheckUnicode(p, nBytes))    // 检查是否为UTF-16 BE 或者是UTF-16 LE
        SetDlgItemText(IDC_TEXT, (LPTSTR)p);
    else
    {
        int nCodePage = GetCodePage(p); // 在UTF8与ANSI中做区别
        if (nCodePage != CP_ACP && nCodePage != CP_UTF8) return; // 不是UTF8或ANSI
        LPWSTR pText = ToUnicode((const char*)p, nCodePage);
        if (!pText) return;
        SetDlgItemText(IDC_TEXT, (LPCTSTR)pText);
    }
    if (!p) delete[]p;
}



小小蒟蒻
1个月前
#include<reg52.h>

unsigned char code LedChar[] = {  // 数码管真值表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {  // 数码管缓存数组
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned int cnt = 0;  // 中断计数器

void main() {
    unsigned long sec = 0, base = 1; // 秒数, 秒数的基数, 十进制
    unsigned int j = 0; // 数码管模块的编号(0-5)  
    P1 = 0x00;    //使能U3,选择控制数码管
    TMOD = 0x01;  // 定时器工作模式1
    TH0 = 0xFC;   // 设定定时器的计时长度为0.02秒
    TL0 = 0x67;
    TR0 = 1;       
    ET0 = 1;
    EA = 1;
    while(1) {
        if(cnt >= 1000) {
            cnt = 0;
            sec++;
            for(j = 0; j < 6; j++) {
                LedBuff[j] = LedChar[sec/base%10];  // 带前导0
                //sec/base ? (LedBuff[j] = LedChar[sec/base%10]) : (LedBuff[j] = 0xFF); // 不带前导0 
                base *= 10;
            }
        }
        base = 1;           
    }
}

unsigned char i = 0;

void InterruptTimer0() interrupt 1 {
    TH0 = 0xFC;  //重新加载初值
    TL0 = 0x67;
    cnt++;       //中断次数计数值加1
    //以下代码完成数码管动态扫描刷新
    P0 = 0xFF;   //显示消隐
    switch (i) {
        case 0: P1 = 0x08, i++, P0 = LedBuff[0]; break;
        case 1: P1 = 0x09, i++, P0 = LedBuff[1]; break;
        case 2: P1 = 0x0A, i++, P0 = LedBuff[2]; break;
        case 3: P1 = 0x0B, i++, P0 = LedBuff[3]; break;
        case 4: P1 = 0x0C, i++, P0 = LedBuff[4]; break;
        case 5: P1 = 0x0D, i=0, P0 = LedBuff[5]; break;
        default: break;
    }
}



小小蒟蒻
1个月前
/*
unicode符号范围 16进制      |       TUF8编码方式 2进制
----------------------------------------------------------------------------------------
1 | 0000 0000 0000 007F     |                                                   0XXXXXXX
2 | 0000 0000 0000 07FF     |                                          110XXXXX 10XXXXXX
3 | 0000 0000 0000 FFFF     |                                 1110XXXX 10XXXXXX 10XXXXXX
4 | 0000 0000 0010 FFFF     |                        11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
5 | 0000 0000 03FF FFFF     |               111110XX 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX
6 | 0000 0000 7FFF FFFF     |      1111110X 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX

按字节顺序遍历字符串 (使用循环的原因: 要按字节为单位检测完所有字节才能确定该字符串是否为TUF编码的字符串)
1)  单字节的UTF8字符, 字节的最高位为0, 继续检测相邻的下一个字节的最高位
2)  获取一个UTF8字符的长度, 单位为字节 (使用循环的原因: 不清楚当前TUF8下的字符占用一个字节还是多个字节)
3)  UTF8字符是单个字节, 错误的UTF8编码
4)  检测一个UTF8字符的非首字节,最高两位(截取的掩码是0xC0),不等于0x80, 错误的UTF8编码 (使用循环的原因: 不清楚当前TUF8下的字符出来首字节外还占用了几个字节)
循环结束, 正确的UTF8编码
*/

BOOL CEncode::CheckUtf8(LPBYTE pStr)
{
    auto p = pStr;
    int nCount = 0;
    int nLength = strlen((LPCSTR)pStr);   // 原始字符串的字节长度
    // 按字节顺序遍历字符串
    while (*p)  // '\0'是字符串的结束标记
    {
        auto c = *p++;   // 获取当前字节, 指针指向相邻的下一个字节
        // 1) 单字节的UTF8字符, 字节的最高位为0, 继续检测相邻的下一个字节的最高位, 默认单字节的字符为UTF8编码的字符
        if ((c & 0x80) == 0)
            if (++nCount == nLength)  // 区分ANSI与UTF8编码, ANSI的字符总个数等于字节总数, UTF8的字符总数不等于字节总数
                return FALSE;
            else continue;

        // 2) 获取一个UTF8字符的长度, 单位为字节
        int nBytes = 0;                             // 一个UTF8字符的长度, 单位为字节
        do nBytes++; while ((c = c << 1) & 0x80);   // 当前字节左移一位后,最高位为0, 停止循环
        if (nBytes == 1) return FALSE;              // 单字节的UTF8在前面处理过. 这里出现就是缺损的编码字符,错误的UTF8编码
        // 4) 检测一个UTF8字符的非首字节,最高两位(截取的掩码是0xC0),不等于二进制的10(0x80), 就是错误的UTF8编码
        for (int i = 1; i < nBytes; i++)            // 检测字符串中某一个UTF8字符的非首字节 
            if ((*p++ & 0xC0) != 0x80)
                return FALSE;
    }
    // 循环结束, 正确的UTF8编码
    return TRUE;
}



小小蒟蒻
1个月前

1.png
2.png
6.png
5.png