React-native-render-html: image getting blur issue

Created on 3 May 2018  路  11Comments  路  Source: meliorence/react-native-render-html

Is this a bug report or a feature request?

bug report

Have you read the guidelines regarding bug report?

yes

Have you read the documentation in its entirety?

yes

Have you made sure that your issue hasn't already been reported/solved?

yes

Is the bug specific to iOS or Android? Or can it be reproduced on both platforms?

Unknown - only able to test on IOS (11.3)

Is the bug reproductible in a production environment (not a debug one)?

Yes

Have you been able to reproduce the bug in the provided example?

I have not tried the demo

Environment

IOS (11.3)

Steps to Reproduce

(Write your steps here:)

  1. Create a string containing HTML Markup, with an image tag whose src points to a url which is resolved into the images.

Expected Behavior

images should in good result as i upload in ckeditor.  should not be blur

Actual Behavior

Image getting blur when i have nested images

Reproducible Demo

i dont have a demo but i have a code

 const htmlContent = `
  <iframe allow="encrypted-media" allowfullscreen="" frameborder="0" gesture="media" height="163" src="https://www.youtube.com/embed/MST_cBdgqic"></iframe>
  <div style="width:100%; height:100%;margin-top:10px; "><img border="0" src="https://storage.googleapis.com/appon/uploadedMedia/54441524224615/54441524224615_up_1524471931.jpg" style="width:100%;" title="" /></div>
  <div style="width:100%; height:100%; "><img border="0" src="https://storage.googleapis.com/appon/uploadedMedia/54441524224615/54441524224615_up_1524471931.jpg" style="width:100%;" title="" /></div>

`;
<HTML style={{ marginTop: 15,}} html={itemId.description} imagesMaxWidth={Dimensions.get('window').width} staticContentMaxWidth={Dimensions.get('window'} ignoredStyles={['height','width']} />
bug easyfix minor scaling waiting pr

Most helpful comment

Hello, I had the same issue (only tested on iOS 10 on iPhone 6S). I spent a lot of time aimlessly debugging and I think I figured it out.
The problem seems to be something like this:

  • Dimensions are unknown so the image gets rendered with props.imagesInitialDimensions tiny dimensions (100x100 by default?).
  • This is a total guess, but React caches the tiny image instead of the original one?
  • After the real dimensions are known via Image.getSize, the image gets stretched.

In other words, if we avoid rendering the image until we know the actual size to render it, it doesn't get blurred.
The following patch (diff for HTMLImage.js) fixes the issue:

10c10,11
<             height: props.imagesInitialDimensions.height
---
>             height: props.imagesInitialDimensions.height,
>             indeterminate: (!props.style || !props.style.width || !props.style.height)
80c81,82
<                 height: typeof styleHeight === 'string' && styleHeight.search('%') !== -1 ? styleHeight : parseInt(styleHeight, 10)
---
>                 height: typeof styleHeight === 'string' && styleHeight.search('%') !== -1 ? styleHeight : parseInt(styleHeight, 10),
>                 indeterminate: false
92c94
<                 this.setState({ width: optimalWidth, height: optimalHeight, error: false });
---
>                 this.setState({ width: optimalWidth, height: optimalHeight, indeterminate: false, error: false });
117a120,125
>     get placeholderImage () {
>         return (
>             <View style={{width: this.props.imagesInitialDimensions.width, height: this.props.imagesInitialDimensions.height}} />
>         );
>     }
> 
120,121c128,134
< 
<         return !this.state.error ? this.validImage(source, style, passProps) : this.errorImage;
---
>         if (this.state.error) {
>             return this.errorImage;
>         } 
>         if (this.state.indeterminate) {
>             return this.placeholderImage;
>         }
>         return this.validImage(source, style, passProps);

I'm not sure if this is a React Native bug or an issue with this library. I'm a React Native noob so I'm not really sure what I'm doing. Shall I submit a PR?

BTW here's a screenshot of the bug in action, the upper image is given fixed dimensions via style props and the bottom one has its dimensions automatically determined, they are the same size (800x600 real pixels) and imagesMaxWidth is set to 360. After applying this diff to HTMLImage.js this bug no longer occurs
img_1543

Edit: applied the diff to this fork: https://github.com/guregu/react-native-render-html

All 11 comments

Hello, I had the same issue (only tested on iOS 10 on iPhone 6S). I spent a lot of time aimlessly debugging and I think I figured it out.
The problem seems to be something like this:

  • Dimensions are unknown so the image gets rendered with props.imagesInitialDimensions tiny dimensions (100x100 by default?).
  • This is a total guess, but React caches the tiny image instead of the original one?
  • After the real dimensions are known via Image.getSize, the image gets stretched.

In other words, if we avoid rendering the image until we know the actual size to render it, it doesn't get blurred.
The following patch (diff for HTMLImage.js) fixes the issue:

10c10,11
<             height: props.imagesInitialDimensions.height
---
>             height: props.imagesInitialDimensions.height,
>             indeterminate: (!props.style || !props.style.width || !props.style.height)
80c81,82
<                 height: typeof styleHeight === 'string' && styleHeight.search('%') !== -1 ? styleHeight : parseInt(styleHeight, 10)
---
>                 height: typeof styleHeight === 'string' && styleHeight.search('%') !== -1 ? styleHeight : parseInt(styleHeight, 10),
>                 indeterminate: false
92c94
<                 this.setState({ width: optimalWidth, height: optimalHeight, error: false });
---
>                 this.setState({ width: optimalWidth, height: optimalHeight, indeterminate: false, error: false });
117a120,125
>     get placeholderImage () {
>         return (
>             <View style={{width: this.props.imagesInitialDimensions.width, height: this.props.imagesInitialDimensions.height}} />
>         );
>     }
> 
120,121c128,134
< 
<         return !this.state.error ? this.validImage(source, style, passProps) : this.errorImage;
---
>         if (this.state.error) {
>             return this.errorImage;
>         } 
>         if (this.state.indeterminate) {
>             return this.placeholderImage;
>         }
>         return this.validImage(source, style, passProps);

I'm not sure if this is a React Native bug or an issue with this library. I'm a React Native noob so I'm not really sure what I'm doing. Shall I submit a PR?

BTW here's a screenshot of the bug in action, the upper image is given fixed dimensions via style props and the bottom one has its dimensions automatically determined, they are the same size (800x600 real pixels) and imagesMaxWidth is set to 360. After applying this diff to HTMLImage.js this bug no longer occurs
img_1543

Edit: applied the diff to this fork: https://github.com/guregu/react-native-render-html

Thanks for your input @guregu, this makes a lot of sense.

I'll take a look into this later and maybe try to trigger a re-render instead of waiting for the image to be loaded to render it. I don't think the UX would be very good if the height of the content changes while the user is reading it.

Thanks @guregu it worked perfect,

i have also done with little hack, i did edit HTMLimage.js and gave to static height,

but now i am happy with your code

Here is the patch content you can use with https://www.npmjs.com/package/patch-package

diff --git a/node_modules/react-native-render-html/src/HTMLImage.js b/node_modules/react-native-render-html/src/HTMLImage.js
index 5406cb2..78ab662 100644
--- a/node_modules/react-native-render-html/src/HTMLImage.js
+++ b/node_modules/react-native-render-html/src/HTMLImage.js
@@ -7,7 +7,8 @@ export default class HTMLImage extends PureComponent {
         super(props);
         this.state = {
             width: props.imagesInitialDimensions.width,
-            height: props.imagesInitialDimensions.height
+            height: props.imagesInitialDimensions.height,
+            indeterminate: (!props.style || !props.style.width || !props.style.height)
         };
     }

@@ -77,7 +78,8 @@ export default class HTMLImage extends PureComponent {
         if (styleWidth && styleHeight) {
             return this.setState({
                 width: typeof styleWidth === 'string' && styleWidth.search('%') !== -1 ? styleWidth : parseInt(styleWidth, 10),
-                height: typeof styleHeight === 'string' && styleHeight.search('%') !== -1 ? styleHeight : parseInt(styleHeight, 10)
+                height: typeof styleHeight === 'string' && styleHeight.search('%') !== -1 ? styleHeight : parseInt(styleHeight, 10),
+                indeterminate: false
             });
         }
         // Fetch image dimensions only if they aren't supplied or if with or height is missing
@@ -89,7 +91,7 @@ export default class HTMLImage extends PureComponent {
                 }
                 const optimalWidth = imagesMaxWidth <= originalWidth ? imagesMaxWidth : originalWidth;
                 const optimalHeight = (optimalWidth * originalHeight) / originalWidth;
-                this.setState({ width: optimalWidth, height: optimalHeight, error: false });
+                this.setState({ width: optimalWidth, height: optimalHeight, indeterminate: false, error: false });
             },
             () => {
                 this.setState({ error: true });
@@ -115,9 +117,21 @@ export default class HTMLImage extends PureComponent {
         );
     }

+    get placeholderImage () {
+        return (
+            <View style={{width: this.props.imagesInitialDimensions.width, height: this.props.imagesInitialDimensions.height}} />
+        );
+    }
+
     render () {
         const { source, style, passProps } = this.props;

-        return !this.state.error ? this.validImage(source, style, passProps) : this.errorImage;
+        if (this.state.error) {
+            return this.errorImage;
+        } 
+        if (this.state.indeterminate) {
+            return this.placeholderImage;
+        }
+        return this.validImage(source, style, passProps);
     }
 }

Try to edit file HTMLImage.js
validImage (source, style, props = {}) {
return (
<Image
source={source}
style={[style, { width: Dimensions.get('window').width, height: this.state.height, resizeMode: 'cover' }]}
{...props}
/>
);
}

Before:

After:

Dimensions.get('window').width

This really work well!!

@JaeWangL
You don't need to update their original package code.
You can set the imagesInitialDimensions props like this.

<HTML 
  html={itemId.description}
  imagesMaxWidth={Dimensions.get('window').width}
  imagesInitialDimensions={
    {
      width: Dimensions.get('window').width
    }
  }
  staticContentMaxWidth={Dimensions.get('window'}
 />

@guregu Thanks you for your proposition! You don't mind if I cherry-pick your patch and integrate it to the next 5.0 release? You'll be credited of course, since I'll be using the git cherry-pick feature.

@guregu It is my understanding that your solution had a small bug, because state.indeterminate was defined as "style prop has both width and height attributes", whilst ignoring width and height props. See my patch on top of your:

diff --git a/src/HTMLImage.js b/src/HTMLImage.js
index 558c7c3..ca1fec8 100644
--- a/src/HTMLImage.js
+++ b/src/HTMLImage.js
@@ -5,10 +5,11 @@ import PropTypes from 'prop-types';
 export default class HTMLImage extends PureComponent {
     constructor (props) {
         super(props);
+        const { styleWidth, styleHeight } = this.getDimensionsFromStyle(props.style, props.height, props.width);
         this.state = {
             width: props.imagesInitialDimensions.width,
             height: props.imagesInitialDimensions.height,
-            indeterminate: (!props.style || !props.style.width || !props.style.height)
+            indeterminate: !(styleWidth && styleHeight)
         };
     }

@jsamr Hello, feel free to use my code however you鈥檇 like.
I鈥檓 not sure why I ignored the props, might have just been an oversight or perhaps there was some issue with the codebase I was integrating it with. Either way if the changes make it more correct then please go ahead and apply them :)
It鈥檚 been a while so I forgot 馃槄

@guregu Awesome! Thank you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

presencewebdesign picture presencewebdesign  路  7Comments

gabriel-tentaculo picture gabriel-tentaculo  路  7Comments

KimJeonghun91 picture KimJeonghun91  路  4Comments

duansiyu picture duansiyu  路  4Comments

jamesawer3 picture jamesawer3  路  3Comments