2015-10-30 11:11:41 u011347072 阅读数 674
       所表示的是每英寸所拥有的像素(Pixel)数目。因此PPI数值越高,即代表显示屏能够以越高的密度显示图像。当然,显示的密度越高,拟真度就越高。
          Pixels Per Inch是图像分辨率的单位,图像PPI值越高,画面的细节就会越丰富,因为单位面积的像素数量更多,所以数码相机拍出来的图片因品牌或生产时间不同可能有所不同,常见的有72PPI,180PPI和300PPI,默认出来就是这么多(A710拍出的是180PPI)。
        
如图,iPad2 是768 x 1024,iPad Retina 是1536 x 2048,开发时都按 768 * 1024 操作。但实际上两者有一倍差异。为了达到最佳效果,使用的图片大小不一样。这时候就用同一个名称,但 Retina 的图加上 @2x 后缀。系统加载图片时,在 iPad2 上会加载 @1x 的图在 1536 * 2048 的设备上,会加载 @2x 的。@3x 现在用于 iPhone 6/6+ 上

附带一提:iOS8渲染操作中使用前缀带有@1x、@2x 和@3x 的测试图像,代码会优先载入3x 图像。@2x图像不被加载。使用图像文件和XCAsset均不行。

用二倍图是为了适配iphone4以上的设备(所谓的retina屏),如果你的项目要适配3gs,那么你要备两套图,一套是一倍图,比如image.png(320*480),另一套是二倍图,比如image@2x.png(640*960)。当然你在用的时候,比如UIImage *image = [UIImage imageNamed:@"image.png"],或者UIImage *image = [UIImage imageNamed:@"image"],这两种方法,在iphone4以上系统会自动去找image@2x.png图片来显示。

1、在项目中,无论代码还是 xib只用不带@2x的图片做为名字,就像这样UIImage *image = [UIImage imageNamed:@"image.png"]

2、在真实文件中必须有@2x 的文件,不带@2x 的文件可有可无(如果有,可以在 xib 中更好的显示,因为xib 只认不带@2x 的图片预览)
2019-11-13 21:42:20 chuanyue11 阅读数 71

IOS图片生成工具(@1X,@2X,@3X)

在进行IOS开发过程中,经常需要为了适配不同分辨率的设备而准备不同尺寸的图片。由于本人长期从事后台研发工作,对前端及UI常用工具(比如PS)并不熟悉,于是开发了下面这个工具对一个大尺寸的图片进行裁剪,生成1倍、2倍、3倍尺寸的图片,方便进行IOS开发。

工具介绍

该工具接受两个参数,分别为源图片文件或目录和目标图片存放文件夹。源图片为分辨率高于所有裁剪结果图片的分辨率(@1X,@2X,@3X)。

裁剪结果图片的尺寸写在ResizeImage类开头处,可以根据需要进行修改。

工具代码

package tools;

import common.Base;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;

/**
 * Genarate @1X, @2X, @3X pictures.
 *
 * @author zjm
 */
public class ResizeImage extends Base {
    private static final Logger LOGGER = LoggerFactory.getLogger(ResizeImage.class);

    /**
     * {width, height}
     */
    //    private static final int[] SIZE_3X = new int[] { 300, 402 };
    //    private static final int[] SIZE_2X = new int[] { 200, 268 };
    //    private static final int[] SIZE_1X = new int[] { 100, 134 };
    private static final int[] SIZE_3X = new int[] { 300, 300 };
    private static final int[] SIZE_2X = new int[] { 200, 200 };
    private static final int[] SIZE_1X = new int[] { 100, 100 };

    private String srcFileOrDirctory;
    private String destDirectory;

    public ResizeImage() {

    }

    public ResizeImage(String srcFileOrDirctory, String destFileOrDirectory) {
        this.srcFileOrDirctory = srcFileOrDirctory;
        this.destDirectory = destFileOrDirectory;
    }

    public String getSrcFileOrDirctory() {
        return srcFileOrDirctory;
    }

    public void setSrcFileOrDirctory(String srcFileOrDirctory) {
        this.srcFileOrDirctory = srcFileOrDirctory;
    }

    public String getDestDirectory() {
        return destDirectory;
    }

    public void setDestDirectory(String destDirectory) {
        this.destDirectory = destDirectory;
    }

    public void resizeImage() throws Exception {
        LOGGER.debug("Resize image parameters: src - {}, dest - {}", srcFileOrDirctory, destDirectory);

        File src = new File(srcFileOrDirctory);

        File dest = new File(destDirectory);
        if (dest.exists() && dest.isFile()) {
            throw new IllegalArgumentException("Not a directory: " + dest);
        }
        dest.mkdirs();

        if (src.exists() && src.isDirectory()) {
            File[] images = src.listFiles();
            for (File image : images) {
                resizeImage(srcFileOrDirctory, destDirectory);
            }
        } else if (src.exists() && src.isFile()) {
            resizeImage(srcFileOrDirctory, destDirectory);
        } else {
            throw new IllegalArgumentException("No such file or directory: " + src);
        }
    }

    private void resizeImage(String src, String dest) throws Exception {
        File destImage;

        destImage = new File(dest, getTypePrefix(src) + "@3X." + getTypeAppendix(src));
        resizeImage(src, destImage.getAbsolutePath(), SIZE_3X);

        destImage = new File(dest, getTypePrefix(src) + "@2X." + getTypeAppendix(src));
        resizeImage(src, destImage.getAbsolutePath(), SIZE_2X);

        destImage = new File(dest, getTypePrefix(src) + "@1X." + getTypeAppendix(src));
        resizeImage(src, destImage.getAbsolutePath(), SIZE_1X);
    }

    private void resizeImage(String src, String dest, int[] size) throws Exception {
        LOGGER.debug("Resizing image {} to {} in size {} ...", src, dest, Arrays.toString(size));

        BufferedImage srcImage = ImageIO.read(new File(src));

        BufferedImage destImage = new BufferedImage(size[0], size[1], srcImage.getType());
        Graphics2D destGraph = destImage.createGraphics();
        destGraph.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        destGraph.drawImage(srcImage, 0, 0, size[0], size[1], 0, 0, srcImage.getWidth(), srcImage.getHeight(), null);
        destGraph.dispose();

        ImageIO.write(destImage, getTypeAppendix(src), new File(dest));

        LOGGER.debug("A new image {} is created.", dest);
    }

    private String getTypeAppendix(String image) {
        int lastIndex = image.lastIndexOf(".");
        return image.substring(lastIndex + 1);
    }

    private String getTypePrefix(String image) {
        int lastSlashIndex = image.lastIndexOf("/");
        int lastDotIndex = image.lastIndexOf(".");
        return image.substring(lastSlashIndex + 1, lastDotIndex);
    }

    public static void main(String[] args) throws Exception {
        if (args.length != 2) {
            LOGGER.error("Invalid arguments. Usage: {} <source image file or directory> <dest image directory>",
                    ResizeImage.class.getSimpleName());
            System.exit(1);
        }
        new ResizeImage(args[0], args[1]).resizeImage();
    }
}

2019-01-18 00:07:27 liuchuo 阅读数 1547

iOS开发中,会要求导入@1x、@2x和@3x:

使用@1x格式iPhone3GS

使用@2x格式iPhone 4,4S,5,5S,5C,SE,6,6S,7,8,XR

使用@3x格式iPhone 6Plus、6sPlus、7Plus、8Plus、X、XS、XS Max

这样在开发过程中,将三种图片(比如分别为1.png、1@2x.png和1@3x.png)导入到工程图库中的时候可以自动被识别为1x、2x和3x大小的图片

可以利用Mac系统中自带的服务自己制作一个快速生成@1x、@2x和@3x图片的功能

首先spotlight搜索Automator,然后按Enter打开

Snip20160127_93

新建文稿 

Snip20160127_94

选取文稿类型为 快速操作

Snip20160127_95

在工作流程收到当前的后面选择图像文件

Snip20160127_108

在左边窗口的“操作”下,选择“资源库”中的“文件和文件夹”,将右侧中的“给访达项目重新命名”拖入最右侧的大窗口中,(如果警告提示是否要增加一个“拷贝访达项目”操作,选择“不添加”),选择“添加文本”,在输入框中输入【@3x

拖入“复制访达项目

选择左侧“资源库”中的照片,将“缩放图像”拖入右侧窗口(如果警告提示是否要增加一个“拷贝访达项目”操作,选择“不添加”),并选择“按百分比”,输入【66

再拖入“文件和文件夹”下的“给访达项目重新命名”,并选择【替换文本】,查找【】,以【仅基本名称】;再拖入“文件和文件夹”下的“给访达项目重新命名”,并选择【替换文本】,查找【@3x”的副本】,以【仅基本名称】,替换成【@2x

拖入“复制访达项目”,选择左侧“资源库”中的照片,将“缩放图像”拖入右侧窗口(如果警告提示是否要增加一个“拷贝访达项目”操作,选择“不添加”),并选择“按百分比”,输入【50

再拖入“文件和文件夹”下的“给访达项目重新命名”,并选择【替换文本】,查找【】,以【仅基本名称】,再拖入“文件和文件夹”下的“给访达项目重新命名”,并选择【替换文本】,查找【@2x”的副本】,以【仅基本名称

然后保存,将“快速操作”存储为“制作@2x@3x图片

 

每次使用的时候,只需选中图片,选择访达 -> 服务 -> 制作@2x@3x图片就会自动生成三个图片:1.png、1@2x.png和1@3x.png

最终效果~

 

2016-04-14 23:07:33 sinat_34194127 阅读数 8552

1x 、2x 、3x图片介绍

手机屏幕分两种

  1. 视网膜屏:
    • 又叫Retain屏幕,就是高清视网膜屏幕,分辨率宽高是标准屏幕分辨率的2倍
  2. 非视网膜屏
    • 又叫非Retain屏,是标准分辨率

分辨率

  • 概念:分辨率的意思就是把屏幕进行横向、纵向等分,通常描述手机屏幕用来表示,在retina屏幕下,一个点表示两个像素,在非retina屏幕下,一个点表示一个像素,而像素,就是常说的分辨率,在iPhone6 Plus下,一个点表示3个像素

iPhone手机的分辨率


  • 在上图可以看出
    1. iPhone3GS的手机,是非视网膜屏幕,它的点 和 分辨率 是相同的,也就是两者相除 得 1
    2. 在iphone4/4S/5/5C//5S/6,它们都是视网膜屏幕,分辨率正好是点的两倍,相除得2
    3. 而在iPhone6 Plus,虽然也是视网膜屏幕,但是分辨率是点的三倍,也就是相除得3

1x 2x 3x 图片

  • 由于不同手机的屏幕的分辨率和它的点的倍数,是不同的,所以我们在实际开发中需要准备多套图片
  • 由于目前只存在1倍,2倍,3倍,这几种,所以目前准备的图片就分 1x,2x,3x图,当然由于只有3GS手机才是1x图,而3GS手机,基本上已经无人使用,可能很多公司已经不再去制作1x图片

图片的命名规则:

  • 1x图片: 直接使用文件名 btn_left.png
  • 2x图片: 在文件名后加上@2x标识 btn_left@2x.png
  • 3x图片: 在文件后加上@3x标识 btn_left@3x.png

总结

  1. 在同样一个尺寸的屏幕下由于使用的屏幕不一样(retina和非retina),所以造成的屏幕分辨率会不同.也就是说,同样是30*30的像素,在3.5 inch大小的屏幕上,如果是非retina显示会大一些,retina屏幕显示会小一些。
  2. 在开发中使用的是点.(比如 30 * 30 ,不是表示30像素,而是表示30点,这样的话iOS系统会自动把点转换为对应的像素)
    • 非retina屏幕1个点表示1像素
    • retian屏幕1个点表示2像素
    • iPhone6 Plus 下1个点表示3像素
  3. 因为程序中的是,iOS系统会自动把点转换为不同的像素去找图片,所以图片对应的也要准备多份不同的图片,
    • @2X:视网膜屏幕,在原来点坐标的大小上乘以2
    • @3X:在原来的坐标的大小上乘以3
2016-08-07 23:27:53 gongwutianya 阅读数 10748

一、图片格式@2x与@3x

应对非视网膜和视网膜屏,APP有时会提供不同大小的图片,1倍图和2倍图和3倍图,它们的像素与1倍数图相比相差2倍或者3倍。

命名规则:2倍图在1倍图的名字后加 @2x

  • 普通:sample.png 
  • 2倍:sample@2x.png 
  • 3倍:sample@3x.png 

系统用“sample”寻找图片的时候,会自动根据设备屏幕取对应的图片

由于retina屏幕的普及,现在工程中用得最多的是@2x和@3x图片

二、加载图片的方法

图片资源在工程的位置如下图


方法一:

-(void)setImageView1{
    UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(80, 80, 180, 180)];
    imageView.backgroundColor = [UIColor blueColor];
//只有test@2x与test@3x图片
    //4s 5 5s 6 6s 会自动加载test@2x图片
    //6Plus 6sPlus 会自动加载test@3x图片
    imageView.image = [UIImage imageNamed:@"test"];
    [self.view addSubview:imageView];
}
PS:这种方法可以加载到逻辑路径中的资源 也可以加载到Assets.xcassets中的资源,而且会根据设备自动匹配@2x和@3x图片。

方法二:

-(void)setImageView2{
    //此处的路径是物理路径如果是逻辑路径是获取不到资源的
    //这里填写test@2x或者test@3x都可以(只要这个文件在wwwwww这个文件夹真实存在即可),主要是获得这个物理路径。
    //获得到这个路径之后 后边才会根据设备自动加载@2x图片或者@3x图片。
    NSString *path = [[NSBundle mainBundle] pathForResource:@"wwwwww/test@2x" ofType:@"png"];
    NSLog(@"path = %@",path);
    //因为www是逻辑路径,用此方法是加载不到这个文件的
     NSString *path1 = [[NSBundle mainBundle] pathForResource:@"www/test@2x" ofType:@"png"];
    //所以path1的值为null;
    NSLog(@"path1 = %@",path1);//path1 = null;
    UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(80, 80, 180, 180)];
    imageView.backgroundColor = [UIColor blueColor];
    //4s 5 5s 6 6s 会自动加载test@2x图片
    //6Plus 6sPlus 会自动加载test@3x图片
    imageView.image = [UIImage imageWithContentsOfFile:path];
    [self.view addSubview:imageView];
}

PS1:这种方法如果加载物理路径中的资源文件需要把路径指定完全。

PS2:逻辑路径中的文件其实也可以用这中方法来加载,只不过逻辑路径中的资源文件的存储位置跟文件夹显示的路径没有关系,如下:


-(void)setImageView3{
    //从此也可以看出逻辑路径下的资源文件的路径并没有真正存在 都是在工程的 根目录下app/资源文件
    UIImageView * imageViewImage = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 100, 100)];
    imageViewImage.backgroundColor = [UIColor blueColor];
    
    //下面两种写法都没有写成:test/inTest/inTest 这种物理路径的方式,其实写成这样是识别不到inTest.png文件的 因为路径并不存在
#if 1
    NSString * mainPath = [[NSBundle mainBundle] resourcePath];
    NSString * path = [NSString stringWithFormat:@"%@/inTest",mainPath];
#else
    NSString * path = [[NSBundle mainBundle] pathForResource:@"inTest" ofType:@"png"];
#endif
    UIImage * image = [UIImage imageWithContentsOfFile:path];
    imageViewImage.image = image;
    [self.view addSubview:imageViewImage];
}

三、imageNamed 与 imageWithContentsOfFile的区别

myImage = [UIImage imageNamed:@"icon.png"];

这种方法在一些图片很少,或者图片很小的程序里是ok的。
但是,在大量加载图片的程序里,请千万不要这样做。
为什么呢 ???????

这种方法在application bundle的顶层文件夹寻找由供应的名字的图象 。 如果找到图片,装载到iPhone系统缓存图象。那意味图片是(理论上)放在内存里作为cache的。

试想你图片多了,是什么后果``````

图片cache极有可能不会响应 memory warnings and release its objects

所以,用图片的时候一定要小心的alloc和release
推荐使用

NSString *path = [[NSBundle mainBundle] pathForResource:@”icon” ofType:@”png”];
myImage = [UIImage imageWithContentsOfFile:path];
四、用UIImage加载图像的方法很多,常用如下:

    1、用imageNamed函数

[UIImage imageNamed:ImageName];

    2、用imageWithContentsOfFile函数

[UIImage imageWithContentsOfFile:path];

    3、用NSData的方式加载,例如:

NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
NSData *image = [NSData dataWithContentsOfFile:filePath];
[UIImage imageWithData:image];

        1)用imageNamed的方式加载时,系统会把图像Cache到内存。如果图像比较大,或者图像比较多,用这种方式会消耗很大的内存,而且释放图像的 内存是一件相对来说比较麻烦的事情。例如:如果利用imageNamed的方式加载图像到一个动态数组NSMutableArray,然后将将数组赋予一 个UIView的对象的animationImages进行逐帧动画,那么这将会很有可能造成内存泄露。并且释放图像所占据的内存也不会那么简单。但是利 用imageNamed加载图像也有自己的优势。对于同一个图像系统只会把它Cache到内存一次,这对于图像的重复利用是非常有优势的。例如:你需要在 一个TableView里重复加载同样一个图标,那么用imageNamed加载图像,系统会把那个图标Cache到内存,在Table里每次利用那个图 像的时候,只会把图片指针指向同一块内存。这种情况使用imageNamed加载图像就会变得非常有效。

    2)利用NSData方式加载时,图像会被系统以数据方式加载到程序。当你不需要重用该图像,或者你需要将图像以数据方式存储到数据库,又或者你要通过网络下载一个很大的图像时,请尽量使用imageWithData的方式加载图像。

    无论用哪种方式加载图像,图像使用结束后,一定要记得显示释放内存。

参考文章:

http://www.cnblogs.com/pengyingh/articles/2355033.html



iOS 图片批量添加@2x

阅读数 1354

iOS开发 2x 3x图

阅读数 21

没有更多推荐了,返回首页