You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter合成星轨图报错:'PixelUint8'无法转换为'int'类型

问题描述

使用Dart和Flutter开发星轨图合成功能,相册选图展示功能正常,但执行图片合成时触发类型转换错误:

I/flutter (17585): Error creating image: type 'PixelUint8' is not a subtype of type 'int' in type cast

错误原因

问题出在使用的image库(代码中以img为前缀):

  • getPixel方法返回的不是int类型像素值,而是PixelUint8对象(根据图像格式不同可能是其他Pixel子类),直接强制转换为int会失败
  • 原代码最后将int类型的像素值强制转换为img.Color属于多余操作,setPixel可直接接受该int值
修复方案
  1. 改用image库内置的颜色提取方法(getAlpha/getRed/getGreen/getBlue),避免手动处理Pixel对象和类型转换
  2. 修正星轨合成逻辑:星轨效果需要保留多张图片对应像素的最亮值,原代码仅做像素覆盖,无法生成正确星轨
  3. 移除所有不必要的强制类型转换
修复后的完整代码
late int alphaValue;
late int redValue;
late int greenValue;
late int blueValue;

// 直接使用image库的内置方法提取颜色分量,规避类型转换问题
int getAlpha(img.Image image, int x, int y) {
  return image.getAlpha(x, y);
}

int getRed(img.Image image, int x, int y) {
  return image.getRed(x, y);
}

int getGreen(img.Image image, int x, int y) {
  return image.getGreen(x, y);
}

int getBlue(img.Image image, int x, int y) {
  return image.getBlue(x, y);
}

Future<File> _createStartrail(List<File> images) async {
  if (images.isEmpty) {
    throw Exception('No images selected');
  }

  img.Image? startrailImage;

  for (final imageFile in images) {
    final bytes = await imageFile.readAsBytes();
    final image = img.decodeImage(Uint8List.fromList(bytes));

    if (image == null) continue;

    startrailImage ??= img.Image(width: image.width, height: image.height);

    for (int y = 0; y < image.height; y++) {
      for (int x = 0; x < image.width; x++) {
        // 提取当前图片的颜色分量
        final currentAlpha = getAlpha(image, x, y);
        final currentRed = getRed(image, x, y);
        final currentGreen = getGreen(image, x, y);
        final currentBlue = getBlue(image, x, y);

        // 提取星轨画布中已有像素的颜色分量
        final existingRed = getRed(startrailImage, x, y);
        final existingGreen = getGreen(startrailImage, x, y);
        final existingBlue = getBlue(startrailImage, x, y);

        // 星轨核心逻辑:保留更亮的颜色值
        redValue = currentRed > existingRed ? currentRed : existingRed;
        greenValue = currentGreen > existingGreen ? currentGreen : existingGreen;
        blueValue = currentBlue > existingBlue ? currentBlue : existingBlue;
        alphaValue = currentAlpha; // 可按需改为取最大值

        // 组合成像素值,直接传入setPixel,无需类型转换
        final newPixel = (alphaValue << 24) | (redValue << 16) | (greenValue << 8) | blueValue;
        startrailImage.setPixel(x, y, newPixel);
      }
    }
  }

  final output = await getTemporaryDirectory();
  final outputPath = '${output.path}/startrail.png';

  final outputFile = File(outputPath);
  await outputFile.writeAsBytes(img.encodePng(startrailImage!));

  return outputFile;
}

// 以下代码无需修改
File? _combinedImage;

void _combineImages() {
  if (_images.isNotEmpty) {
    _createStartrail(_images).then((combinedImage) {
      setState(() {
        _combinedImage = combinedImage;
      });
    }).catchError((error) {
      print('Errore durante la creazione dell\'immagine startrail: $error');
    });
  }
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text('Camera Preview')),
    body: Column(
      children: [
        Expanded(
          child: FutureBuilder<void>(
            future: _initializeControllerFuture,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                return AspectRatio(
                  aspectRatio: 16 / 9,
                  child: CameraPreview(_controller),
                );
              } else {
                return const Center(child: CircularProgressIndicator());
              }
            },
          ),
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _pickImages,
              child: const Text('Select Images'),
            ),
            const SizedBox(width: 10),
            ElevatedButton(
              onPressed: _combineImages,
              child: const Text('Create Startrail'),
            ),
          ],
        ),
        if (_imagePreviews.isNotEmpty)
          Container(
            padding: EdgeInsets.symmetric(vertical: 10),
            height: 100,
            child: ListView(
              scrollDirection: Axis.horizontal,
              children: _imagePreviews,
            ),
          ),
        if (_combinedImage != null)
          Container(
            padding: EdgeInsets.all(10),
            child: Image.file(_combinedImage!),
          ),
      ],
    ),
  );
}

内容的提问来源于stack exchange,提问作者Gabriele Iocco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 01:12:04