我的所有图像都是像素艺术图像。我想在没有任何抗锯齿的情况下缩放这些,同时保持宽高比。目前我可以保持纵横比,但缩放是抗锯齿,因此图像模糊。
这是一张图片:
以下是我当前代码的外观:
<Image key={attr_name} source={{uri:attr_value}} resizeMode="contain" style={{ flex:1 }} resizeMethod="resize" />;
以下是我在iOS模拟器中的屏幕截图:http://i.imgur.com/pbEUz9S.png
在网络上,我们使用CSS完成此任务:
.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上找到的一个很棒的主题但它适用于网络 - Disable Interpolation when Scaling a <canvas>
答案 0 :(得分:1)
有一个解决方案:https://github.com/react-native-community/react-native-svg
如果使用此库提供的<Image />
,它将被像素化(类似于image-rendering: pixelated
CSS效果)。
在您的情况下:
<Image key={attr_name} source={{uri:attr_value}} resizeMode="contain" style={{ flex:1 }} resizeMethod="resize" />;
成为
<Svg><Image key={attr_name} href={{uri:attr_value}} height={...} width={...} /></Svg>
我很好奇,您终于找到了解决方案吗?
答案 1 :(得分:0)
我为自己找到了一个解决方案,我不喜欢它,但它现在是一个权宜之计。
如果您有解决方案,请分享您的解决方案。
我所做的是使用plot(DJI.raw$Date, DJI.raw$InterDay < -4, pch=19, col=2, type='h',
xlab="Year", ylab="Days with > 4% change", xaxt="n",
cex.axis=.7, cex.main=.8, cex.lab =.8,las=2,
main = "Clustering of big drop days")
axis(1, at = DJI.raw$Date[which(DJI.raw$InterDay < -4)],
labels = format(DJI.raw$Date[which(DJI.raw$InterDay < -4)], "%Y"))
。我最初的目标是做WebView
,但它似乎不起作用,似乎在iOS Safari中没有完全支持。所以我只是使用canvas.toDataURL
调整WebView
的大小。在html中,我使用原始帖子中的样式表:
transparent backgroundColor
用法:
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
适用于Android和iOS。
答案 2 :(得分:0)
对于这个建议的迟到感到抱歉,但我是新来的。无论如何,我不确定您是否正在寻求帮助来编写自己的应用程序来执行此操作,或者只是寻找使用现有应用程序执行此操作的任何方法,但如果它是后者,那么这是一个想法。
对于任何桌面操作系统,只需使用一个好的图像编辑器(例如= Gimp)&amp;使用&#34;调整大小&#34;放大图像。 &安培;选择大多数图像编辑调用的选择&#34;最近邻居&#34;或&#34;无&#34; (它完全符合你的要求)。
对于android(我唯一的设备),我的主要图像编辑器是&#34;照片编辑器&#34; (通过dev.macgyver)。使用它,使用&#34;调整大小&#34;来放大你的图像,然后进入&#34;效果&#34;菜单,选择&#34; Mosaic&#34;,&amp;调整它,使它看起来像是使用&#34;最近邻居/无&#34;放大。 (其他一些Android图像编辑器也应该有Mosaic功能,但他们可能称之为Pixelate。)我希望这会有所帮助。