我们都知道,MTK平台Camera在拍照时生成的照片中包含相应照片的Exif信息,而这些信息是从什么地方来的呢?今天我们就来捋一下Code思路。

(1)生成照片通过JpegNode

这里以v2.0的JpegNode.cpp举例

//vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/hwnode/JpegNode/v2.0/JpegNode.cppstatic void onProcessRequest(JpegNodeImp& jpg,Request& req
)
{//(1)prepareCAM_TRACE_NAME(__FUNCTION__);sp<encode_frame> enc_frame = req.getEncodeFrame();// lock bufferif (req.lockMeta() != OK) {MY_LOGE("lock request meta failed!");req.mbIsEncodeJpegError = MTRUE;return;}if (req.prepareMeta() != OK) {MY_LOGE("prepareMeta failed!");req.mbIsEncodeJpegError = MTRUE;return;}if (req.lockInImg() != OK) {MY_LOGE("lock request input image failed");req.mbIsEncodeJpegError = MTRUE;return;}if (req.prepareExif() != OK) {MY_LOGE("prepareExif failed!");return;}if (req.lockOutImg() != OK) {MY_LOGE("lock request output image failed");req.mbIsEncodeJpegError = MTRUE;return;}enc_frame->muJpegSwMode = jpg.mPropJpegSwMode;// (2)encode flowif (!jpg.mbAppnOnly || jpg.mIsIspHidlHeif) {std::thread encodeThumbThread;if (enc_frame->mbHasThumbnail) {encodeThumbThread = std::thread(&JpegNodeImp::encodeThumbnailJpeg, &jpg, std::ref(enc_frame));}jpg.encodeMainJpeg(enc_frame);if(enc_frame->mbHasThumbnail &&encodeThumbThread.joinable()) {encodeThumbThread.join();}} else {if (enc_frame->mbHasThumbnail)jpg.encodeThumbnailJpeg(enc_frame);}req.updateMetadata(enc_frame->mParams);if (req.unlock() != OK) {MY_LOGE("request unlock failed!");}// (3)encode exifjpg.encodeExif(enc_frame);//...return;
}

我们这里主要关注exif信息是如何产生的?所以跟踪第三步encode exif。

MVOID
JpegNodeImp::
encodeExif(sp<encode_frame>& pEncodeFrame)
{//...MUINT const usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;MBOOL ret = pOutImageBuffer->lockBuf(getNodeName(), usage);MY_LOGA_IF(!ret, "%s", "lockBuffer failed, please check VA usage!");size_t exifSize  = 0;MINT8 * pExifBuf = reinterpret_cast<MINT8*>(pOutImageBuffer->getBufVA(0));//这里主要关注是如何make Exif信息if( pExifBuf == NULL|| OK != ExifUtils::makeExifHeader(pEncodeFrame, pExifBuf, exifSize, mbAppnOnly)) {pEncodeFrame->mbSuccess = MFALSE;MY_LOGE("frame %u make exif header failed: buf %p, size %zu",pEncodeFrame->mpFrame->getFrameNo(),pExifBuf, exifSize);}if( pExifBuf )pExifBuf = NULL;size_t JpegBitStreamSize = 0;if (pEncodeFrame->mpJpeg_Main != NULL) {JpegBitStreamSize = pEncodeFrame->exif.getHeaderSize() +pEncodeFrame->mpJpeg_Main->getBitstreamSize();pEncodeFrame->mpJpeg_Main->setBitstreamSize(JpegBitStreamSize);} else {JpegBitStreamSize = pEncodeFrame->exif.getHeaderSize();}//...
}

我们进入makeExifHeader函数。

MERROR
ExifUtils::
makeExifHeader(sp<encode_frame> rpEncodeFrame,MINT8 * const pOutExif,size_t& rOutExifSize, // [IN/OUT] in: exif buf size, out: exif header sizeMBOOL const isAppnOnly
)
{MERROR ret;MBOOL needSOI = MTRUE;ret = rpEncodeFrame->exif.make((MUINTPTR)pOutExif, rOutExifSize, needSOI);rpEncodeFrame->exif.uninit();return ret;
}

这里的exif类型是StdExif,所以我们可以定位到StdExif文件。

(2)进入StdExif文件

我们搜索一下Code,发现StdExif有好几处,如下:

//vendor/mediatek/proprietary/hardware/mtkcam/legacy/exif/camera/StdExif.cpp
//vendor/mediatek/proprietary/hardware/mtkcam/legacy/exif/v3/StdExif.cpp
//vendor/mediatek/proprietary/hardware/mtkcam/utils/exif/v3/StdExif.cpp
//vendor/mediatek/proprietary/hardware/mtkcam-core/utils/exif/v3/StdExif.cpp

那我们如何确定是走的哪个文件中的呢?可通过如下Log来判断:

05-31 23:43:27.593   973 19585 I mtkcam/exif: [make] out buffer(0x7252bc3000)
05-31 23:43:27.593   973 19585 I mtkcam/exif: [updateStdExif] strDateTime(2022:05:31 23:43:27), strSubSecTime(579)
05-31 23:43:27.593   973 19585 I mtkcam/exif: [updateStdExif] property: make(UTIME), model(TM152)
05-31 23:43:27.594   973 19585 E mtkcam/exif: [make] not support ICC profile 0 (make){#642:vendor/mediatek/proprietary/hardware/mtkcam/utils/exif/v3/StdExif.cpp}

一旦拍照之后就会出现make exif信息的Log,可通过如上Log来看能否辨别相应的文件。

我们接下来进入StdExif.cpp文件的make函数。

//vendor/mediatek/proprietary/hardware/mtkcam/utils/exif/v3/StdExif.cppstatus_t
StdExif::
make(MUINTPTR const  outputExifBuf,size_t& rOutputExifSize,MBOOL enableSOI
)
{int ret = 0;mpOutputExifBuf = outputExifBuf;// set 0 first for error returnrOutputExifSize = 0;MY_LOGI("out buffer(%#" PRIxPTR ")", getBufAddr());unsigned int u4OutputExifSize = 0;//这里主要有如下两个exif信息相关的结构体exifAPP1Info_s exifApp1Info;exifImageInfo_s exifImgInfo;//  (1) Fill exifApp1InfoupdateStdExif(&exifApp1Info);//  (2) Fill exifImgInfo::memset(&exifImgInfo, 0, sizeof(exifImageInfo_t));exifImgInfo.bufAddr     = getBufAddr();exifImgInfo.mainWidth   = mExifParam.u4ImageWidth;exifImgInfo.mainHeight  = mExifParam.u4ImageHeight;exifImgInfo.thumbSize   = getThumbnailSize();ret = mpBaseExif->exifApp1Make(&exifImgInfo, &exifApp1Info, &u4OutputExifSize, enableSOI);rOutputExifSize = (size_t)u4OutputExifSize;//  (4) Append App2int app2 = 2;unsigned int app2ReturnSize = 0;int size = mICCSize; // Data(n bytes)unsigned char *pAddr = (unsigned char*)getBufAddr()+ getStdExifSize() + getThumbnailSize();MY_LOGD_IF(mLogLevel,"offset %zu buf %p ", getStdExifSize() + getThumbnailSize() , pAddr);if(mICCIdx == EXIF_ICC_PROFILE_SRGB) {ret = mpBaseExif->exifAppnMake(app2, pAddr, (unsigned char*)&icc_profile_srgb, size, &app2ReturnSize, 0);}else if(mICCIdx == EXIF_ICC_PROFILE_DCI_P3) {ret = mpBaseExif->exifAppnMake(app2, pAddr, (unsigned char*)&icc_profile_display_p3, size, &app2ReturnSize, 0);}elseMY_LOGE("not support ICC profile %d", mICCIdx);// return app2ReturnSize is mICCSize + 2 +2 (Data(n bytes) + Data size(2 bytes) + Data tag(2 bytes))// (3) Append debug exifif ( isEnableDbgExif() ){updateDbgExif();}return (status_t)ret;
}

相关exif信息的部分结构体如下:

//vendor/mediatek/proprietary/hardware/mtkcam/utils/exif/common/IBaseExif.htypedef struct exifImageInfo_s {MUINTPTR bufAddr;unsigned int mainWidth;unsigned int mainHeight;unsigned int thumbSize;
} exifImageInfo_t;typedef struct exifAPP1Info_s {unsigned int imgIndex;      // mtk definition: the index of continuous shot image.unsigned int groupID;       // mtk definition: group ID for continuous shot.unsigned int bestFocusH;    // mtk definition: focus value (H) for best shot.unsigned int bestFocusL;    // mtk definition: focus value (L) for best shot.unsigned int refocusPos;            // mtk definition: for image refocus. JPEG(main sensor) in left or right position.unsigned char strJpsFileName[32];   // mtk definition: for image refocus. JPS file name for calculating depth map.unsigned int exposureTime[2];unsigned int fnumber[2];unsigned int shutterSpeed[2];int brightness[2];int exposureBiasValue[2];unsigned int focalLength[2];unsigned int maxApertureValue[2];unsigned short focalLength35mm;unsigned short orientation;unsigned short exposureProgram;unsigned short isoSpeedRatings;unsigned short isoType;unsigned int isoSpeed;unsigned short meteringMode;unsigned short flash;unsigned short whiteBalanceMode;unsigned short reserved;unsigned char strImageDescription[32];unsigned char strMake[32];unsigned char strModel[32];unsigned char strSoftware[32];unsigned char strDateTime[20];unsigned char strSubSecTime[4];unsigned char gpsLatitudeRef[2];unsigned char gpsLongitudeRef[2];unsigned char reserved02;unsigned int digitalZoomRatio[2];unsigned short sceneCaptureType;unsigned short lightSource;unsigned char strFlashPixVer[8];unsigned short exposureMode;unsigned short reserved03;int gpsIsOn;int gpsAltitude[2];int gpsLatitude[8];int gpsLongitude[8];int gpsTimeStamp[8];unsigned char gpsDateStamp[12];unsigned char gpsProcessingMethod[64];
} exifAPP1Info_t;

这里我们主要看updateStdExif(&exifApp1Info)函数,看主要有那些exif信息被产生。

void
StdExif::
updateStdExif(exifAPP1Info_s* exifApp1Info)
{::memset(exifApp1Info, 0, sizeof(exifAPP1Info_s));/*********************************************************************************GPS**********************************************************************************/if  (mExifParam.u4GpsIsOn == 1) {float latitude = atof((char*)mExifParam.uGPSLatitude);float longitude = atof((char*)mExifParam.uGPSLongitude);long long timestamp = atol((char*)mExifParam.uGPSTimeStamp);char const*pgpsProcessingMethod = (char*)mExifParam.uGPSProcessingMethod;//// Set GPS Infoif (latitude >= 0) {strncpy((char *)exifApp1Info->gpsLatitudeRef, "N", sizeof(exifApp1Info->gpsLatitudeRef)/sizeof(char));}else {strncpy((char *)exifApp1Info->gpsLatitudeRef, "S", sizeof(exifApp1Info->gpsLatitudeRef)/sizeof(char));latitude *= -1;     // make it positive}if (longitude >= 0) {strncpy((char *)exifApp1Info->gpsLongitudeRef, "E", sizeof(exifApp1Info->gpsLongitudeRef)/sizeof(char));}else {strncpy((char *)exifApp1Info->gpsLongitudeRef, "W", sizeof(exifApp1Info->gpsLongitudeRef)/sizeof(char));longitude *= -1;    // make it positive}exifApp1Info->gpsIsOn = 1;// AltitudeexifApp1Info->gpsAltitude[0] = mExifParam.u4GPSAltitude;exifApp1Info->gpsAltitude[1] = 1;// LatitudeexifApp1Info->gpsLatitude[0] = (int) latitude;exifApp1Info->gpsLatitude[1] = 1;latitude -= exifApp1Info->gpsLatitude[0];latitude *= 60;exifApp1Info->gpsLatitude[2] = (int) latitude;exifApp1Info->gpsLatitude[3] = 1;latitude -= exifApp1Info->gpsLatitude[2];latitude *= 60;latitude *= 10000;exifApp1Info->gpsLatitude[4] = (int) latitude;exifApp1Info->gpsLatitude[5] = 10000;// LongtitudeexifApp1Info->gpsLongitude[0] = (int) longitude;exifApp1Info->gpsLongitude[1] = 1;longitude -= exifApp1Info->gpsLongitude[0];longitude *= 60;exifApp1Info->gpsLongitude[2] = (int) longitude;exifApp1Info->gpsLongitude[3] = 1;longitude -= exifApp1Info->gpsLongitude[2];longitude *= 60;longitude *= 10000;exifApp1Info->gpsLongitude[4] = (int) longitude;exifApp1Info->gpsLongitude[5] = 10000;// Timestampif ( timestamp >= 0 ){time_t tim = (time_t) timestamp;struct tm *ptime = gmtime(&tim);if (ptime != NULL) {exifApp1Info->gpsTimeStamp[0] = ptime->tm_hour;exifApp1Info->gpsTimeStamp[1] = 1;exifApp1Info->gpsTimeStamp[2] = ptime->tm_min;exifApp1Info->gpsTimeStamp[3] = 1;exifApp1Info->gpsTimeStamp[4] = ptime->tm_sec;exifApp1Info->gpsTimeStamp[5] = 1;if (0 > snprintf((char *)exifApp1Info->gpsDateStamp, sizeof(exifApp1Info->gpsDateStamp),"%04d:%02d:%02d", ptime->tm_year + 1900, ptime->tm_mon + 1, ptime->tm_mday)) {MY_LOGW("snprintf failed");}} else {MY_LOGD("gmtime might not be implemented");}}else{MY_LOGE("wrong timestamp(%lld)", timestamp);}// ProcessingMethodconst char exifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; // ASCIIint len1, len2, maxLen;len1 = sizeof(exifAsciiPrefix);memcpy(exifApp1Info->gpsProcessingMethod, exifAsciiPrefix, len1);maxLen = sizeof(exifApp1Info->gpsProcessingMethod) - len1;len2 = strlen(pgpsProcessingMethod);if (len2 > maxLen) {len2 = maxLen;}memcpy(&exifApp1Info->gpsProcessingMethod[len1], pgpsProcessingMethod, len2);}/*********************************************************************************common**********************************************************************************/// software informationmemset(exifApp1Info->strSoftware, 0, 32);char _strSoftware[] =  "MediaTek Camera Application";strncpy((char *)exifApp1Info->strSoftware, "MediaTek Camera Application", sizeof(_strSoftware)/sizeof(char));// get datetime// [SubsecTime]// convert microsecond to second// if microsecond is not full 6 digits, it will be filled with "0" from headstruct tm *tm;if ((tm = localtime(&mExifParam.seconds)) != NULL){size_t stret = strftime((char *)exifApp1Info->strDateTime,sizeof(exifApp1Info->strDateTime), "%Y:%m:%d %H:%M:%S", tm);if (stret == 0) {MY_LOGE("strftime failed!");}int snpret = 0;snpret = snprintf((char *)exifApp1Info->strSubSecTime,sizeof(exifApp1Info->strSubSecTime), "%06ld\n", mExifParam.microSeconds);if (snpret < 0) {MY_LOGE("snprintf failed!");}MY_LOGI("strDateTime(%s), strSubSecTime(%s)", exifApp1Info->strDateTime, exifApp1Info->strSubSecTime);}// [digital zoom ratio]exifApp1Info->digitalZoomRatio[0] = (unsigned int)mExifParam.u4ZoomRatio;exifApp1Info->digitalZoomRatio[1] = 100;// [orientation]exifApp1Info->orientation = (unsigned short)determineExifOrientation(mExifParam.u4Orientation,mExifParam.u4Facing);/*********************************************************************************3A**********************************************************************************/// [f number]//// [max aperture value]// aperture value = 2 log2(f number)exifApp1Info->fnumber[0] = (unsigned int)mExifParam.u4FNumber;exifApp1Info->fnumber[1] = FNUMBER_PRECISION;double apertureValue = 2 * log(mExifParam.u4FNumber / FNUMBER_PRECISION) / log(2);exifApp1Info->maxApertureValue[0] = static_cast<unsigned int>(apertureValue * 100);exifApp1Info->maxApertureValue[1] = 100;// [focal length]exifApp1Info->focalLength[0] = (unsigned int)mExifParam.u4FocalLength;exifApp1Info->focalLength[1] = 1000;// [35mm focal length]exifApp1Info->focalLength35mm = (unsigned short)mExifParam.u4FocalLength35mm;// [iso speed]// For super high ISO case(>65535), the isoSpeedRatings will be equal to 65535 due to its SHORT type// Therefore, we record real ISO value in another variable isoSpeed, which is also EXIF_TAG_RECOMMENDEDEXPOSUREINDEX// isoType indicates the tag we use for recording real ISO value, and we use EXIF_TAG_RECOMMENDEDEXPOSUREINDEX here which isoType = 2// isoType: 1=StandardOutputSensitivity, 2=RecommendedExposureIndex, 3=ISOSpeedif ( mExifParam.u4AEISOSpeed > 65535) {exifApp1Info->isoSpeedRatings = 65535;exifApp1Info->isoType = 2;exifApp1Info->isoSpeed = (unsigned int)mExifParam.u4AEISOSpeed;} else {exifApp1Info->isoSpeedRatings = (unsigned short)mExifParam.u4AEISOSpeed;}// [exposure time]//// [shutter speed value]// shutterspeedvalue = -log2(exp time)if(mExifParam.u4CapExposureTime == 0){//YUV sensorexifApp1Info->exposureTime[0] = 0;exifApp1Info->exposureTime[1] = 0;exifApp1Info->shutterSpeed[0] = 0;exifApp1Info->shutterSpeed[1] = 0;}else{// RAW sensorif (mExifParam.u4CapExposureTime > 1000000) { //1 secexifApp1Info->exposureTime[0] = mExifParam.u4CapExposureTime / 100000;exifApp1Info->exposureTime[1] = 10;}else{ // usexifApp1Info->exposureTime[0] = mExifParam.u4CapExposureTime;exifApp1Info->exposureTime[1] = 1000000;}double shutterSpeedValue = log(1000000/mExifParam.u4CapExposureTime) / log(2);exifApp1Info->shutterSpeed[0] = static_cast<unsigned int>(shutterSpeedValue * 1000);exifApp1Info->shutterSpeed[1] = 1000;}// [flashlight]// bit coding of the exif flash tag//         |6|5|4|3|2|1|0|//// use 0~6 bit determine the flash value// 0: indicates the flash firing status(on, off)// 1,2: indicates the flash return status// 3,4: indicates the flash mode(auto, compulsory)// 5: indicates the flash function// 6: indicates the red eye modeexifApp1Info->flash = (mExifParam.u4FlashFiringStatus << FLASH_FIRING_STATUS_SHIFT |mExifParam.u4FlashReturnDetect << FLASH_RETURN_DETECT_SHIFT |mExifParam.u4FlashMode << FLASH_MODE_SHIFT |mExifParam.u4FlashFunction << FLASH_SUPPORT_SHIFT |mExifParam.u4FlashRedEye << FLASH_REDEYE_SHIFT);// [white balance mode]exifApp1Info->whiteBalanceMode = mExifParam.u4AWBMode;// [light source]exifApp1Info->lightSource = mExifParam.u4LightSource;// [metering mode]exifApp1Info->meteringMode = mExifParam.u4AEMeterMode;// [exposure program] , [scene mode]exifApp1Info->exposureProgram  = mExifParam.u4ExpProgram;exifApp1Info->sceneCaptureType = mExifParam.u4SceneCapType;// [Brightness value]exifApp1Info->brightness[0] = mExifParam.i4Brightness;exifApp1Info->brightness[1] = 10;// [Ev offset]exifApp1Info->exposureBiasValue[0] = (unsigned int)mExifParam.i4AEExpBias;exifApp1Info->exposureBiasValue[1] = 10;/*********************************************************************************update customized exif**********************************************************************************/{char make[PROPERTY_VALUE_MAX] = {'\0'};char model[PROPERTY_VALUE_MAX] = {'\0'};property_get("ro.product.manufacturer", make, "0");property_get("ro.product.model", model, "0");MY_LOGI("property: make(%s), model(%s)", make, model);// [Make]if ( ::strcmp(make, "0") != 0 ) {::memset(exifApp1Info->strMake, 0, 32);::strncpy((char*)exifApp1Info->strMake, (const char*)make, 31);}// [Model]if ( ::strcmp(model, "0") != 0 ) {::memset(exifApp1Info->strModel, 0, 32);::strncpy((char*)exifApp1Info->strModel, (const char*)model, 31);}}/*********************************************************************************MISC**********************************************************************************/// [flashPixVer]memcpy(exifApp1Info->strFlashPixVer, "0100 ", 5);// [exposure mode]exifApp1Info->exposureMode = 0;  // 0 means Auto exposure}

可以看到有GPS、common、3A相关exif信息被写入,同时还有软件来源_strSoftware[] = "MediaTek Camera Application"以及最后的自定义系统属性等。

MTK平台Camera图片的Exif信息相关推荐

  1. 获取图片的EXIF信息如此困难?

    对于数码相机所拍摄出的图片,Exif信息非常重要.Exif是英语Exchangeable Image File(可交换图像文件)的缩写,最初由日本电子工业发展协会(JEIDA --Japan Elec ...

  2. C# 获取图片的EXIF 信息

    关于 EXIF 信息的介绍. 1  EXIF,是英文Exchangeable Image File(可交换图像文件)的缩写.EXIF是一种图像文件格式,只是文件的后缀名为jpg.EXIF信息是由数码相 ...

  3. php exif信息,php通过exif_read_data函数获取图片的exif信息

    php获取图片的exif信息,php自带一个exif_read_data函数可以用来读取图片的exif信息,代码来自php手册 echo "test1.jpg: \n"; $exi ...

  4. python相机拍照显示时间_python让图片按照exif信息里的创建时间进行排序的方法...

    本文实例讲述了python让图片按照exif信息里的创建时间进行排序的方法.分享给大家供大家参考.具体分析如下: 我们经常会从不同的设备里取出照片,比如照相机,手机,iphone等等,操作系统记录的创 ...

  5. php exif信息,php如何给jpg图片写入exif信息?

    在写一个php把图片方向根据exif旋转过来的功能,功能是做好了,但是旋转之后的图片文件exif信息都没了,因为我用imagejpeg重写了图片,请问怎么把exif写回去? 贴一下我旋转图片的代码: ...

  6. JS获取图片的EXIF信息+纠正图片方向

    前端图片处理碰到的一个离奇 bug , 关于图片的 EXIF 信息,特地记录下来 . 然后使用一下代码可以获取Orientation信息,并纠正Orientation带来的图片旋转问题 // from ...

  7. php exif信息,php通过exif_read_data函数获取图片的exif信息_php技巧

    php获取图片的exif信息,php自带一个exif_read_data函数可以用来读取图片的exif信息,代码来自php手册 \n"; $exif = exif_read_data('te ...

  8. 零基础学习MTK平台camera引脚配置

    目录 一.MTK平台的GPIO配置 1. MTK平台GPIO驱动程序提供了两个接口: 2.配置dws文件 3.配置dts文件 二.MTK平台camera模块的GPIO配置 一.MTK平台的GPIO配置 ...

  9. [转]数码照片的JPG文件高级信息(用C#读取图片的EXIF信息)

    [转]数码照片的JPG文件高级信息(用C#读取图片的EXIF信息) 数码相机的照片很多,而且文件名也不直观,所以写了个程序批量改名,就是把文件名都改成相机的拍照日期,呵呵,谁知道拍照日期不是那么好取, ...

  10. 在Android下通过ExifInterface类操作图片的Exif信息

    什么是Exif 先来了解什么是Exif.Exif是一种图像文件格式,它的数据存储于JPEG格式是完全相同的,实际上Exif格式就是JPEG格式头插入了 数码照片的信息,包括拍摄的光圈.快门.平衡白.I ...

最新文章

  1. react 开发过程中的总结/归纳
  2. 全球43亿IPv4地址正式耗尽,IPv6才是物联网的菜
  3. 论分层思想在各行各业的应用
  4. JSON字符串key缺少双引号的解决方法
  5. 存储基础知识一 主要技术DAS、SAN、NAS
  6. 白话Elasticsearch04- 结构化搜索之使用terms query搜索多个值以及多值搜索结果优化
  7. kafka-eagle报错解决:Kafka version is “-“ or JMX Port is “-1“ maybe kafka broker jmxport disable.
  8. 【小米校招笔试】假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友...),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈。
  9. 加载中...loading... 图片_搞笑图片:小子这就是你单身的原因...
  10. npoi 未将对象引用设置到对象的实例_new一个对象到底占了多少内存?
  11. 计算机工作原理_学堂第九课|计算机内部的工作原理
  12. 常见概率抽样方法及其适用场景总结(简单随机抽样、分层抽样、整群抽样、系统抽样)
  13. [百度百科]英语状语
  14. 正则html在线测试,正则作业.html
  15. 江苏省普通高校“专转本”选拔考试 计算机专业大类专业综合基础理论考试大纲
  16. html控制两个页面转换,html页面切换过度效果实现方案_蓝戒的博客
  17. 设备配网专题《原理分析,设备配网技术之AirKiss微信配网》
  18. 小程序无限插屏广告实现方法
  19. python追踪屏幕的移动目标_利用树莓派和Python建立一个简单、便宜的移动目标探测器...
  20. dllimport和dllexport作用与区别

热门文章

  1. 新媒体运营数据分析怎么做?
  2. windows平台HTTP代理服务器搭建(CCproxy)
  3. 敬伟PS教程:基础篇A
  4. SDN先行开拓者们获得可视性和带宽控制
  5. 我去!微信竟然可以查出行轨迹了,预计又一波情侣要分手?
  6. 英特尔应用PC业真的已经走到了穷途末路?
  7. unity点光源消失
  8. win11如何备份系统 Windows11备份系统的设置方法
  9. APICloud AVM框架 开发CRM客户管理系统
  10. ENVI添加指北针/比例尺