Skip to content

centerSlice doesn't work properly with resolution-aware image assets #20013

Closed

Description

@luizgpa

Steps to Reproduce

  1. Create an image to be used with centerSlice.
    border
  2. Show the image in a widget
          Image(
            image: AssetImage('assets/border.png'),
            centerSlice: Rect.fromLTRB(15.0, 15.0, 25.0, 25.0),
            height: 71.0,
            width: 190.0,
          ),

It works
1x
3. Add an image for higher pixel density devices.
border
(I changed the color just to be sure the right image is shown.)
4. Run the same code in a device with higher pixel density.
2x (200%)
Notice that the corners are blurred and don't fit the rest of the image.

If you multiply the centerSlice values by 2 the result is correct.
2xok
Probably the code that handle centerSlice doesn't consider the 'real' image scale?

The code and images can be found here:
https://github.com/luizgpa/center_slice

Thanks

Logs

flutter doctor -v

[√] Flutter (Channel master, v0.5.8-pre.179, on Microsoft Windows [Version 10.0.17134.165], locale pt-BR)
    • Flutter version 0.5.8-pre.179 at C:\Projects\flutter
    • Framework revision 711ecf7f58 (4 hours ago), 2018-07-30 12:35:15 -0700
    • Engine revision af855e063a
    • Dart version 2.0.0-dev.69.4.flutter-08f59e5de3

[√] Android toolchain - develop for Android devices (Android SDK 27.0.3)
    • Android SDK at C:\Android\sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-27, build-tools 27.0.3
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b02)
    • All Android licenses accepted.

[√] Android Studio (version 3.1)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin version 26.0.1
    • Dart plugin version 173.4700
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b02)

[√] Connected devices (1 available)
    • Android SDK built for x86 64 • emulator-5554 • android-x64 • Android 6.0 (API 23) (emulator)

• No issues found!

Activity

  1. added
    engineflutter/engine related. See also e: labels.
    on Jul 31, 2018
  2. luizgpa commented on Aug 7, 2018

    @luizgpa
    Author

    One extra point, DecorationImage suffers from the same issue.

  3. rockingdice commented on Aug 27, 2018

    @rockingdice

    any updates on this? Can we show nine patch images with 2.0x or 3.0x?

  4. rockingdice commented on Aug 27, 2018

    @rockingdice

    maybe related to #18682, and there's already a PR: #20791

  5. rockingdice commented on Aug 28, 2018

    @rockingdice

    More works to do:
    I modified some source codes to make the centerSlice multiply by the image's scale, it still has got issues:
    Incorrect result:
    image
    The nine patch image rendered with 3.0x resolution (incorrect). The original centerSlice is Rect.fromLTRB(20.0, 20.0, w - 20.0, h - 20.0) which under 1.0x density. After multiplication, it should be 60.0 to the borders so that it will correctly get the corner from the 3.0x image. But it is rendered as 60 points on the screen, which is expected to be 20.

    Correct result:
    image
    The corner is 20 points on the screen. The corner size shouldn't be changed by different pixel density.

    So I think the rendering logic should consider current pixel density, and maybe apply a scale matrix when rendering the nine patch image when calling skia native functions?

    I cannot continue to write the app because there's plenty of nine patch images in it. So if there's a quick fix or workaround, that would be great.

    Btw, I think the users should not be aware of the pixel density at all. If they declared the assets for different pixel density like 2.0x, 3.0x, when they use the assets, the size should be points instead of real pixels. For completeness, we can clearly ask for pixel size for different situations, but the default should be points, IMHO.

  6. rockingdice commented on Aug 28, 2018

    @rockingdice

    Never think this could be really easy to achieve!

    It could be fixed by giving a transform to the canvas with 1.0/scale and make the destinationRect multiplied by its scale before rendering. Then it should be render correctly. Also, don't forget to save/restore the canvas state when doing all the canvas manipulations.

    Correct result:
    image

  7. sir-boformer commented on Aug 28, 2018

    @sir-boformer
    Contributor

    If it's related to #20791, maybe we can add the code to fix this issue as well? I created that PR. Or does the PR already fix this issue?

  8. rockingdice commented on Aug 29, 2018

    @rockingdice

    @sir-boformer
    No, but we can fix this issue based on your PR with some more changes.

    I mentioned #18682 that might be related because this issue can be traced to the same place and some of your codes are needed.

    You might already notice there's a logic branch when checking the centerSlice if exists, the flutter libs don't handle resolution images in that situation as well.

    here are the changes for lib/src/painting/decoration_image.dart (based on #20791):

    Remove these lines which is using 'sliceBorder':
    image

    • Removed sliceBorder related codes.

    Modify these codes:
    image

    • Removed sliceBorder related codes.
    • added:
      centerSlice = centerSlice.topLeft * scale & centerSlice.size * scale;

    Modify the codes rendering for the nine patch image:
    image

    for (Rect tileRect in _generateImageTileRects(rect, destinationRect, repeat)) {
          canvas.save();
          canvas.scale(1.0/scale, 1.0/scale);
          tileRect = tileRect.topLeft * scale & tileRect.size * scale;
          canvas.drawImageNine(image, centerSlice, tileRect, paint);
          canvas.restore();
        }
    
    

    I don't know if the sliceBorder is needed. But for my test, this mod works well.

  9. Quanhua-Guan commented on Mar 24, 2020

    @Quanhua-Guan

    try add scale value to Image widget

             Image.asset(
                'images/mask32x32.png',
                centerSlice: Rect.fromLTWH(15.5, 15.5, 1, 1),
                scale: window.devicePixelRatio, //  from dart:io window.dart
              )
    
  10. Quanhua-Guan commented on Mar 25, 2020

    @Quanhua-Guan

    try add scale value to Image widget

             Image.asset(
                'images/mask32x32.png',
                centerSlice: Rect.fromLTWH(15.5, 15.5, 1, 1),
                scale: window.devicePixelRatio, //  from dart:io window.dart
              )
    

    seems still not working, the image used is the 1x one

  11. Quanhua-Guan commented on Mar 25, 2020

    @Quanhua-Guan

    One possible solution: use 4 corner images to substitute the center sliced image.

  12. TahaTesser commented on Oct 13, 2020

    @TahaTesser
    Contributor
    complete code sample
    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              Image(
                image: AssetImage('assets/border.png'),
                centerSlice: Rect.fromLTRB(15.0, 15.0, 25.0, 25.0),
                height: 71.0,
                width: 190.0,
                repeat: ImageRepeat.repeat,
              ),
              Container(
                decoration: BoxDecoration(
                    image: DecorationImage(
                  image: AssetImage('assets/border.png'),
                  centerSlice: Rect.fromLTRB(15.0, 15.0, 25.0, 25.0),
                )),
                child: SizedBox(width: 190.0, height: 71.0),
              ),
            ],
          ),
        );
      }
    }
    

    assets.zip

      assets:
        - assets/image.jpg
        - assets/border.png
        - assets/2.0x/border.png
    
    flutter doctor -v
    [✓] Flutter (Channel master, 1.23.0-14.0.pre.152, on Mac OS X 10.15.7 19H2
        x86_64, locale en-GB)
        • Flutter version 1.23.0-14.0.pre.152 at
          /Users/tahatesser/Code/flutter_master
        • Framework revision 62cf4dbf10 (7 hours ago), 2020-10-13 14:12:02 +0800
        • Engine revision 6634406889
        • Dart version 2.11.0 (build 2.11.0-213.0.dev)
    
     
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
        • Android SDK at /Users/tahatesser/Code/sdk
        • Platform android-30, build-tools 30.0.2
        • ANDROID_HOME = /Users/tahatesser/Code/sdk
        • Java binary at: /Applications/Android
          Studio.app/Contents/jre/jdk/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build
          1.8.0_242-release-1644-b3-6222593)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 12.0.1)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 12.0.1, Build version 12A7300
        • CocoaPods version 1.10.0.rc.1
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 4.1)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build
          1.8.0_242-release-1644-b3-6222593)
    
    [✓] VS Code (version 1.50.0)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.15.0
    
    [✓] Connected device (4 available)
        • RMX2001 (mobile) • EUYTFEUSQSRGDA6D • android-arm64  • Android 10 (API 29)
        • macOS (desktop)  • macos            • darwin-x64     • Mac OS X 10.15.7
          19H2 x86_64
        • Web Server (web) • web-server       • web-javascript • Flutter Tools
        • Chrome (web)     • chrome           • web-javascript • Google Chrome
          86.0.4240.80
    
    • No issues found!
  13. added
    a: imagesLoading, displaying, rendering images
    a: qualityA truly polished experience
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    on Oct 13, 2020
  14. github-actions commented on Aug 10, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  15. locked as resolved and limited conversation to collaborators on Aug 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: imagesLoading, displaying, rendering imagesa: qualityA truly polished experienceengineflutter/engine related. See also e: labels.found in release: 1.23Found to occur in 1.23has reproducible stepsThe issue has been confirmed reproducible and is ready to work on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions