Qt 使用GDAL 显示卫星遥感影像数据Ttiff文件等,缩放、移动

对于影像文件的读取,借鉴了已有的资料,网址忘了,侵权告知即删

耗时3天,直接提供我测试的代码吧,

头文件内容

#ifndef SHOWBIGPICWIDGET_H
#define SHOWBIGPICWIDGET_H

#include <QWidget>
#include <QLabel>
#include<gdal_priv.h>

class ShowBigPicWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ShowBigPicWidget(QWidget *parent = nullptr);
    ~ShowBigPicWidget();

private:

    //读取图像
    void readImage(QString filePath);
    //
    void sectionHandle();
    //波段处理
    void ShowBand( GDALRasterBand* band );
    //显示图片
    void ShowImg( QList<GDALRasterBand*>*imgBand );
    unsigned char* ImgSketch( float* buffer ,GDALRasterBand* currentBand, int size, double noValue );


    //根据图像的全部宽高,去获取当前显示时读取的图像宽高和缩放宽高
    void scaleShow(int &imgX,int &imgY, int &imgW,int &imgH,int &scaleW,int &scaleH);



    /**
    * @auther 贺华
    * @date   2024/09/04
    * @brief  图像显示,首次显示,默认全部显示 即 显示全景
    */
    void picShowNormal();




    //针对放大、缩小功能,实际就是计算下列的控制值的过程
    /**
    * @auther 贺华
    * @date   2024/09/05
    * @brief  放大
    */
    void magnification();

    /**
    * @auther 贺华
    * @date   2024/09/05
    * @brief  缩小
    */
    void reduce();

private:

    QString m_filePath = "";

    //文件读取对象
    GDALDataset *poDataset = nullptr;
    //图像的全部像素宽高
    int m_totalW = 0;
    int m_totalH = 0;

    //绘制的图像
    QLabel *m_picLabel = nullptr;

    /// <summary>
    /// 判断是否显示RGB彩色图像
    /// </summary>
    bool m_showColor;

    //缩放因子 默认1.0  大于1.0为放大  小于1.0为缩小  最多保留两位小数
    //按照
    float m_scaleFac = 1.0;

    /**
    * @auther 贺华
    * @date   2024/09/04
    * @brief  下列字段用来控制获取当前显示图像,移动和缩放都会更新相应值
    */

    //左上角  定位获取图像数据的像素点
    int m_locationX = 0;
    int m_locationY = 0;

    //获取图像的实际像素的长和宽
    int m_realW = 0;
    int m_realH = 0;

    //显示在label上的长和宽,一般来说都是label的长宽
    int m_showW = 0;
    int m_showH = 0;



    //鼠标按下的坐标
    QPoint lastEventCursorPos;

protected:
    void wheelEvent( QWheelEvent *event );
    void mousePressEvent( QMouseEvent *event );
    void mouseMoveEvent( QMouseEvent *event );
    void mouseReleaseEvent( QMouseEvent *event);

};

#endif // SHOWBIGPICWIDGET_H

cpp文件

#include "ShowBigPicWidget.h"
#include "ui_ShowBigPicDialog.h"

#include <QFile>
#include <QDebug>
#include <QFileDialog>
#include <QMessageBox>
#include <QMouseEvent>
#include <qglobal.h>

#include "MapCanvas.h"

ShowBigPicWidget::ShowBigPicWidget(QWidget *parent) :
    QWidget(parent)
{

    this->setAttribute(Qt::WA_DeleteOnClose);

    QHBoxLayout *lay = new QHBoxLayout();
    m_picLabel = new QLabel(this);
    m_picLabel->setFixedSize(600,500);
    m_picLabel->setAlignment(Qt::AlignCenter);
    lay->addWidget(m_picLabel);
    lay->setContentsMargins(0,0,0,0);
    this->setLayout(lay);

    m_filePath = "C:/Users/dev36/Desktop/HH/Demos/dllConsole/GF2_PMS2_E85.0_N44.6_20160527_L1A0001606970/GF2_PMS2_E85.0_N44.6_20160527_L1A0001606970-PAN2.tiff";

    this->readImage(m_filePath);

}

ShowBigPicWidget::~ShowBigPicWidget()
{
    qDebug()<<"~~delete ShowBigPicWidget";
    if(poDataset){
        GDALClose( poDataset );
        poDataset = nullptr;
        GDALDestroyDriverManager();
    }
}

void ShowBigPicWidget::readImage(QString filePath)
{
    GDALAllRegister();
    CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO" );

    //设置缓存64M
//    GDALSetCacheMax(64);

    poDataset = ( GDALDataset* )GDALOpen(filePath.toStdString().c_str(), GA_ReadOnly );
    if ( poDataset == NULL )
    {
        qDebug()<<tr( "Can not open file %1" ).arg( filePath );
        return;
    }

//    ShowFileList( filePath );
//    ShowImgInfor( filePath );

    int imgWidth = poDataset->GetRasterBand(1)->GetXSize();
    int imgHeight = poDataset->GetRasterBand(1)->GetYSize();
    m_totalH = imgHeight;
    m_totalW = imgWidth;

	//解决大图像移动、缩放  很慢的问题  会在图像的相同目录下新建ovr文件
	if(poDataset->GetRasterBand(1)->GetOverviewCount() == 0) {
        //金字塔信息会缓存  如果已有金字塔信息就不需要再创建
        int iPixelNum = imgHeight * imgWidth;    //图像中的总像元个数
        int iTopNum = 4096;                 //顶层金字塔大小,64*64
        int iCurNum = iPixelNum / 4;

        int anLevels[1024] = { 0 };
        int nLevelCount = 0;                //金字塔级数

        do    //计算金字塔级数,从第二级到顶层
        {
            anLevels[nLevelCount] = static_cast<int>(pow(2.0, nLevelCount+2));
            nLevelCount ++;
            iCurNum /= 4;
        } while (iCurNum > iTopNum);

        const char      *pszResampling = "nearest"; //采样方式

        /* -------------------------------------------------------------------- */
        /*      Generate overviews.                                             */
        /* -------------------------------------------------------------------- */
        CPLErr err = GDALBuildOverviews( poDataset,pszResampling, nLevelCount, anLevels,
        0, NULL, NULL, NULL );
    }


    this->picShowNormal();

    this->sectionHandle();

}

void ShowBigPicWidget::sectionHandle()
{
    // 如果图像文件并非三个波段,则默认只显示第一波段灰度图像
    if ( poDataset->GetRasterCount() != 3 )
    {
        m_showColor = false;
        ShowBand( poDataset->GetRasterBand(1) );
    }
    // 如果图像正好三个波段,则默认以RGB的顺序显示彩色图
    else
    {
        m_showColor = true;
        QList<GDALRasterBand*> bandList;
        bandList.append(poDataset->GetRasterBand( 1 ) );
        bandList.append(poDataset->GetRasterBand( 2 ) );
        bandList.append(poDataset->GetRasterBand( 3 ) );
        ShowImg( &bandList );
    }
}

void ShowBigPicWidget::ShowBand(GDALRasterBand *band)
{
    if ( band == NULL )
    {
        return;
    }

    QList<GDALRasterBand*> myBand;
    myBand.append( band );
    myBand.append( band );
    myBand.append( band );

    ShowImg( &myBand );
}

void ShowBigPicWidget::ShowImg(QList<GDALRasterBand *> *imgBand)
{
    if ( imgBand->size() != 3 )
    {
        return;
    }

    int imgWidth = m_realW;
    int imgHeight = m_realH;

    int iScaleWidth = m_showW;
    int iScaleHeight = m_showH;

    int x = m_locationX;
    int y = m_locationY;

//    this->scaleShow(x,y,imgWidth,imgHeight,iScaleWidth,iScaleHeight);


//    GDALDataType dataType = imgBand->at( 0)->GetRasterDataType();

    // 首先分别读取RGB三个波段
    float* rBand = new float[iScaleWidth *iScaleHeight];
    float* gBand = new float[iScaleWidth *iScaleHeight];
    float* bBand = new float[iScaleWidth *iScaleHeight];

    unsigned char *rBandUC, *gBandUC, *bBandUC;

    // 根据是否显示彩色图像,判断RGB三个波段的组成方式,并分别读取
    if ( m_showColor == true )
    {
        imgBand->at( 0 )->RasterIO(GF_Read, x, y, imgWidth, imgHeight, rBand , iScaleWidth, iScaleHeight,GDT_Float32, 0, 0 );
        imgBand->at( 1 )->RasterIO(GF_Read, x, y, imgWidth, imgHeight, gBand, iScaleWidth, iScaleHeight,GDT_Float32, 0, 0 );
        imgBand->at( 2 )->RasterIO(GF_Read, x, y, imgWidth, imgHeight, bBand, iScaleWidth, iScaleHeight,GDT_Float32, 0, 0 );

        // 分别拉伸每个波段并将Float转换为unsigned char
        rBandUC = ImgSketch( rBand,imgBand->at( 0 ), iScaleWidth * iScaleHeight, imgBand->at( 0)->GetNoDataValue() );
        gBandUC = ImgSketch( gBand,imgBand->at( 1 ), iScaleWidth * iScaleHeight, imgBand->at( 1)->GetNoDataValue() );
        bBandUC = ImgSketch( bBand,imgBand->at( 2 ), iScaleWidth * iScaleHeight, imgBand->at( 2)->GetNoDataValue() );
    }
    else
    {
        imgBand->at( 0 )->RasterIO(GF_Read, x, y, imgWidth, imgHeight, rBand , iScaleWidth, iScaleHeight,GDT_Float32, 0, 0 );

        rBandUC = ImgSketch( rBand,imgBand->at( 0 ), iScaleWidth * iScaleHeight, imgBand->at( 0)->GetNoDataValue() );
        gBandUC = rBandUC;
        bBandUC = rBandUC;
    }

    // 将三个波段组合起来
    int bytePerLine = ( iScaleWidth * 24 + 31 )/ 8;
    unsigned char* allBandUC = new unsigned char[bytePerLine * iScaleHeight * 3];//可能不需要乘3
    for( int h = 0; h < iScaleHeight; h++ )
    {
        for( int w = 0; w < iScaleWidth; w++)
        {
            allBandUC[h * bytePerLine + w * 3 +0] = rBandUC[h * iScaleWidth + w];
            allBandUC[h * bytePerLine + w * 3 +1] = gBandUC[h * iScaleWidth + w];
            allBandUC[h * bytePerLine + w * 3 +2] = bBandUC[h * iScaleWidth + w];
        }
    }


    //显示图片
    m_picLabel->setPixmap(QPixmap::fromImage(QImage( allBandUC, iScaleWidth, iScaleHeight, bytePerLine,QImage::Format_RGB888)));



    //释放内存
    delete [] rBand;
    delete [] gBand;
    delete [] bBand;

    if ( m_showColor == true ){
        delete []rBandUC;
        delete []gBandUC;
        delete []bBandUC;
    }else{
        delete []rBandUC;
    }

    delete [] allBandUC;

    //还是不清除缓存了,清除之后遇到大文件缩放、移动
//    if(poDataset){
//        //清除框架内部缓存,否则大图移动缩放,内存会一直上涨
//        GDALFlushCache(poDataset);
//    }

}

///<summary>
/// 图像线性拉伸
///</summary>
///<param name="buffer">图像缓存</param>
///<param name="currentBand">当前波段</param>
///<param name="size">The size.</param>
///<param name="noValue">图像中的异常值</param>
///<returns>经过拉伸的8位图像缓存</returns>
unsigned char *ShowBigPicWidget::ImgSketch(float *buffer, GDALRasterBand *currentBand, int bandSize, double noValue)
{
    unsigned char* resBuffer = new unsigned char[bandSize];
    double max, min;
    double minmax[2];


    currentBand->ComputeRasterMinMax( 1,minmax );
    min = minmax[0];
    max = minmax[1];
    if( min <= noValue && noValue<= max )
    {
        min = 0;
    }
    for ( int i = 0; i < bandSize; i++ )
    {
        if ( buffer[i] > max )
        {
            resBuffer[i] = 255;
        }
        else if ( buffer[i] <= max&& buffer[i] >= min )
        {
            resBuffer[i] =static_cast<uchar>( 255 - 255 * ( max - buffer[i] ) / ( max - min ) );
        }
        else
        {
            resBuffer[i] = 0;
        }
    }

    return resBuffer;
}

//根据图像的全部宽高,去获取当前显示时读取的图像宽高和缩放宽高
void ShowBigPicWidget::scaleShow(int &imgX,int &imgY,int &imgW, int &imgH, int &scaleW, int &scaleH)
{
    int labelW = this->width();
    int labelH = this->height();

    scaleW = labelW;
    scaleH = labelH;

    imgX = m_locationX;
    imgY = m_locationY;

    imgW = labelW;
    imgH = labelH;

    if(imgX + imgW > m_totalW && imgX == 0){
        imgW = m_totalW;
        scaleW = m_totalW;
    }
    if(imgY + imgH > m_totalH && imgY == 0){
        imgH = m_totalH;
        scaleH = m_totalH;
    }

}

/**
* @auther 贺华
* @date   2024/09/04
* @brief  图像显示,首次显示,默认全部显示,
*/
void ShowBigPicWidget::picShowNormal()
{
    m_locationX = 0;
    m_locationY = 0;

    m_realW = m_totalW;
    m_realH = m_totalH;

    QSize labelSize = m_picLabel->size();

    if(labelSize.width() >= m_totalW){
        if(labelSize.height() >= m_totalH){

            //这种情况就要不改变分辨率的情况下显示
            m_showW = m_totalW;
            m_showH = m_totalH;

        }else{

            m_showW = m_totalH*labelSize.width()/m_totalW;
            m_showH = m_totalH;
        }
    }else{

        if(labelSize.height() >= m_totalH){
            m_showW = m_totalW;
            m_showH = m_totalW*labelSize.height()/m_totalH;
        }else{

            //需要看宽度、高度占比更高
            if(labelSize.width()/labelSize.height() >= m_totalW/m_totalH){
                //高度占比更高
                m_showH = labelSize.height();
                m_showW = labelSize.height()*m_totalW/m_totalH;
            }else{
                //宽度占比更高
                m_showW = labelSize.width();
                m_showH = labelSize.width()*m_totalH/m_totalW;
            }

        }
    }
}

/**
* @auther 贺华
* @date   2024/09/05
* @brief  放大
*/
void ShowBigPicWidget::magnification()
{
    if(m_realH <= 2 || m_realW <= 2){
        //如果实际显示像素低于2个像素,不支持继续放大
        return;
    }

    if(m_locationX > 0){
        if(m_locationY > 0){
            //图像的显示肯定是已经超过了当前的视图,那么继续放大  当前宽高的0.05

            m_locationX = m_locationX + (((int)m_realW*0.05)/2);
            m_locationY = m_locationY + (((int)m_realH*0.05)/2);

            m_realW = m_realW*0.95;
            m_realH = m_realH*0.95;
        }else{
            //这种情况需要计算,判断放大后会不会超过视图高度
            if(m_showH * 1.05 <= m_picLabel->size().height()){
                //等于的话
                m_locationX = m_locationX + (((int)m_realW*0.05)/2);
                m_locationY = 0;

                m_realW = m_realW*0.95;

                if(m_showH * 1.05 < m_picLabel->size().height()){
                    m_showH = m_showH*1.05;
                }else{
                    m_showH = m_picLabel->size().height();
                }
            }else{
                //宽度肯定是大于了
                m_locationX = m_locationX + (((int)m_realW*0.05)/2);
                m_locationY = ((int)m_realH*0.05)/2;

                m_realW = m_realW*0.95;
                m_realH = m_realH*0.95;

                m_showH = m_picLabel->size().height();
            }
        }
    }else{
        if(m_locationY > 0){
            //这种情况需要计算,判断放大后会不会超过视图宽度
            if(m_showW * 1.05 <= m_picLabel->size().width()){
                //等于的话
                m_locationY = m_locationY + (((int)m_realH*0.05)/2);
                m_locationX = 0;

                m_realH = m_realH*0.95;

                if(m_showW * 1.05 < m_picLabel->size().width()){
                    m_showW = m_showW*1.05;
                }else{
                    m_showW = m_picLabel->size().width();
                }
            }else{
                //宽度肯定是大于了
                m_locationY = m_locationY + (((int)m_realH*0.05)/2);
                m_locationX = ((int)m_realW*0.05)/2;

                m_realH = m_realH*0.95;
                m_realW = m_realW*0.95;

                m_showW = m_picLabel->size().width();
            }
        }else{
            //那不得判断放大后是否都超过了视图区域?
            bool xOut = m_showW * 1.05 > m_picLabel->size().width();
            bool yOut = m_showH * 1.05 > m_picLabel->size().height();

            if(xOut){
                if(yOut){
                    //都超出了
                    m_locationX = ((int)m_realW*0.05)/2;
                    m_locationY = ((int)m_realH*0.05)/2;

                    m_showH = m_picLabel->size().height();
                    m_showW = m_picLabel->size().width();

                    m_realW = m_realW*1.05 - ((m_showW*1.05-m_picLabel->size().width())*m_realW/m_showW);
                    m_realH = m_realH*1.05 - ((m_showH*1.05-m_picLabel->size().height())*m_realH/m_showH);

                }else{
                    //宽度超出
                    m_locationY = 0;
                    m_locationX = ((int)m_realW*0.05)/2;

                    m_showH = m_showH*1.05;
                    m_showW = m_picLabel->size().width();

                    m_realH = m_totalH;
                    m_realW = m_totalW-(2*m_locationX);
                }
            }else{
                if(yOut){
                    //高度超出
                    m_locationX = 0;
                    m_locationY = ((int)m_realH*0.05)/2;

                    m_showW = m_showW*1.05;
                    m_showH = m_picLabel->size().height();

                    m_realW = m_totalW;
                    m_realH = m_totalH-(2*m_locationY);
                }else{
                    //都未超出
                    m_locationX = 0;
                    m_locationY = 0;

                    //需要向上取整,否则可能放大不了了
                    m_showH = ceil(m_showH*1.05);
                    m_showW = ceil(m_showW*1.05);

                    m_realW = m_totalW;
                    m_realH = m_totalH;
                }
            }

        }
    }

    if(m_locationX < 0){
        m_locationX = 0;
    }
    if(m_locationY < 0){
        m_locationY = 0;
    }

    this->sectionHandle();
//    this->readImage(m_filePath);

}

/**
* @auther 贺华
* @date   2024/09/05
* @brief  缩小  注意*******缩小还要考虑在边缘时缩小
*/
void ShowBigPicWidget::reduce()
{
    if(m_showH <= 5 || m_showW <= 5){
        //如果显示区域低于5像素,不支持缩小
        return;
    }

    //先判断缩小之后需要显示的内容是否已经超过了图像的最大尺寸
    bool xAll = m_realW*1.05 >= m_totalW;
    bool yAll = m_realH*1.05 >= m_totalH;

    if(xAll){
        if(yAll){
            //都超过了最大尺寸 宽高都显示全部内容

            if(m_realW < m_totalW){
                if(m_realH < m_totalH){

                    //需要看宽度、高度占比更高
                    if(m_picLabel->size().width()/m_picLabel->size().height() >= m_totalW/m_totalH){
                        //高度占比更高
                        m_showH = m_picLabel->size().height();
                        m_showW = m_picLabel->size().height()*m_totalW/m_totalH;
                    }else{
                        //宽度占比更高
                        m_showW = m_picLabel->size().width();
                        m_showH = m_picLabel->size().width()*m_totalH/m_totalW;
                    }
                }else{
                    //说明高度在未缩小之前就已全部显示
                    m_showH = m_showH*0.95;
                    m_showW = m_showH*m_totalW/m_totalH;
                }
            }else{

                if(m_realH < m_totalH){
                    //说明宽度在未缩小之前就已全部显示
                    m_showW = m_showW*0.95;
                    m_showH = m_showW*m_totalH/m_totalW;
                }else{
                    m_showW = m_showW*0.95;
                    m_showH = m_showH*0.95;
                }
            }

            m_locationX = 0;
            m_locationY = 0;

            m_realW = m_totalW;
            m_realH = m_totalH;

        }else{
            //在缩小后宽度全部显示,而高度显示部分
            m_locationY = m_locationY-(m_realH*0.05/2);
            if(m_locationY < 0){
                m_locationY = 0;
            }else if(m_locationY + (m_realH *1.05) > m_totalH){
                m_locationY = m_totalH - (m_realH *1.05);
            }

            if(m_realW < m_totalW){
                //宽度在缩小之前未全部显示  根据比例计算
                m_showW = m_showH*m_totalW/(m_realH*1.05);
            }else{
                //宽度在缩小之前已全部显示
                m_showW = m_showW*0.95;
            }

            m_locationX = 0;

            m_realW = m_totalW;
            m_realH = m_realH*1.05;

            m_showH = m_showH * 1;
        }
    }else{
        if(yAll){
            //在缩小后高度全部显示,而宽度显示部分
            m_locationX = m_locationX-(m_realW*0.05/2);
            if(m_locationX < 0){
                m_locationX = 0;
            }else if(m_locationX + (m_realW *1.05) > m_totalW){
                m_locationX = m_totalW - (m_realW *1.05);
            }

            if(m_realH < m_totalH){
                //高度在缩小之前未全部显示  根据比例计算
                m_showH = m_showW*m_totalH/(m_realW*1.05);
            }else{
                //高度在缩小之前已全部显示
                m_showH = m_showH*0.95;
            }

            m_locationY = 0;

            m_realH = m_totalH;
            m_realW = m_realW*1.05;

            m_showW = m_showW * 1;
        }else{
            //这种情况就是缩小之后 视图显示宽高都不是全部的  //需要向上取整,否则可能缩小不了

            m_locationX = m_locationX-(ceil(m_realW*0.05)/2);
            if(m_locationX < 0){
                m_locationX = 0;
            }else if(m_locationX + (ceil(m_realW *1.05)) > m_totalW){
                m_locationX = m_totalW - (ceil(m_realW *1.05));
            }

            m_locationY = m_locationY-(ceil(m_realH *0.05)/2);
            if(m_locationY < 0){
                m_locationY = 0;
            }else if(m_locationY + ceil(m_realH *1.05) > m_totalH){
                m_locationY = m_totalH - ceil(m_realH *1.05);
            }


            m_realW = ceil(m_realW*1.05);
            m_realH = ceil(m_realH*1.05);

            m_showW = m_showW*1;
            m_showH = m_showH*1;
        }
    }


    this->sectionHandle();
//    this->readImage(m_filePath);

}

/**
* @auther 贺华
* @date   2024/09/05
* @brief  图像的放大缩小功能  0.05的当前显示区域变化
*/
void ShowBigPicWidget::wheelEvent(QWheelEvent *event)
{
    //缩放
    if(event->angleDelta().y() > 0){
        //放大
        this->magnification();
    }else{
        //缩小
        this->reduce();
    }
}

void ShowBigPicWidget::mousePressEvent(QMouseEvent *event)
{
    if ( event->button() == Qt::LeftButton ){
        lastEventCursorPos = event->pos();
    }
}

void ShowBigPicWidget::mouseMoveEvent(QMouseEvent *event)
{
    QPoint p = event->pos();
    int xPadding = p.x()-lastEventCursorPos.x();
    int yPadding = p.y()-lastEventCursorPos.y();

    //获取移动比例,在不同尺寸下,移动的距离跟随变化,更加流程
    xPadding = xPadding*m_realW/m_picLabel->size().width();
    yPadding = yPadding*m_realW/m_picLabel->size().width();


    //计算什么时候是不做处理的?
    if(m_locationX == 0 && m_locationY == 0 && xPadding > 0 && yPadding > 0){
        //第一种  已经到了左上角,不能继续滑动
        return;
    }

    if(m_locationX + m_realW >= m_totalW && m_locationY+m_realH >= m_totalH
            && xPadding < 0 && yPadding < 0){
        //第二种  已经到了右下角,不能继续滑动
        return;
    }

    m_locationX = m_locationX-xPadding;
    m_locationY = m_locationY-yPadding;


    //确保不会超出边界
    if(m_locationX + m_realW > m_totalW){
        m_locationX = m_totalW-m_realW;
    }
    if(m_locationY + m_realH > m_totalH){
        m_locationY = m_totalH-m_realH;
    }

    if(m_locationX < 0){
        m_locationX = 0;
    }
    if(m_locationY < 0){
        m_locationY = 0;
    }

    this->sectionHandle();
//    this->readImage(m_filePath);

    lastEventCursorPos = event->pos();
}

void ShowBigPicWidget::mouseReleaseEvent(QMouseEvent *event)
{

}

感觉对于放大、缩小写的还是有点复杂,但是效果还好

使用金字塔的API解决了图像文件过大操作卡死的现象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值