[flutter] photo_view 패키지로 이미지에 톤매핑 효과 추가하기

photo_view는 Flutter에서 이미지를 확대 및 축소하고 스와이프하여 볼 수 있도록 하는 편리한 패키지입니다. 이 패키지를 사용하여 이미지에 톤매핑 효과를 추가하는 방법을 알아보겠습니다.

photo_view 패키지 추가하기

먼저 pubspec.yaml 파일에 photo_view 패키지를 추가해야 합니다. 아래와 같이 dependencies 섹션에 패키지를 추가합니다.

dependencies:
  photo_view: ^0.12.0

추가한 후에는 터미널에서 다음 명령을 실행하여 패키지를 다운로드합니다.

flutter pub get

톤매핑 효과 추가하기

photo_view 패키지를 이용하여 이미지에 톤매핑 효과를 추가하려면 CustomPainter를 사용해야 합니다. CustomPainter는 화면에 그릴 수 있는 사용자 정의 그래픽을 구현하는 데 사용됩니다.

CustomPainter 클래스를 상속받는 새로운 클래스를 만들고 paint() 메서드를 재정의하여 이미지 위에 톤매핑 효과를 그립니다.

import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';

class ImageToneMappingPainter extends CustomPainter {
  final double opacity;

  ImageToneMappingPainter({required this.opacity});

  @override
  void paint(ui.Canvas canvas, ui.Size size) {
    // 이미지에 대한 톤매핑 효과를 그리는 로직 작성
    // 예시: 이미지를 흑백으로 변환하고 지정된 투명도로 그림자를 추가한다.
    
    // 이미지를 로드
    final image = NetworkImage("https://example.com/image.jpg");
    final decoder = await ui.instantiateImageCodec(await (await image).getByteData());
    final frame = await decoder.getNextFrame();
    final imageBitmap = await frame.image.toByteData();

    // 이미지를 흑백으로 변환
    final grayscaleImagePaint = Paint()
      ..shader = ImageShader(
        imageBitmap!,
        TileMode.repeated,
        TileMode.repeated,
        Matrix4.identity().storage,
      );
    grayscaleImagePaint.colorFilter = const ColorFilter.matrix(<double>[
      0.21, 0.72, 0.07, 0, 0, // RGB 투명도
      0.21, 0.72, 0.07, 0, 0,
      0.21, 0.72, 0.07, 0, 0,
      0,    0,    0,    opacity, 0, // 투명도
    ]);

    // 흑백으로 변환된 이미지에 그림자를 추가
    final shadowPaint = Paint()
      ..maskFilter = MaskFilter.blur(BlurStyle.normal, 8);

    final shadowOffset = Offset(5, 5);
    final shadowRect = Rect.fromLTWH(
      0 - shadowOffset.dx,
      0 - shadowOffset.dy,
      size.width + shadowOffset.dx * 2,
      size.height + shadowOffset.dy * 2,
    );

    canvas.saveLayer(Rect.fromLTRB(0, 0, size.width, size.height), Paint());

    canvas.translate(shadowOffset.dx, shadowOffset.dy);
    canvas.scale(1.0, 1.0);
    canvas.drawImageRect(
      imageBitmap!.buffer.asUint8List(),
      Rect.fromLTRB(0, 0, size.width, size.height),
      Rect.fromLTRB(0, 0, size.width, size.height),
      shadowPaint,
    );

    canvas.translate(-shadowOffset.dx, -shadowOffset.dy);
    canvas.scale(1.0, 1.0);
    canvas.drawImageRect(
      imageBitmap.buffer.asUint8List(),
      Rect.fromLTRB(0, 0, size.width, size.height),
      Rect.fromLTRB(0, 0, size.width, size.height),
      grayscaleImagePaint,
    );

    canvas.restore();
  }

  @override
  bool shouldRepaint(ImageToneMappingPainter oldDelegate) {
    return opacity != oldDelegate.opacity;
  }
}

위의 코드에서는 paint() 메서드 내에서 이미지를 로드하여 흑백으로 변환한 후 해당 이미지에 그림자를 추가합니다. 그리기 할 때 사용할 투명도는 opacity 매개변수로 전달받습니다.

톤매핑 효과를 적용한 이미지 보기

이제 photo_view 패키지를 사용하여 이미지에 톤매핑 효과를 적용하도록 합니다. CustomPainter를 사용하여 톤매핑 효과를 그린 후, 그려진 효과를 photo_view 패키지를 이용하여 화면에 보여줍니다.

import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';

class ImagePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Stack(
          children: [
            PhotoView.customChild(
              child: Image.network("https://example.com/image.jpg"),
              backgroundDecoration: BoxDecoration(
                color: Colors.white,
              ),
              minScale: PhotoViewComputedScale.contained,
              maxScale: PhotoViewComputedScale.covered * 2,
              initialScale: PhotoViewComputedScale.contained,
              customChildPainter: ImageToneMappingPainter(opacity: 0.5),
            ),
          ],
        ),
      ),
    );
  }
}

위의 코드에서는 customChildPainter 속성을 사용하여 생성한 ImageToneMappingPainter를 지정하고, opacity 매개변수로 톤매핑 효과의 투명도를 전달합니다.

이제 앱을 실행하고 해당 이미지 페이지로 이동하면 photo_view 패키지를 이용하여 톤매핑 효과가 추가된 이미지를 확인할 수 있습니다.

결론

photo_view 패키지를 사용하여 Flutter 앱에서 이미지에 톤매핑 효과를 추가하는 방법을 알아보았습니다. 이러한 효과는 이미지를 더욱 흥미롭고 시각적으로 풍부하게 만들어줄 수 있습니다. photo_view 패키지와 CustomPainter를 적절히 활용하여 다양한 효과를 추가해보세요!

참고 자료