首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在没有消除锯齿的情况下放大像素图片

在没有消除锯齿的情况下放大像素图片
EN

Stack Overflow用户
提问于 2017-05-26 14:17:19
回答 3查看 1.5K关注 0票数 1

我所有的图片都是像素艺术图片。我想在保持纵横比的同时,不使用任何抗锯齿来缩放它们。目前我可以保持宽高比,但是缩放是抗锯齿的,所以图像是模糊的。

这是一张图片:

下面是它在我当前代码中的样子:

代码语言:javascript
复制
<Image key={attr_name} source={{uri:attr_value}} resizeMode="contain" style={{ flex:1 }} resizeMethod="resize" />;

下面是我的iOS模拟器中的一个屏幕截图:http://i.imgur.com/pbEUz9S.png

在web上,我们使用CSS来实现这一点:

代码语言:javascript
复制
.pixelated-img {
    image-rendering: optimizeSpeed;
    image-rendering: -moz-crisp-edges;
    image-rendering: -o-crisp-edges;
    image-rendering: -webkit-optimize-contrast;
    image-rendering: optimize-contrast;
    -ms-interpolation-mode: nearest-neighbor;
    image-rendering: pixelated;
}

编辑后添加一个我在stackoverflow上找到的很棒的主题,但它是为web - Disable Interpolation when Scaling a 准备的

EN

回答 3

Stack Overflow用户

发布于 2019-11-25 21:41:40

有一个解决方案:https://github.com/react-native-community/react-native-svg如果你使用这个库提供的<Image />,它将被像素化(就像image-rendering: pixelated CSS效果一样)。

在您的案例中:

代码语言:javascript
复制
<Image key={attr_name} source={{uri:attr_value}} resizeMode="contain" style={{ flex:1 }} resizeMethod="resize" />;

变成了

代码语言:javascript
复制
<Svg><Image key={attr_name} href={{uri:attr_value}} height={...} width={...} /></Svg>

我很好奇,你最终找到解决方案了吗?

票数 1
EN

Stack Overflow用户

发布于 2017-05-28 17:50:11

我有一个自己的解决方案,我不喜欢它,但这是目前的权宜之计。

如果你有解决方案,请分享你的解决方案。

我所做的就是使用WebView。我最初的目标是做canvas.toDataURL,但它似乎不工作,似乎在iOS safari上没有完全支持。所以我只是用transparent backgroundColor来调整WebView的大小。在html中,我使用了原始帖子中的样式表:

代码语言:javascript
复制
import React, { Component } from 'react'
import { Image, Text, View, WebView } from 'react-native'

const html = `
    <html>
        <head>
            <style>
                body {
                    margin: 0;
                }
                img {
                    image-rendering: optimizeSpeed;
                    image-rendering: -moz-crisp-edges;
                    image-rendering: -o-crisp-edges;
                    image-rendering: -webkit-optimize-contrast;
                    image-rendering: optimize-contrast;
                    -ms-interpolation-mode: nearest-neighbor;
                    image-rendering: pixelated;
                }
            </style>
            <script>
                function whenRNPostMessageReady(cb) {
                    if (postMessage.length === 1) cb();
                    else setTimeout(function() { whenRNPostMessageReady(cb) }, 1000);
                }

                function resizePixelated() {
                    var url = '%%%URL%%%';

                    var img = document.createElement('img');
                    document.body.appendChild(img);
                    img.addEventListener('load', handleImageLoad, false);
                    img.addEventListener('error', handleImageError, false);
                    img.setAttribute('id', 'image');
                    img.setAttribute('src', url);
                }

                function handleImageLoad(e) {
                    if (this.naturalHeight + this.naturalWidth === 0) {
                        this.onerror();
                        return;
                    }

                    var WANTED_HEIGHT = %%%HEIGHT%%%;
                    var WANTED_WIDTH = %%%WIDTH%%%;

                    var naturalHeight = this.naturalHeight;
                    var naturalWidth = this.naturalWidth;

                    postMessage('LOG:' + 'naturalHeight: ' + naturalHeight + ' naturalWidth: ' + naturalWidth);
                    postMessage('LOG:' + 'WANTED_HEIGHT: ' + WANTED_HEIGHT + ' WANTED_WIDTH: ' + WANTED_WIDTH);

                    var factorHeight = WANTED_HEIGHT / naturalHeight;
                    var factorWidth = WANTED_WIDTH / naturalWidth;

                    postMessage('LOG:' + 'factorHeight: ' + factorHeight + ' factorWidth: ' + factorWidth);

                    var byWidthHeight = naturalHeight * factorWidth;
                    var byHeightWidth = naturalWidth * factorHeight;
                    postMessage('LOG:' + 'byWidthHeight: ' + byWidthHeight + ' byHeightWidth: ' + byHeightWidth);

                    var sortable = [
                        { sorter:byWidthHeight, variable:'height', height:byWidthHeight, width:WANTED_WIDTH },
                        { sorter:byHeightWidth, variable:'width',  height:WANTED_HEIGHT, width:byHeightWidth }
                    ];

                    sortable.sort(function byDescSorter(a, b) {
                        return b.sorter - a.sorter;
                    });

                    postMessage('LOG:' + JSON.stringify(sortable));

                    for (var i=0; i<sortable.length; i++) {
                        var variable = sortable[i].variable;
                        var sorter = sortable[i].sorter;
                        if (variable == 'height') {
                            if (sorter <= WANTED_HEIGHT) {
                                break;
                            }
                        } else if (variable == 'width') {
                            if (sorter <= WANTED_WIDTH) {
                                break;
                            }
                        }
                    }

                    if (i >= sortable.length) {
                        postMessage('LOG: THIS SHOULD NEVER HAPPEN');
                    }

                    postMessage('LOG:' + i);

                    var drawWidth = Math.round(sortable[i].width);
                    var drawHeight = Math.round(sortable[i].height);

                    postMessage('LOG:will draw now at width: ' + drawWidth + ' drawHeight: ' + drawHeight);

                    var img = document.getElementById('image');
                    img.setAttribute('width', drawWidth);
                    img.setAttribute('height', drawHeight);

                    var dataurl = '';

                    postMessage('OK:' + drawWidth + '$' + drawHeight + '$' + dataurl);
                }

                function handleImageError() {
                    postMessage('Image failed to load.');
                }

                window.addEventListener('DOMContentLoaded', function() {
                    whenRNPostMessageReady(resizePixelated);
                }, false);
            </script>
        </head>
        <body></body>
    </html>
`;

const STATUS = {
    INIT: 'INIT',
    FAIL: 'FAIL',
    SUCCESS: 'SUCCESS'
}

class ImagePixelated extends Component {
    /* props
    url: dataURL or web url
    height?: number or undefined - set either height or width or both, but one must be set
    width?: number or undefined
    */
    state = {
        status: STATUS.INIT,
        reason: null, // set on STATUS.FAIL
        dataurl: null, // set on STATUS.SUCCESS
        height: null, // set on STATUS.SUCCESS
        width: null // set on STATUS.SUCCESS
    }
    handleMessage = e => {
        const {nativeEvent:{ data }} = e;

        const [action, payload] = data.split(/\:(.+)/); // split on first instance of colon
        // console.log('action:', action, 'payload:', payload);

        switch (action) {
            case 'LOG': {
                    // console.log(payload);
                break;
            }
            case 'OK': {
                    let [ width, height, dataurl ] = data.substr('OK:'.length).split('$');
                    width = parseInt(width);
                    height = parseInt(height);
                    console.log('width:', width, 'height:', height, 'dataurl:', dataurl);
                    this.setState(()=>({status:STATUS.SUCCESS, dataurl, height, width}));
                break;
            }
            default:
                // FAILED // TODO:
                this.setState(()=>({status:STATUS.FAIL, reason:data}));
        }
    }
    getHtml() {
        const { height, width, url } = this.props;
        let html_propified = html.replace('%%%URL%%%', url);

        // because my scaling in WebView is to get max height while maintaining aspect ratio, if one (height or width) is not specificed, instead of setting to undefined, set the other to 1000

        if (isNaN(height) || height === undefined || height === null) html_propified = html_propified.replace('%%%HEIGHT%%%', '1000');
        else html_propified = html_propified.replace('%%%HEIGHT%%%', height);

        if (isNaN(width) || width === undefined || width === null) html_propified = html_propified.replace('%%%WIDTH%%%', '1000');
        else html_propified = html_propified.replace('%%%WIDTH%%%', width);

        return html_propified;
    }
    render() {
        const { status } = this.state;
        switch (status) {
            case STATUS.INIT: {
                const { height, width } = this.state;
                // android: transparent the background in webview here too, because when switch to success, where display is not none, we see a flash of white
                // android: the wrap of view is needed because WebView does not respect height as its a RN bug
                return (
                    <View style={{ display:'none' }}>
                        <WebView source={{ html:this.getHtml() }} style={{ display:'none', backgroundColor:'transparent' }} onMessage={this.handleMessage} />
                    </View>
                )
            }
            case STATUS.FAIL: {
                const { reason } = this.state;
                return (
                    <View>
                        <Text>{reason}</Text>
                    </View>
                )
            }
            case STATUS.SUCCESS: {
                // const { dataurl, height, width } = this.state;
                // return <Image source={{ uri:dataurl, height, width }}  />
                const { height, width } = this.state;
                return (
                    <View style={{ height, width }}>
                        <WebView source={{ html:this.getHtml() }} style={{ height, width, backgroundColor:'transparent' }} />
                    </View>
                )
            }
            // no-default
        }
    }
}

export default ImagePixelated

用法:

代码语言:javascript
复制
<ImagePixelated url={entity.image} height={90} width={90} />

适用于安卓和iOS。

票数 0
EN

Stack Overflow用户

发布于 2018-04-25 14:22:05

很抱歉这个建议来得太晚了,但我是新来的。无论如何,我不确定你是在请求帮助编写自己的应用程序来实现这一点,还是只是在寻找任何方法来使用现有的应用程序来实现这一点,但如果是后者,那么这里有一个想法。

对于任何桌面操作系统,只需使用一个好的图像编辑器(例如: Gimp),并使用“调整大小”来放大您的图像,并选择大多数图像编辑器称之为“最近的邻居”或“无”的选项(它所做的正是您想要的)。

对于android (我现在唯一的设备),我的主要图片编辑器是“图片编辑器”(由dev.macgyver开发)。使用它,用“调整大小”放大你的图像,然后进入“效果”菜单,选择“马赛克”,并调整它,使它看起来像是用“最近的邻居/无”放大的。(其他一些android图像编辑器也应该有马赛克功能,但他们可能会称之为像素化。)我希望这能有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44194861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档