• Flutter高仿微信-第55篇-群聊-合成群头像


     Flutter高仿微信系列共59篇,从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。

     详情请查看

    /**
     * 处理合并群头像
     * @groupId 群id
     * @avatarList 头像列表
     */
    static processMergeAvatarImage(String groupId, List avatarList) async {
      if(avatarList.isEmpty){
        return;
      }
      List filePathList = [];
      for(int i = 0; i < avatarList.length; i++){
        if(avatarList[i].isNotEmpty){
          String avatarFilePath = await getCacheFilePath(CommonUtils.getReallyImage(avatarList[i]));
          filePathList.add(avatarFilePath);
        }
      }
    
      if(filePathList.isEmpty){
        return;
      }
    
      //合成群头像
      String groupAvatar = await mergeAvatarImage(filePathList);
      LogUtils.d("合并头像地址");
      GroupBean? groupBean = await GroupRepository.getInstance().findGroupByGroupId(groupId);
      if(groupBean != null){
        groupBean?.avatar = groupAvatar;
        GroupRepository.getInstance().updateGroup(groupBean);
    
        String serverResultAvatar = await UploadUtils.getInstance().uploadGroupAvatar(groupId, groupAvatar);
        //设置服务器头像地址
        groupBean?.avatar = serverResultAvatar;
    
        //发送消息通知更改群头像
        ChatSendBean chatSendBean = ChatSendBean();
        int contentType = CommonUtils.GROUP_CHAT_TYPE_REFRESH;
        chatSendBean.contentType = contentType;
        chatSendBean.content = serverResultAvatar;
        int id = DateTime.now().millisecondsSinceEpoch;
        String toJid = "${groupId}@conference.wangning";
        String msg = jsonEncode(chatSendBean);
        XmppManager.getInstance().sendGroupMessageWithType(toJid, msg, "${id}", id);
        //GroupRepository.getInstance().updateGroupServer(groupBean);
        LogUtils.d("合并头像更新成功 ${serverResultAvatar}");
      }
    
    }
    
    /**
     * 合并群头像
     * 不管多少个,默认取9个,生成3行3列的图片(从文件读取图片)
     */
    static Future mergeAvatarImage(List filePathList) async {
    
      if(filePathList.isEmpty){
        return "";
      }
    
      filePathList = _interceptList(filePathList);
    
      const kCanvasSize = 200.0;
      final Random rd = Random();
      final int numColors = Colors.primaries.length;
    
      final color = Colors.primaries[rd.nextInt(numColors)];
    
      final recorder = ui.PictureRecorder();
      final canvas = Canvas(recorder,
          Rect.fromPoints(Offset(0.0, 0.0), Offset(kCanvasSize, kCanvasSize)));
    
      final stroke = Paint()
        ..color = Colors.grey
        ..style = PaintingStyle.stroke;
    
      canvas.drawRect(Rect.fromLTWH(0.0, 0.0, kCanvasSize, kCanvasSize), stroke);
    
      final paint = Paint()
        ..color = color
        ..style = PaintingStyle.fill;
    
      //3行3列
      for(int i = 0; i < 3; i++){
        for(int j = 0; j < 3; j++){
          String filePath = filePathList[i*3 + j];
          //LogUtils.d("文件路径:${filePath}");
          //加载文件图片
          ui.Image fileImage = await _loadFileImage(filePath);
          //取图片宽高最小的值
          int fileWidth = fileImage.width >= fileImage.height ? fileImage.height : fileImage.width;
          double scale = kCanvasSize/3/fileWidth;
    
          //显示图片真是的宽高
          double imageWidth = fileWidth * scale;
          double left = j * imageWidth - _getSpaceY(j);
          double top = i * imageWidth - _getSpaceX(i);
          LogUtils.d("file 参数:left = ${left} , top = ${top} , imageWidth = ${imageWidth} , fileWidth = ${fileWidth}, scale = ${scale}  ");
          //移动x
          double dx = j * imageWidth;
          //移动y
          double dy = i * imageWidth;
          canvas.save();
          canvas.translate(dx, dy);
          canvas.scale(scale, scale);
    
          Rect src = Rect.fromLTWH(left, top , fileWidth.toDouble(), fileWidth.toDouble());
          canvas.drawImageRect(fileImage, src, src, paint);
    
          canvas.restore();
        }
      }
    
      final picture = recorder.endRecording();
      final img = await picture.toImage(200, 200);
      final pngBytes = await img.toByteData(format: ImageByteFormat.png);
    
      String resultFilePath = await _saveMergeGroupAvatar(pngBytes);
      return resultFilePath;
    }
    
    //如果超过9个, 截取前面9个,如果少于9个,在里面随机获取补够9个
    static List _interceptList(List filePathList){
      List resultFilePathList = [];
      //最多9个
      int maxSize = 9;
      //个数
      int size = filePathList.length;
      if(size >= 9){
        resultFilePathList = filePathList.sublist(0,9);
      } else {
        resultFilePathList = filePathList;
        //还要补多少个
        int repairSize = maxSize - size;
        for(int i = 0; i < repairSize; i++){
          //在现有的列表随机取
          int ran = Random().nextInt(size);
          resultFilePathList.add(filePathList[ran]);
        }
      }
      return resultFilePathList;
    }
    
    static int _getSpaceY(int j){
      //纵轴空白
      int spaceY = 0;
      if(j == 1){
        spaceY = 40;
      } else if(j == 2){
        spaceY = 110;
      }
      return spaceY;
    }
    
    //横轴空白
    static int _getSpaceX(int i){
      //横轴空白
      int spaceX = 0;
      if(i == 1){
        spaceX = 40;
      } else if(i == 2){
        spaceX = 110;
      }
    
      return spaceX;
    }
    
    //从手机加载图片
    static Future _loadFileImage(String filePath) async {
      File file = File(filePath);
      final Completer completer = Completer();
      ui.decodeImageFromList(file.readAsBytesSync(), (ui.Image img) {
        return completer.complete(img);
      });
      return completer.future;
    }
    
    //从资源文件加载图片
    static Future _loadAssetUiImage(String imageAssetPath) async {
      final ByteData data = await rootBundle.load(imageAssetPath);
    
      final Completer completer = Completer();
      ui.decodeImageFromList(Uint8List.view(data.buffer), (ui.Image img) {
        return completer.complete(img);
      });
      return completer.future;
    }
    
    //保存合并群头像
    static Future _saveMergeGroupAvatar(ByteData? imgBytes) async {
      String uuid = UUID.getUUID();
      String saveFilePath = await FileUtils.getBaseFile("${uuid}.png");
      File file = File(saveFilePath);
      final pngBytes = imgBytes!.buffer.asUint8List();
      await file.writeAsBytes(pngBytes);
      return saveFilePath;
    }

  • 相关阅读:
    时空预测2-GCN_LSTM
    Cloud微服务:Ribbon负载均衡
    CUDA编程入门系列(十)并行规约
    内边距(padding会影响盒子内边距大小)
    电子协会 C语言 1级 32、计算2的幂
    路由跳转问题(浏览器返回replace replaceState)
    反射【Java】
    React - React v18 的 批处理
    数组的substring方法和substr方法
    python文件操作(Windows路径,内置os库)+ 正则表达式(语法与re库)
  • 原文地址:https://blog.csdn.net/maoning20080808/article/details/128050605