鸿蒙OSUniApp 实现图片上传与压缩功能#三方框架 #Uniapp

news2025/5/19 19:37:46

UniApp 实现图片上传与压缩功能

前言

在移动应用开发中,图片上传是一个非常常见的需求。无论是用户头像、朋友圈图片还是商品图片,都需要上传到服务器。但移动设备拍摄的图片往往尺寸较大,直接上传会导致流量消耗过大、上传时间过长,影响用户体验。因此,图片压缩成为了移动应用开发中的必备技能。

通过 UniApp 实现图片上传与压缩功能,既能满足用户体验需求,又能减轻服务器负担。今天就来分享一下我在实际项目中使用的图片上传与压缩方案,希望能对大家有所帮助。

技术方案分析

在 UniApp 中实现图片上传与压缩,主要涉及以下几个方面:

  1. 图片选择:通过 uni.chooseImage() 实现
  2. 图片压缩:通过 canvas 实现
  3. 图片上传:通过 uni.uploadFile() 实现

这个方案的优点是:

  • 压缩在客户端进行,减轻了服务器压力
  • 减少了网络流量,提高了上传速度
  • 可以根据不同场景设置不同的压缩参数

具体实现

1. 图片选择

首先实现图片选择功能:

// 选择图片
chooseImage() {
  return new Promise((resolve, reject) => {
    uni.chooseImage({
      count: 9, // 最多可选择的图片张数
      sizeType: ['original', 'compressed'], // 可选择原图或压缩后的图片
      sourceType: ['album', 'camera'], // 从相册选择或使用相机拍摄
      success: (res) => {
        resolve(res.tempFilePaths);
      },
      fail: (err) => {
        reject(err);
      }
    });
  });
}

2. 图片压缩实现

压缩图片是整个功能的核心,我们使用 canvas 来实现:

/**
 * 图片压缩
 * @param {String} src 图片路径
 * @param {Number} quality 压缩质量(0-1)
 * @param {Number} maxWidth 最大宽度
 * @param {Number} maxHeight 最大高度
 */
compressImage(src, quality = 0.8, maxWidth = 800, maxHeight = 800) {
  return new Promise((resolve, reject) => {
    // 获取图片信息
    uni.getImageInfo({
      src: src,
      success: (imgInfo) => {
        // 计算压缩后的尺寸
        let width = imgInfo.width;
        let height = imgInfo.height;
        
        // 等比例缩放
        if (width > maxWidth || height > maxHeight) {
          const ratio = Math.max(width / maxWidth, height / maxHeight);
          width = Math.floor(width / ratio);
          height = Math.floor(height / ratio);
        }
        
        // 创建canvas上下文
        const ctx = uni.createCanvasContext('compressCanvas', this);
        
        // 绘制图片到canvas
        ctx.drawImage(src, 0, 0, width, height);
        
        // 将canvas转为图片
        ctx.draw(false, () => {
          setTimeout(() => {
            uni.canvasToTempFilePath({
              canvasId: 'compressCanvas',
              fileType: 'jpg',
              quality: quality,
              success: (res) => {
                // 获取压缩后的图片路径
                resolve(res.tempFilePath);
              },
              fail: (err) => {
                reject(err);
              }
            }, this);
          }, 300); // 延迟确保canvas绘制完成
        });
      },
      fail: (err) => {
        reject(err);
      }
    });
  });
}

在页面中需要添加对应的 canvas 元素:

<canvas canvas-id="compressCanvas" style="width: 0px; height: 0px; position: absolute; left: -1000px; top: -1000px;"></canvas>

3. 图片上传实现

图片上传时,我们往往需要添加额外的参数,比如表单字段、用户 token 等:

/**
 * 上传图片到服务器
 * @param {String} filePath 图片路径
 * @param {String} url 上传地址
 * @param {Object} formData 附加数据
 */
uploadFile(filePath, url, formData = {}) {
  return new Promise((resolve, reject) => {
    uni.uploadFile({
      url: url,
      filePath: filePath,
      name: 'file', // 服务器接收的字段名
      formData: formData,
      header: {
        // 可以添加自定义 header,如 token
        'Authorization': 'Bearer ' + uni.getStorageSync('token')
      },
      success: (res) => {
        // 这里需要注意,返回的数据是字符串,需要手动转为 JSON
        let data = JSON.parse(res.data);
        resolve(data);
      },
      fail: (err) => {
        reject(err);
      }
    });
  });
}

4. 完整的上传流程

将以上三个步骤组合,实现完整的图片上传流程:

// 实现完整的上传流程
async handleUpload() {
  try {
    // 显示加载提示
    uni.showLoading({
      title: '上传中...',
      mask: true
    });
    
    // 选择图片
    const imagePaths = await this.chooseImage();
    
    // 用于存储上传结果
    const uploadResults = [];
    
    // 循环处理每张图片
    for (let i = 0; i < imagePaths.length; i++) {
      // 压缩图片
      const compressedPath = await this.compressImage(
        imagePaths[i],
        0.7,  // 压缩质量
        800,  // 最大宽度
        800   // 最大高度
      );
      
      // 获取原图和压缩后的图片大小进行对比
      const originalInfo = await this.getFileInfo(imagePaths[i]);
      const compressedInfo = await this.getFileInfo(compressedPath);
      
      console.log(`原图大小: ${(originalInfo.size / 1024).toFixed(2)}KB, 压缩后: ${(compressedInfo.size / 1024).toFixed(2)}KB`);
      
      // 上传压缩后的图片
      const uploadResult = await this.uploadFile(
        compressedPath,
        'https://your-api.com/upload',
        {
          type: 'avatar', // 附加参数
          userId: this.userId
        }
      );
      
      uploadResults.push(uploadResult);
    }
    
    // 隐藏加载提示
    uni.hideLoading();
    
    // 提示上传成功
    uni.showToast({
      title: '上传成功',
      icon: 'success'
    });
    
    // 返回上传结果
    return uploadResults;
    
  } catch (error) {
    uni.hideLoading();
    uni.showToast({
      title: '上传失败',
      icon: 'none'
    });
    console.error('上传错误:', error);
  }
}

// 获取文件信息
getFileInfo(filePath) {
  return new Promise((resolve, reject) => {
    uni.getFileInfo({
      filePath: filePath,
      success: (res) => {
        resolve(res);
      },
      fail: (err) => {
        reject(err);
      }
    });
  });
}

进阶优化

以上代码已经可以基本满足图片上传与压缩需求,但在实际项目中,我们还可以进一步优化:

1. 添加图片预览功能

在上传前,通常需要让用户预览选择的图片:

// 预览图片
previewImage(current, urls) {
  uni.previewImage({
    current: current, // 当前显示图片的路径
    urls: urls, // 需要预览的图片路径列表
    indicator: 'number',
    loop: true
  });
}

2. 使用 uniCloud 上传

如果你使用 uniCloud 作为后端服务,可以利用其提供的云存储功能简化上传流程:

// 使用 uniCloud 上传
async uploadToUniCloud(filePath) {
  try {
    const result = await uniCloud.uploadFile({
      filePath: filePath,
      cloudPath: 'images/' + Date.now() + '.jpg'
    });
    return result.fileID; // 返回文件ID
  } catch (error) {
    throw error;
  }
}

3. 添加上传进度显示

对于大图片,添加上传进度能提升用户体验:

uploadFileWithProgress(filePath, url, formData = {}) {
  return new Promise((resolve, reject) => {
    const uploadTask = uni.uploadFile({
      url: url,
      filePath: filePath,
      name: 'file',
      formData: formData,
      success: (res) => {
        let data = JSON.parse(res.data);
        resolve(data);
      },
      fail: (err) => {
        reject(err);
      }
    });
    
    uploadTask.onProgressUpdate((res) => {
      console.log('上传进度', res.progress);
      // 更新进度条
      this.uploadProgress = res.progress;
    });
  });
}

4. 针对鸿蒙系统的适配

随着国产操作系统鸿蒙的普及,我们也需要考虑在鸿蒙系统上的兼容性。虽然目前 UniApp 官方还没有专门针对鸿蒙系统的适配文档,但我们可以通过一些方法来优化:

// 检测当前系统
checkSystem() {
  const systemInfo = uni.getSystemInfoSync();
  console.log('当前系统:', systemInfo.platform);
  
  // 鸿蒙系统目前会被识别为 android,可以通过 brand 和 model 辅助判断
  const isHarmonyOS = systemInfo.brand === 'HUAWEI' && /HarmonyOS/i.test(systemInfo.system);
  
  if (isHarmonyOS) {
    console.log('当前是鸿蒙系统');
    // 针对鸿蒙系统进行特殊处理
    // 例如:调整压缩参数、使用不同的 API 等
  }
  
  return systemInfo;
}

根据我的测试,在鸿蒙系统上,有时 canvas 绘制需要更长的延迟时间,可以适当调整:

// 针对鸿蒙系统的 canvas 延迟调整
const delay = isHarmonyOS ? 500 : 300;
setTimeout(() => {
  uni.canvasToTempFilePath({
    // 配置项...
  });
}, delay);

实际案例

下面是一个完整的实际案例,用于实现商品发布页面的图片上传功能:

<template>
  <view class="container">
    <view class="image-list">
      <!-- 已选图片预览 -->
      <view 
        class="image-item" 
        v-for="(item, index) in imageList" 
        :key="index"
      >
        <image :src="item.path" mode="aspectFill" @tap="previewImage(index)"></image>
        <view class="delete-btn" @tap.stop="deleteImage(index)">×</view>
      </view>
      
      <!-- 添加图片按钮 -->
      <view class="add-image" @tap="handleAddImage" v-if="imageList.length < 9">
        <text class="add-icon">+</text>
        <text class="add-text">添加图片</text>
      </view>
    </view>
    
    <!-- 上传按钮 -->
    <button class="upload-btn" @tap="submitUpload" :disabled="imageList.length === 0">
      上传图片 ({{imageList.length}}/9)
    </button>
    
    <!-- 压缩画布(隐藏) -->
    <canvas canvas-id="compressCanvas" style="width: 0px; height: 0px; position: absolute; left: -1000px; top: -1000px;"></canvas>
    
    <!-- 上传进度条 -->
    <view class="progress-bar" v-if="isUploading">
      <view class="progress-inner" :style="{width: uploadProgress + '%'}"></view>
      <text class="progress-text">{{uploadProgress}}%</text>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      imageList: [], // 已选图片列表
      isUploading: false, // 是否正在上传
      uploadProgress: 0, // 上传进度
      isHarmonyOS: false // 是否鸿蒙系统
    };
  },
  onLoad() {
    // 检测系统
    const systemInfo = this.checkSystem();
    this.isHarmonyOS = systemInfo.brand === 'HUAWEI' && /HarmonyOS/i.test(systemInfo.system);
  },
  methods: {
    // 添加图片
    async handleAddImage() {
      try {
        const imagePaths = await this.chooseImage();
        
        // 添加到图片列表
        for (let path of imagePaths) {
          this.imageList.push({
            path: path,
            compressed: false,
            compressedPath: '',
            uploaded: false,
            fileID: ''
          });
        }
      } catch (error) {
        console.error('选择图片失败:', error);
      }
    },
    
    // 预览图片
    previewImage(index) {
      const urls = this.imageList.map(item => item.path);
      uni.previewImage({
        current: this.imageList[index].path,
        urls: urls
      });
    },
    
    // 删除图片
    deleteImage(index) {
      this.imageList.splice(index, 1);
    },
    
    // 提交上传
    async submitUpload() {
      if (this.imageList.length === 0) {
        uni.showToast({
          title: '请至少选择一张图片',
          icon: 'none'
        });
        return;
      }
      
      this.isUploading = true;
      this.uploadProgress = 0;
      
      uni.showLoading({
        title: '准备上传...',
        mask: true
      });
      
      try {
        // 上传结果
        const uploadResults = [];
        
        // 总进度
        let totalProgress = 0;
        
        // 遍历所有图片进行压缩和上传
        for (let i = 0; i < this.imageList.length; i++) {
          let item = this.imageList[i];
          
          // 如果还没压缩过,先压缩
          if (!item.compressed) {
            uni.showLoading({
              title: `压缩第 ${i+1}/${this.imageList.length} 张图片`,
              mask: true
            });
            
            try {
              const compressedPath = await this.compressImage(
                item.path,
                0.7,
                800,
                800
              );
              
              // 更新图片信息
              this.imageList[i].compressed = true;
              this.imageList[i].compressedPath = compressedPath;
              
              // 获取压缩前后的大小对比
              const originalInfo = await this.getFileInfo(item.path);
              const compressedInfo = await this.getFileInfo(compressedPath);
              
              console.log(`图片 ${i+1}: 原图 ${(originalInfo.size / 1024).toFixed(2)}KB, 压缩后 ${(compressedInfo.size / 1024).toFixed(2)}KB, 压缩率 ${((1 - compressedInfo.size / originalInfo.size) * 100).toFixed(2)}%`);
              
            } catch (error) {
              console.error(`压缩第 ${i+1} 张图片失败:`, error);
              // 如果压缩失败,使用原图
              this.imageList[i].compressedPath = item.path;
              this.imageList[i].compressed = true;
            }
          }
          
          // 准备上传
          uni.showLoading({
            title: `上传第 ${i+1}/${this.imageList.length} 张图片`,
            mask: true
          });
          
          try {
            // 使用压缩后的图片路径,如果没有则使用原图
            const fileToUpload = item.compressedPath || item.path;
            
            // 上传图片
            const result = await this.uploadFileWithProgress(
              fileToUpload,
              'https://your-api.com/upload',
              {
                type: 'product',
                index: i
              }
            );
            
            // 更新图片信息
            this.imageList[i].uploaded = true;
            this.imageList[i].fileID = result.fileID || result.url;
            
            uploadResults.push(result);
            
            // 更新总进度
            totalProgress = Math.floor((i + 1) / this.imageList.length * 100);
            this.uploadProgress = totalProgress;
            
          } catch (error) {
            console.error(`上传第 ${i+1} 张图片失败:`, error);
            uni.showToast({
              title: `第 ${i+1} 张图片上传失败`,
              icon: 'none'
            });
          }
        }
        
        uni.hideLoading();
        this.isUploading = false;
        
        uni.showToast({
          title: '所有图片上传完成',
          icon: 'success'
        });
        
        // 返回上传结果,可以传给父组件或进行后续处理
        this.$emit('uploadComplete', uploadResults);
        
      } catch (error) {
        uni.hideLoading();
        this.isUploading = false;
        console.error('上传过程出错:', error);
        uni.showToast({
          title: '上传失败,请重试',
          icon: 'none'
        });
      }
    },
    
    // 其他方法实现(chooseImage, compressImage, uploadFile等,同前面的实现)
  }
};
</script>

<style lang="scss">
.container {
  padding: 20rpx;
}

.image-list {
  display: flex;
  flex-wrap: wrap;
}

.image-item {
  width: 220rpx;
  height: 220rpx;
  margin: 10rpx;
  position: relative;
  border-radius: 8rpx;
  overflow: hidden;
  
  image {
    width: 100%;
    height: 100%;
  }
  
  .delete-btn {
    position: absolute;
    top: 0;
    right: 0;
    width: 44rpx;
    height: 44rpx;
    background-color: rgba(0, 0, 0, 0.5);
    color: #ffffff;
    text-align: center;
    line-height: 44rpx;
    font-size: 32rpx;
    z-index: 10;
  }
}

.add-image {
  width: 220rpx;
  height: 220rpx;
  margin: 10rpx;
  background-color: #f5f5f5;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  border-radius: 8rpx;
  border: 1px dashed #dddddd;
  
  .add-icon {
    font-size: 60rpx;
    color: #999999;
  }
  
  .add-text {
    font-size: 24rpx;
    color: #999999;
    margin-top: 10rpx;
  }
}

.upload-btn {
  margin-top: 40rpx;
  background-color: #007aff;
  color: #ffffff;
  border-radius: 8rpx;
  
  &:disabled {
    background-color: #cccccc;
  }
}

.progress-bar {
  margin-top: 30rpx;
  height: 40rpx;
  background-color: #f5f5f5;
  border-radius: 20rpx;
  overflow: hidden;
  position: relative;
  
  .progress-inner {
    height: 100%;
    background-color: #007aff;
    transition: width 0.3s;
  }
  
  .progress-text {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 24rpx;
    color: #ffffff;
  }
}
</style>

鸿蒙系统适配经验

前面已经简单提到了鸿蒙系统的适配,下面来详细说一下我在实际项目中遇到的问题和解决方案:

  1. 画布延迟问题:在鸿蒙系统上,canvas 绘制后转图片需要更长的延迟时间,建议延长 setTimeout 时间。

  2. 文件系统差异:有些文件路径的处理方式可能与 Android 有所不同,建议使用 UniApp 提供的 API 进行文件操作,而不要直接操作路径。

  3. 图片格式支持:在鸿蒙系统上,对 WebP 等格式的支持可能有限,建议统一使用 JPG 或 PNG 格式。

  4. 内存管理:鸿蒙系统对内存的管理略有不同,处理大图片时需要注意内存释放。可以在完成上传后,主动清空临时图片:

// 清空临时文件
clearTempFiles() {
  for (let item of this.imageList) {
    // 如果存在压缩后的临时文件,尝试删除
    if (item.compressedPath && item.compressedPath !== item.path) {
      uni.removeSavedFile({
        filePath: item.compressedPath,
        complete: () => {
          console.log('清理临时文件');
        }
      });
    }
  }
}

总结

通过本文介绍的方法,我们可以在 UniApp 中实现图片上传与压缩功能,主要包括以下几个步骤:

  1. 使用 uni.chooseImage() 选择图片
  2. 使用 canvas 进行图片压缩
  3. 使用 uni.uploadFile() 上传图片
  4. 添加进度显示和预览功能
  5. 针对鸿蒙系统做特殊适配

在实际项目中,可以根据需求调整压缩参数,比如对头像类图片可以压缩得更小,而对需要展示细节的商品图片,可以保留更高的质量。

希望本文能够帮助大家更好地实现 UniApp 中的图片上传与压缩功能。如果有任何问题或建议,欢迎在评论区交流讨论!

参考资料

  1. UniApp 官方文档:https://uniapp.dcloud.io/
  2. Canvas API 参考:https://uniapp.dcloud.io/api/canvas/CanvasContext

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2379492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

科技项目验收测试对软件产品和企业分别有哪些好处?

科技项目验收测试是指在项目的开发周期结束后&#xff0c;针对项目成果进行的一系列验证和确认活动。其目的是确保终交付的产品或系统符合预先设定的需求和标准。验收测试通常包括功能测试、性能测试、安全测试等多个方面&#xff0c;帮助企业评估软件在实际应用中的表现。 科…

汽车零部件冲压车间MES一体机解决方案

在当前制造业升级的大背景下&#xff0c;提升生产效率、实现精细化管理已成为企业竞争力的关键。特别是在汽车零部件制造领域&#xff0c;冲压车间作为生产流程中的重要一环&#xff0c;其生产数据的实时采集与分析对于确保产品质量、优化生产节拍、降低运营成本至关重要。今天…

hysAnalyser 从MPEG-TS导出ES功能说明

摘要 hysAnalyser 是一款特色的 MPEG-TS 数据分析工具。本文主要介绍了 hysAnalyser 从MPEG-TS 中导出选定的 ES 或 PES 功能(版本v1.0.003)&#xff0c;以便用户知悉和掌握这些功能&#xff0c;帮助分析和解决各种遇到ES或PES相关的实际问题。hysAnalyser 支持主流的MP1/MP2/…

家里wifi不能上网或莫名跳转到赌博及色情网站就是域名被劫持、DNS被污染了

文章目录 定义上网过程域名被劫持可能阶段案例排查工具 解决方法清除系统DNS缓存查看DNS缓存清除DNS缓存 登录路由器&#xff0c;设置DNS可用的DNS地址&#xff1a; 找网络运营商报警 定义 DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;劫持&#xff0c…

基于SSM实现的健身房系统功能实现十六

一、前言介绍&#xff1a; 1.1 项目摘要 随着社会的快速发展和人们健康意识的不断提升&#xff0c;健身行业也在迅速扩展。越来越多的人加入到健身行列&#xff0c;健身房的数量也在不断增加。这种趋势使得健身房的管理变得越来越复杂&#xff0c;传统的手工或部分自动化的管…

【Java微服务组件】分布式协调P1-数据共享中心简单设计与实现

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 欢迎评论交流&#xff0c;感谢您的阅读&#x1f604;。 目录 引言设计一个共享数据中心选择数据模型键值对设计 数据可靠性设计持久化快照 &#xff08…

cursor/vscode启动项目connect ETIMEDOUT 127.0.0.1:xx

现象&#xff1a; 上午正常使用cursor/vscode&#xff0c;因为需要写前端安装了nodejs16.20和vue2&#xff0c;结果下午启动前端服务无法访问&#xff0c;浏览器一直转圈。接着测试运行最简单的flask服务&#xff0c;vscode报错connect ETIMEDOUT 127.0.0.1:xx&#xff0c;要么…

兼顾长、短视频任务的无人机具身理解!AirVista-II:面向动态场景语义理解的无人机具身智能体系统

作者&#xff1a;Fei Lin 1 ^{1} 1, Yonglin Tian 2 ^{2} 2, Tengchao Zhang 1 ^{1} 1, Jun Huang 1 ^{1} 1, Sangtian Guan 1 ^{1} 1, and Fei-Yue Wang 2 , 1 ^{2,1} 2,1单位&#xff1a; 1 ^{1} 1澳门科技大学创新工程学院工程科学系&#xff0c; 2 ^{2} 2中科院自动化研究所…

20250515配置联想笔记本电脑IdeaPad总是使用独立显卡的步骤

20250515配置联想笔记本电脑IdeaPad总是使用独立显卡的步骤 2025/5/15 19:55 百度&#xff1a;intel 集成显卡 NVIDIA 配置成为 总是用独立显卡 百度为您找到以下结果 ?要将Intel集成显卡和NVIDIA独立显卡配置为总是使用独立显卡&#xff0c;可以通过以下步骤实现?&#xff…

sparkSQL读入csv文件写入mysql

思路 示例 &#xff08;年龄>18改成>20) mysql的字符集问题 把user改成person “让字符集认识中文”

大涡模拟实战:从区域尺度到街区尺度的大气环境模拟

前言&#xff1a; 随着低空经济的蓬勃发展&#xff0c;无人机、空中出租车等新型交通工具正在重塑我们的城市空间。这场静默的革命不仅带来了经济机遇&#xff0c;更对城市大气环境提出了全新挑战。在距离地面200米以下的城市冠层中&#xff0c;建筑物与大气的复杂相互作用、人…

单目测距和双目测距 bev 3D车道线

单目视觉测距原理 单目视觉测距有两种方式。 第一种&#xff0c;是通过深度神经网络来预测深度&#xff0c;这需要大量的训练数据。训练后的单目视觉摄像头可以认识道路上最典型的参与者——人、汽车、卡车、摩托车&#xff0c;或是其他障碍物&#xff08;雪糕桶之类&#xf…

Web开发-JavaEE应用SpringBoot栈SnakeYaml反序列化链JARWAR构建打包

知识点&#xff1a; 1、安全开发-JavaEE-WAR&JAR打包&反编译 2、安全开发-JavaEE-SnakeYaml反序列化&链 一、演示案例-WEB开发-JavaEE-项目-SnakeYaml序列化 常见的创建的序列化和反序列化协议 • &#xff08;已讲&#xff09;JAVA内置的writeObject()/readObje…

项目复习(2)

第四天 高并发优化 前端每隔15秒就发起一次请求&#xff0c;将播放记录写入数据库。 但问题是&#xff0c;提交播放记录的业务太复杂了&#xff0c;其中涉及到大量的数据库操作&#xff1a;在并发较高的情况下&#xff0c;会给数据库带来非常大的压力 使用Redis合并写请求 一…

UE 材质基础 第一天

课程&#xff1a;虚幻引擎【UE5】材质宝典【初学者材质基础入门系列】-北冥没有鱼啊_-稍后再看-哔哩哔哩视频 随便记录一些 黑色是0到负无穷&#xff0c;白色是1到无穷 各向异性 有点类似于高光&#xff0c;可以配合切线来使用&#xff0c;R G B 相当于 X Y Z轴&#xff0c;切…

学习FineBI

FineBI 第一章 FineBI 介绍 1.1. FineBI 概述 FineBI 是帆软软件有限公司推出的一款商业智能 &#xff08;Business Intelligence&#xff09; 产品 。 FineBI 是新一代大数据分析的 BI 工具 &#xff0c; 旨在帮助企业的业务人员充分了解和利用他们的数据 。FineBI 凭借强…

深入剖析某App视频详情逆向:聚焦sig3参数攻克

深入剖析某手App视频详情逆向&#xff1a;聚焦sig3参数攻克 一、引言 在当今互联网信息爆炸的时代&#xff0c;短视频平台如某手&#xff0c;已成为人们获取信息、娱乐消遣的重要渠道。对于技术爱好者和研究人员而言&#xff0c;深入探索其内部机制&#xff0c;特别是视频详情…

【Linux】Linux安装并配置MongoDB

目录 1.添加仓库 2.安装 MongoDB 包 3.启动 MongoDB 服务 4. 验证安装 5.配置 5.1.进入无认证模式 5.2.1创建用户 5.2.2.开启认证 5.2.3重启 5.2.4.登录 6.端口变更 7.卸载 7.1.停止 MongoDB 服务 7.2.禁用 MongoDB 开机自启动 7.3.卸载 MongoDB 包 7.4.删除数…

新电脑软件配置二:安装python,git, pycharm

安装python 地址 https://www.python.org/downloads/ 不是很懂为什么这么多版本 安装windows64位的 这里我是凭自己感觉装的了 然后cmd输入命令没有生效&#xff0c;先重启下&#xff1f; 重启之后再次验证 环境是成功的 之前是输入的python -version 命令输入错误 安装pyc…

数据仓库:企业数据管理的核心引擎

一、数据仓库的由来 数据仓库&#xff08;Data Warehouse, DW&#xff09;概念的诞生源于企业对数据价值的深度挖掘需求。在1980年代&#xff0c;随着OLTP&#xff08;联机事务处理&#xff09;系统在企业中的普及&#xff0c;传统关系型数据库在处理海量数据分析时显露出明显瓶…