首页 > 其他分享 >【解决方案】harmonyOS 图片压缩

【解决方案】harmonyOS 图片压缩

时间:2024-08-18 10:51:36浏览次数:10  
标签:const 缩放 解决方案 压缩 harmonyOS packing image 图片

图片压缩在应用开发中是一个非常常见的需求,特别是在处理用户上传图片时,需要上传指定大小以内的图片。目前图片压缩支持jpeg、webp、png格式。本例中以jpeg图片为例介绍如何通过packing和scale实现图片压缩到目标大小以内

使用说明

  1. 进入页面,输入图片压缩目标大小,点击“图片压缩”按钮查看压缩后的图片。效果图中输入图片压缩目标大小为10kb,实际压缩小于等于10kb

实现思路

  1. 获取图片。从资源管理器获取要压缩的图片,创建ImageSource实例,设置解码参数DecodingOptions,使用createPixelMap获取PixelMap图片对象。

    // 获取压缩前图片大小,用于页面上图片显示
      async aboutToAppear() {
        // this.compress()
    
        const context: Context = getContext(this);
        const resourceMgr: resourceManager.ResourceManager = context.resourceManager;
        // 获取待压缩的图片
    
        resourceMgr.getRawFileContent(this.imageSrc).then((fileData: Uint8Array) => {
          // 获取图片的ArrayBuffer
          const buffer = fileData.buffer.slice(0);
          this.sourceImageByteLength = buffer.byteLength;
          this.beforeCompressionSize = (this.sourceImageByteLength / BYTE_CONVERSION).toFixed(1);
        }).catch((err: BusinessError) => {
          console.log(TAG, `Failed to get RawFileContent with error message: ${err.message}, error code: ${err.code}`);
        });
      }
  2. 图片压缩。先判断设置图片质量参数quality为0时,packing能压缩到的图片最小字节大小是否满足指定的图片压缩大小。如果满足,则使用packing方式二分查找最接近指定图片压缩目标大小的quality来压缩图片。如果不满足,则使用scale对图片先进行缩放,采用while循环每次递减0.4倍缩放图片,再用packing(图片质量参数quality设置0)获取压缩图片大小,最终查找到最接近指定图片压缩目标大小的缩放倍数的图片压缩数据 

  3. /**
       * 从rawfile中获取需要压缩的图片image_compression_before.jpeg,压缩
       */
      imageCompression(): void {
        // 获取图片。从资源管理器获取要压缩的图片,创建ImageSource实例,设置解码参数DecodingOptions,使用createPixelMap获取PixelMap图片对象。
        // 获取resourceManager资源管理器
        const resourceMgr: resourceManager.ResourceManager = this.context.resourceManager;
        // 获取资源管理器后,再调用resourceMgr.getRawFileContent()获取资源文件的ArrayBuffer。
        resourceMgr.getRawFileContent(this.imageSrc).then((fileData: Uint8Array) => {
          // 获取图片的ArrayBuffer
          const buffer = fileData.buffer.slice(0);
          // 创建ImageSource实例
          const imageSource: image.ImageSource = image.createImageSource(buffer);
          // 设置解码参数DecodingOptions,解码获取PixelMap图片对象。
          const decodingOptions: image.DecodingOptions = {
            sampleSize: 1, // 缩略图采样大小
            rotate: 0, // 旋转角度
            editable: true, // 是否可编辑。当取值为false时,图片不可二次编辑,如crop等操作将失败
            desiredSize: { width: 1000, height: 2000 }, // 期望输出大小image.size
            desiredPixelFormat: 3, // 解码的像素格式。3表示RGBA_8888
          }
          // 创建pixelMap
          imageSource.createPixelMap(decodingOptions).then((originalPixelMap: image.PixelMap) => {
            this.beforeImgSrc = originalPixelMap
            // 压缩图片
            imageCompressionMethod.compressedImage(originalPixelMap, this.maxCompressedImageSize, 0)
              .then((showImage: CompressedImageInfo) => {
                // 获取压缩后的图片信息
    
                this.compressedImageSrc = fileUri.getUriFromPath(showImage.imageUri);
                this.compressedByteLength = showImage.imageByteLength;
                this.afterCompressionSize = (this.compressedByteLength / BYTE_CONVERSION).toFixed(1);
                // 图片压缩后的大小如果未能达到指定压缩目标大小。提示修改代码中的图片缩小倍数(REDUCE_SCALE),以便进一步压缩图片大小。
                if (this.compressedByteLength / BYTE_CONVERSION > this.maxCompressedImageSize) {
                  AlertDialog.show({
                    message: '图片压缩后的大小未能达到指定压缩目标大小。请尝试修改代码中的图片缩小倍数(REDUCE_SCALE),以便进一步压缩图片大小',
                    alignment: DialogAlignment.Center
                  });
                }
              })
          }).catch((err: BusinessError) => {
            console.log(TAG, `Failed to create PixelMap with error message: ${err.message}, error code: ${err.code}`);
          });
        }).catch((err: BusinessError) => {
          console.log(TAG, `Failed to get RawFileContent with error message: ${err.message}, error code: ${err.code}`);
        });
      }

4.压缩图片方法

//button一压缩图片
  compressedImage() {
    if (this.maxCompressedImageSize === 0) {
      AlertDialog.show({
        message: "请输入大于0的值",
        alignment: DialogAlignment.Center
      });
      return;
    }
    if (this.maxCompressedImageSize * BYTE_CONVERSION > this.sourceImageByteLength) {
      if (this.sourceImageByteLength === 0) {
        AlertDialog.show({
          message: "图片获取失败",
          alignment: DialogAlignment.Center
        });
      } else {
        AlertDialog.show({
          message: "符合压缩要求,无需压缩",
          alignment: DialogAlignment.Center
        });
      }
      return;
    }
    // 重置压缩后的图片路径
    this.compressedImageSrc = '';
    // 从rawfile中获取图片,图片压缩
    this.imageCompression();
  }

 5.相册图片选择

//button相册选择图片压缩
  async getPictureSelect() {
    //  1. 实例化选择参数对象
    const options = new picker.PhotoSelectOptions()
    options.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE // 表示从相册中选择图片
    options.maxSelectNumber = 1 // 表示只选择一张

    //   2. 实例化选择器对象
    const pickerView = new picker.PhotoViewPicker()
    //   3. 调用选择器对象上的select方法传入参数对象即可完成选择
    let res = await pickerView.select(options)

    //   4. 判断用户取消了选择图片,则组织下面代码的继续运行
    if (res.photoUris.length === 0) {
      promptAction.showToast({ message: "用户取消图片选择" })
      return
    }
    //   4.1 准备好一个图片的完整路径
    let ext = 'jpg' // 图片扩展名
    let fileName = Date.now().toString() // 图片名称
    let cacheDir = getContext().cacheDir // 获取应用程序的缓存目录
    let fullPath = cacheDir + '/' + fileName + '.' + ext // 完整的图片路径
    //   4.2 利用fileIo拷贝图片
    let file = fileIo.openSync(res.photoUris[0], fileIo.OpenMode.READ_ONLY)
    fileIo.copyFileSync(file.fd, fullPath)

    let imgResource = image.createImageSource(fullPath)

    // 设置解码参数DecodingOptions,解码获取PixelMap图片对象。
    let originalPixelMap = await imgResource.createPixelMap()

    imageCompressionMethod.compressedImage(originalPixelMap, this.maxCompressedImageSize, 0)
      .then((showImage: CompressedImageInfo) => {
        AlertDialog.show({ message: `showImage.imageUri:${showImage.imageUri}` })
        // 获取压缩后的图片信息
        this.compressedImageSrc = fileUri.getUriFromPath(showImage.imageUri);
        this.compressedByteLength = showImage.imageByteLength;
        this.afterCompressionSize = (this.compressedByteLength / BYTE_CONVERSION).toFixed(1);
        // 图片压缩后的大小如果未能达到指定压缩目标大小。提示修改代码中的图片缩小倍数(REDUCE_SCALE),以便进一步压缩图片大小。
        if (this.compressedByteLength / BYTE_CONVERSION > this.maxCompressedImageSize) {
          AlertDialog.show({
            message: '图片压缩后的大小未能达到指定压缩目标大小。请尝试修改代码中的图片缩小倍数(REDUCE_SCALE),以便进一步压缩图片大小',
            alignment: DialogAlignment.Center
          });
        }
      }).catch((err: BusinessError) => {
      console.log(TAG, `Failed to create PixelMap with error message: ${err.message}, error code: ${err.code}`);
    });
  }

6.ArkUI渲染

  build() {
    Column({ space: SPACE_TEN }) {
      this.titleBar();

      Row({ space: SPACE_TEN }) {
        Text("输入图片压缩目标大小(kb):")
          .fontSize(20)
        TextInput({
          placeholder: '',
          text: $$this.strMaxCompressedImageSize // $$运算符为系统内置组件提供TS变量的引用,使得TS变量和系统内置组件的内部状态保持同步。
        })
          .type(InputType.NUMBER_DECIMAL)// 带小数点的数字输入模式。支持数字,小数点(只能存在一个小数点)。
          .fontSize(20)
          .width("30%")
          .onChange((value: string) => {
            // 由于TextInput组件的InputType.NUMBER_DECIMAL能力对输入的0个数和'.'的位置没有限制,会存在'000.8','008'和'.008'也能输入的情况,所以需要手动限制'0'和'.'。
            if (value.charAt(0) === '.') {
              // 如果字符串第一个字符是'.'时,TextInput的值重置为''
              this.strMaxCompressedImageSize = '';
            } else if (value.charAt(0) === '0' && value.length > 1 && value.charAt(1) !== '.') {
              // value长度为2时,第一个字符是'0',第二个字符输入还是'0',则TextInput重置为'0'。否则,用空字符串替换字符串开头所有0。比如,数字8006,删除'8'后,TextInput显示为6。
              this.strMaxCompressedImageSize =
                (value.length === 2 && value.charAt(1) === '0') ? '0' : value.replace(/^0+/, '');
            } else {
              this.strMaxCompressedImageSize = value;
            }
            this.maxCompressedImageSize = Number(value);
          })
      }

      Row() {
        Button("压缩图片")
          .width("30%")
          .onClick(() => {
            this.compressedImage()
          })
        Button('选择图片')
          .width("30%")
          .onClick(() => {
            this.getPictureSelect()
          })
      }.width('100%').justifyContent(FlexAlign.SpaceBetween)

      Row() {
        Text("压缩前图片大小(kb): ")
          .fontSize(20)
        Text(this.beforeCompressionSize)
          .fontSize(20)
      }

      Image(this.beforeImgSrc)// Image(this.imageSrc)
        .width("100%")
        .height("30%")
        .objectFit(ImageFit.Contain)

      Row() {
        Text("压缩后图片大小(kb): ")
          .fontSize(20)
        Text(this.afterCompressionSize)
          .fontSize(20)
      }

      Image(this.compressedImageSrc)
        .objectFit(ImageFit.Contain)
        .width("100%")
        .height("30%")
    }.alignItems(HorizontalAlign.Start).padding({ left: 20, right: 20 })
  }

  @Builder
  titleBar() {
    Row() {
      Image($r("app.media.ic_left_row"))
        .width(22)
        .aspectRatio(1)

        .margin({ left: 15 })
        .onClick(() => {
          router.back()
        })
    }
    .width("100%")
    .margin({ bottom: 20 })
    .justifyContent(FlexAlign.SpaceBetween)
  }

7.图片压缩、图片保存类ImageCompressionMethod方法封装

import { image } from '@kit.ImageKit'
import { fileIo } from '@kit.CoreFileKit';
import { util } from '@kit.ArkTS';


const TAG = 'Image_Compress';
const BYTE_CONVERSION: number = 1024; // 字节转换

// 压缩后的图片信息类,用于刷新显示压缩后的图片和图片字节长度
export class CompressedImageInfo {
  imageUri: string = ""; // 压缩后图片保存位置的uri
  imageByteLength: number = 0; // 压缩后图片字节长度
  imageBase64: string = ''
}


class ImageCompressionMethod {
  // 设置解码参数DecodingOptions
  private decodingOptions: image.DecodingOptions = {
    sampleSize: 1, // 缩略图采样大小
    rotate: 0, // 旋转角度
    editable: true, // 是否可编辑。当取值为false时,图片不可二次编辑,如crop等操作将失败
    desiredSize: { width: 1920, height: 1080 }, // 期望输出大小image.size
    desiredPixelFormat: 3, // 解码的像素格式。3表示RGBA_8888
  }

  //根据传入图片url进行压缩,返回压缩后的图片info
  public async urlImageCompress(url: string, maxCompressedImageSize: number, isBase64: number) {
    let afterComPreImgInfo: CompressedImageInfo = { imageUri: '', imageByteLength: 0, imageBase64: '' }
    // 创建pixelMap后进行图片压缩
    try {
      // 打开文件创建pixelMap
      let file = fileIo.openSync(url, fileIo.OpenMode.READ_ONLY)
      const imgResource = image.createImageSource(file.fd);
      let originalPixelMap = await imgResource.createPixelMap(this.decodingOptions)
      afterComPreImgInfo = await this.compressedImage(originalPixelMap, maxCompressedImageSize, isBase64)
      return afterComPreImgInfo
    } catch (err) {
      console.log(TAG, `Failed to create PixelMap with error message: ${err.message}, error code: ${err.code}`);
    }

    return afterComPreImgInfo
  }

  /**
   * 图片压缩,保存
   * @param sourcePixelMap:原始待压缩图片的PixelMap对象
   * @param maxCompressedImageSize:指定图片的压缩目标大小,单位kb
   * @returns compressedImageInfo:返回最终压缩后的图片信息
   */
  public async compressedImage(sourcePixelMap: image.PixelMap, maxCompressedImageSize: number,
    isBase64: number): Promise<CompressedImageInfo> {
    // 创建图像编码ImagePacker对象
    const imagePackerApi = image.createImagePacker();
    // 定义图片质量参数
    const IMAGE_QUALITY = 0;
    // 设置编码输出流和编码参数。图片质量参数quality范围0-100。
    const packOpts: image.PackingOption = { format: "image/jpeg", quality: IMAGE_QUALITY };
    // 通过PixelMap进行编码。compressedImageData为打包获取到的图片文件流。
    let compressedImageData: ArrayBuffer = await imagePackerApi.packing(sourcePixelMap, packOpts);
    // 压缩目标图像字节长度
    const maxCompressedImageByte = maxCompressedImageSize * BYTE_CONVERSION;
    // 图片压缩。先判断设置图片质量参数quality为0时,packing能压缩到的图片最小字节大小是否满足指定的图片压缩大小。如果满足,则使用packing方式二分查找最接近指定图片压缩目标大小的quality来压缩图片。如果不满足,则使用scale对图片先进行缩放,采用while循环每次递减0.4倍缩放图片,再用packing(图片质量参数quality设置0)获取压缩图片大小,最终查找到最接近指定图片压缩目标大小的缩放倍数的图片压缩数据。
    let base64: string = ''
    if (maxCompressedImageByte > compressedImageData.byteLength) {
      // 使用packing二分压缩获取图片文件流
      compressedImageData =
        await this.packingImage(compressedImageData, sourcePixelMap, IMAGE_QUALITY, maxCompressedImageByte);
      if (isBase64 === 1) {
        let arrayBuffer = new Uint8Array(compressedImageData)
        let help = new util.Base64Helper
        base64 = help.encodeToStringSync(arrayBuffer)
      }
    } else {
      // 使用scale对图片先进行缩放,采用while循环每次递减0.4倍缩放图片,再用packing(图片质量参数quality设置0)获取压缩图片大小,最终查找到最接近指定图片压缩目标大小的缩放倍数的图片压缩数据
      let imageScale = 1; // 定义图片宽高的缩放倍数,1表示原比例。
      const REDUCE_SCALE = 0.4; // 图片缩小倍数
      // 判断压缩后的图片大小是否大于指定图片的压缩目标大小,如果大于,继续降低缩放倍数压缩。
      while (compressedImageData.byteLength > maxCompressedImageByte) {
        if (imageScale > 0) {
          // 性能知识点: 由于scale会直接修改图片PixelMap数据,所以不适用二分查找scale缩放倍数。这里采用循环递减0.4倍缩放图片,来查找确定最适
          // 合的缩放倍数。如果对图片压缩质量要求不高,建议调高每次递减的缩放倍数reduceScale,减少循环,提升scale压缩性能。
          imageScale = imageScale - REDUCE_SCALE; // 每次缩放倍数减0.4
          // 使用scale对图片进行缩放
          await sourcePixelMap.scale(imageScale, imageScale);
          // packing压缩
          compressedImageData = await this.packing(sourcePixelMap, IMAGE_QUALITY);
          if (isBase64 === 1) {
            let arrayBuffer = new Uint8Array(compressedImageData)
            let help = new util.Base64Helper
            base64 = help.encodeToStringSync(arrayBuffer)
          }
        } else {
          // imageScale缩放小于等于0时,没有意义,结束压缩。这里不考虑图片缩放倍数小于reduceScale的情况。
          break;
        }
      }
    }
    // 保存图片,返回压缩后的图片信息。
    const compressedImageInfo: CompressedImageInfo = await this.saveImage(compressedImageData, base64);
    return compressedImageInfo;
  }

  /**
   * 图片保存
   * @param compressedImageData:压缩后的图片数据
   * @returns compressedImageInfo:返回压缩后的图片信息
   */
  private async saveImage(compressedImageData: ArrayBuffer, base64: string): Promise<CompressedImageInfo> {
    const context: Context = getContext();
    // 定义要保存的压缩图片uri。image_compression_after.jpeg表示压缩后的图片。
    const compressedImageUri: string = context.filesDir + '/' + `${Date.now()}.jpeg`;
    try {
      const res = fileIo.accessSync(compressedImageUri);
      if (res) {
        // 如果图片image_compression_after.jpeg已存在,则删除
        fileIo.unlinkSync(compressedImageUri);
      }
    } catch (err) {
      console.log(TAG, `AccessSync failed with error message: ${err.message}, error code: ${err.code}`);
    }

    // 压缩图片数据写入文件
    const file: fileIo.File = fileIo.openSync(compressedImageUri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
    fileIo.writeSync(file.fd, compressedImageData);
    fileIo.closeSync(file);
    // 获取压缩图片信息
    let compressedImageInfo: CompressedImageInfo = new CompressedImageInfo();
    compressedImageInfo.imageUri = compressedImageUri;
    compressedImageInfo.imageByteLength = compressedImageData.byteLength;
    compressedImageInfo.imageBase64 = base64
    return compressedImageInfo;
  }

  /**
   * packing压缩
   * @param sourcePixelMap:原始待压缩图片的PixelMap
   * @param imageQuality:图片质量参数
   * @returns data:返回压缩后的图片数据
   */
  private async packing(sourcePixelMap: image.PixelMap, imageQuality: number): Promise<ArrayBuffer> {
    const imagePackerApi = image.createImagePacker();
    const packOpts: image.PackingOption = { format: "image/jpeg", quality: imageQuality };
    const data: ArrayBuffer = await imagePackerApi.packing(sourcePixelMap, packOpts);
    return data;
  }

  /**
   * packing二分方式循环压缩
   * @param compressedImageData:图片压缩的ArrayBuffer
   * @param sourcePixelMap:原始待压缩图片的PixelMap
   * @param imageQuality:图片质量参数
   * @param maxCompressedImageByte:压缩目标图像字节长度
   * @returns compressedImageData:返回二分packing压缩后的图片数据
   */
  private async packingImage(compressedImageData: ArrayBuffer, sourcePixelMap: image.PixelMap, imageQuality: number,
    maxCompressedImageByte: number): Promise<ArrayBuffer> {
    // 图片质量参数范围为0-100,这里以10为最小二分单位创建用于packing二分图片质量参数的数组。
    const packingArray: number[] = [];
    const DICHOTOMY_ACCURACY = 10;
    // 性能知识点: 如果对图片压缩质量要求不高,建议调高最小二分单位dichotomyAccuracy,减少循环,提升packing压缩性能。
    for (let i = 0; i <= 100; i += DICHOTOMY_ACCURACY) {
      packingArray.push(i);
    }
    let left = 0; // 定义二分搜索范围的左边界
    let right = packingArray.length - 1; // 定义二分搜索范围的右边界
    // 二分压缩图片
    while (left <= right) {
      const mid = Math.floor((left + right) / 2); // 定义二分搜索范围的中间位置
      imageQuality = packingArray[mid]; // 获取二分中间位置的图片质量值
      // 根据传入的图片质量参数进行packing压缩,返回压缩后的图片文件流数据。
      compressedImageData = await this.packing(sourcePixelMap, imageQuality);
      // 判断查找一个尽可能接近但不超过压缩目标的压缩大小
      if (compressedImageData.byteLength <= maxCompressedImageByte) {
        // 二分目标值在右半边,继续在更高的图片质量参数(即mid + 1)中搜索
        left = mid + 1;
        // 判断mid是否已经二分到最后,如果二分完了,退出
        if (mid === packingArray.length - 1) {
          break;
        }
        // 获取下一次二分的图片质量参数(mid+1)压缩的图片文件流数据
        compressedImageData = await this.packing(sourcePixelMap, packingArray[mid + 1]);
        // 判断用下一次图片质量参数(mid+1)压缩的图片大小是否大于指定图片的压缩目标大小。如果大于,说明当前图片质量参数(mid)压缩出来的
        // 图片大小最接近指定图片的压缩目标大小。传入当前图片质量参数mid,得到最终目标图片压缩数据。
        if (compressedImageData.byteLength > maxCompressedImageByte) {
          compressedImageData = await this.packing(sourcePixelMap, packingArray[mid]);
          break;
        }
      } else {
        // 目标值不在当前范围的右半部分,将搜索范围的右边界向左移动,以缩小搜索范围并继续在下一次迭代中查找左半部分。
        right = mid - 1;
      }
    }
    return compressedImageData;
  }
}

const imageCompressionMethod = new ImageCompressionMethod()

export { imageCompressionMethod }

标签:const,缩放,解决方案,压缩,harmonyOS,packing,image,图片
From: https://blog.csdn.net/xp1870069025/article/details/141294115

相关文章

  • HarmonyOS 层叠布局:(Stack)打造灵活多变的UI界面
    在应用开发中,布局设计是用户体验的关键之一。而在HarmonyOS中,层叠布局(Stack)是一种极为灵活的布局方式。它允许我们在同一个区域内放置多个组件,并根据需求将它们叠加起来,形成丰富的视觉效果。无论是广告展示还是卡片叠加效果,层叠布局都能轻松胜任。今天,我将带大家深入了解Stack......
  • electron-forge通过Squirrel.Windows打包导致的asar文件过大的解决方案
    环境我的Eectron环境如下:"@electron-forge/cli":"^7.1.0","@electron-forge/maker-deb":"^7.1.0","@electron-forge/maker-rpm":"^7.1.0","@electron-forge/maker-squirrel":"^7.1.0",&q......
  • 数字孪生智慧工地解决方案
    1.行业背景与挑战建筑行业面临材料成本高、施工管理问题、环境污染、劳资纠纷和安全隐患等挑战。智慧工地的发展趋势需要集成统一管理、高效协同工作以及自动化和智能化。2.政策引导与新技术推动国家政策如《建筑业信息化发展纲要》和雄安新区管理办法强调了BIM和CIM技术......
  • 生鲜商城购物系统解决方案毕设毕业设计.web期末作业设计网页.css网页成品参考
     博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、P......
  • LookupError: Resource averaged_perceptron_tagger not found.解决方案
      大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学......
  • 安装git-format-staged后,Sourcetree中提交代码报错的解决方案
    pre-commit文件中内容为:git-format-staged--formatter"swiftformatstdin--stdinpath'{}'""*.swift" 在终端中,gitcommit不会报错。Sourcetree中提交具体错误:git-format-staged或者swiftformat命令找不到。解决方案一:利用Automator(自动操作)新建一个SourceTree应......
  • 2024新型数字政府综合解决方案(一)
    新型数字政府综合解决方案通过整合先进的数字技术和智能化系统,构建了一个高效、透明且响应迅速的政府服务平台,能够实现跨部门数据共享和实时信息更新。该解决方案包括智能数据分析、大数据平台和云计算服务,旨在提升政府决策的科学性和行政管理的效能。通过在线服务和自动化流程......
  • Clion控制台中文输出/报错信息乱码的最完美解决方案(无需更改注册表,beta版UTF-8)
    Clion控制台中文输出/报错信息乱码的最完美解决方案(无需更改注册表,beta版UTF-8)1.问题:clion控制台乱码2.错误解决方案:Ctrl+Shift+Alt+/,回车,打开注册表,取消勾选"run.processes.with.pty"(clion可能会卡死)3.正确方式:1.Ctrl+Alt+S打开设置2.找到编辑器Editor-文件编码Fil......
  • 并查集(路径压缩法+启发式合并法)
    我们从一道例题看起:洛谷P1551亲戚。问题很简单,给出一个亲戚关系图,规定\(x\)和\(y\)是亲戚,\(y\)和\(z\)是亲戚,那么\(x\)和\(z\)也是亲戚,那么\(x\)的亲戚都是\(y\)的亲戚,\(y\)的亲戚也都是\(x\)的亲戚,再给定\(P_i\)和\(P_j\),询问他们是否是亲戚,输出Yes或......
  • Git 命令大全:详细讲解与常见问题解决方案
    目录1.Git基础命令2.分支管理命令3.远程仓库管理命令4.标签管理命令5.其他常用命令6.总结Git是目前最流行的分布式版本控制系统,它使得团队协作和代码管理变得更加高效。本文将详细介绍Git的常用命令及其应用场景,并针对可能遇到的问题提供解决方案。1.Git......