sm4算法加密解密

sm4算法加密解密一、基本知识分组加密(英语:Blockcipher),又称分块加密或块密码,是一种对称密钥算法。它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。 对称加密、加密算法主要可以分为两种,一个是非对称加密算法,另一个就是对称加密算法。对称加密简单来说就是有一个明文,通过一个密钥加密之后得到一个密文,这个密文可以通过相同的密要解密得出和原来相同的明文二、sm…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

一、基本知识

  1. 分组加密(英语:Block cipher),又称分块加密或块密码,是一种对称密钥算法。它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。
  2. 对称加密、加密算法主要可以分为两种,一个是非对称加密算法,另一个就是对称加密算法。对称加密简单来说就是有一个明文,通过一个密钥加密之后得到一个密文,这个密文可以通过相同的密要解密得出和原来相同的明文

二、sm4算法

  1. 算法定义:SM4算法是一种分组密码算法。其分组长度为128bit,密钥长度也为128bit。加密算法与密钥扩展算法均采用32轮非线性迭代结构,以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。SM4算法加/解密算法的结构相同,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。
  2. 基本运算     

       ⊕  异或

      <<<i  循环左移i位

     3.算法实现

sm4算法加密解密

即首先执行32次轮函数迭代运算,然后在对最后一轮数据反序变换并得到密文输出

三、步骤详解

1.轮函数F

 

sm4算法加密解密

示意图

sm4算法加密解密

SM4的轮函数将输入部分看做了4个32bit长度的数据,每轮的后3个部分都向左移动32bit的数据长度,这三组数据异或后进入非线性部分τ和线性部分L,运算后的结果与第一组数据异或置于最右面。如此循环往复32轮,也就是数据一共左移了8个周期,将其中的混乱因素不断扩散至每个bit位中

2.T函数

sm4算法加密解密

s盒如下:

sm4算法加密解密

使用规则:sm4算法加密解密

3.秘钥扩展算法

sm4算法加密解密

系统参数FK的取值

FK0=(A3B1BAC6),FK1=(56AA3350),FK2=(677D9197),FK3=(B27022DC)

固定参数CK的取值

00070e15, 1c232a31, 383f464d, 545b6269,

70777e85, 8c939aa1, a8afb6bd, c4cbd2d9, 

e0e7eef5,  fc030a11,  181f262d, 343b4249,

50575e65, 6c737a81, 888f969d, a4abb2b9,

c0c7ced5,  dce3eaf1,  f8ff060d,  141b2229, 

30373e45, 4c535a61, 686f767d, 848b9299,

a0a7aeb5, bcc3cad1,  d8dfe6ed, f4fb0209,

 10171e25, 2c333a41, 484f565d, 646b7279

四、java代码实现

 

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Random;

/**
 * @ClassName: Sm4Util
 * @Author: tanp
 * @Description: sm4加解密工具类
 * @Date: 2020/5/8 15:24
 */
public class Sm4Util {

    /**
     * 加密标识
     */
    private static final int ENCRYPT = 1;
    /**
     * 解密标识
     */
    private static final int DECRYPT = 0;
    /**
     * F轮函数循环次数
     */
    private static final int ROUND = 32;
    private static final int BLOCK = 16;
    private static final int FOUR = 4;
    private static final int ZERO = 0;

    /**
     * s盒
     */
    private byte[] sbox = {(byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe,
            (byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6,
            0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67,
            (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3,
            (byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06,
            (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91,
            (byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43,
            (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4,
            (byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8,
            (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa,
            0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7,
            (byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83,
            0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8,
            0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda,
            (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56,
            (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1,
            (byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87,
            (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27,
            0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4,
            (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a,
            (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3,
            (byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15,
            (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4,
            (byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32,
            0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d,
            (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca,
            0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f,
            (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd,
            (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b,
            0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb,
            (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41,
            0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31,
            (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d,
            0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4,
            (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c,
            (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09,
            (byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0,
            0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79,
            (byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48};


    /**
     * 固定的ck参数
     */
    private int[] ck = {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
            0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5,
            0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81,
            0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d,
            0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
            0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25,
            0x2c333a41, 0x484f565d, 0x646b7279};

    /**
     * 固定的fk参数
     */
    private int[] fk = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};


    /**
     * @Description 将传入的x参数循环左移num位
     * @Author tanp
     */
    private int leftMove(int x, int num) {
        //假如数据为无符号的数,长度为N,需要循环移动n位。可以用下面的公式:
        //循环左移n位: (x>>(N - n) ) | (x<<n);
        return x << num | x >>> (32 - num);
    }

    /**
     * @Description s盒的非线性变化函数
     * @Author tanp
     */
    private int byteSub(int x) {
        return (sbox[x >>> 24 & 0xFF] & 0xFF) << 24
                | (sbox[x >>> 16 & 0xFF] & 0xFF) << 16
                | (sbox[x >>> 8 & 0xFF] & 0xFF) << 8
                | (sbox[x & 0xFF] & 0xFF);
    }

    /**
     * @Description 轮函数中T函数的线性变化L函数
     * @Author tanp
     */
    private int transLf(int x) {
        //B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8);
        return x ^ leftMove(x, 2) ^ leftMove(x, 10) ^ leftMove(x, 18) ^ leftMove(x, 24);
    }

    /**
     * @Description 秘钥扩展算法中的T'函数的线性变化L函数
     * @Author tanp
     */
    private int transTf(int x) {
        // B^(B<<13|B>>>19)^(B<<23|B>>>9);
        return x ^ leftMove(x, 13) ^ leftMove(x, 23);
    }

    /**
     * @Description 秘钥扩展算法T置换
     * @Author tanp
     */
    private int transTh(int in) {
        return transTf(byteSub(in));
    }

    /**
     * @Description 轮函数T置换
     * @Author tanp
     */
    private int transLth(int in) {
        return transLf(byteSub(in));
    }

    /**
     * @param key       秘钥
     * @param cryptFlag 加解密标识
     * @Description 获取轮秘钥
     * @Author tanp
     */
    private int[] sm4KeyExt(byte[] key, int cryptFlag) {
        int r, mid;
        int[] x = new int[4];
        int[] tmp = new int[4];
        int[] rk = new int[ROUND];
        getValue(key, x, tmp);
        //获取轮秘钥之前,先将秘钥与系统函数FK异或
        for (r = ZERO; r < FOUR; r++) {
            x[r] = x[r] ^ (fk[r]);
        }
        //轮训执行T置换
        for (r = ZERO; r < ROUND; r += FOUR) {
            rk[r] = x[0] ^= transTh(x[1] ^ x[2] ^ x[3] ^ ck[r]);
            rk[r + 1] = x[1] ^= transTh(x[2] ^ x[3] ^ x[0] ^ ck[r + 1]);
            rk[r + 2] = x[2] ^= transTh(x[3] ^ x[0] ^ x[1] ^ ck[r + 2]);
            rk[r + 3] = x[3] ^= transTh(x[0] ^ x[1] ^ x[2] ^ ck[r + 3]);
        }

        // 解密时轮密钥使用顺序:rk31,rk30,...,rk0
        if (cryptFlag == DECRYPT) {
            for (r = 0; r < BLOCK; r++) {
                mid = rk[r];
                rk[r] = rk[31 - r];
                rk[31 - r] = mid;
            }
        }
        return rk;
    }


    /**
     * @Description 轮函数F
     * @param input 加密解密的字节数组
     * @param rk 轮秘钥
     * @Author tanp
     */
    private void sms4Crypt(byte[] input, byte[] output, int[] rk) {
        int r;
        int[] x = new int[4];
        int[] tmp = new int[4];
        getValue(input, x, tmp);
        for (r = ZERO; r < ROUND; r += FOUR) {
            x[0] = x[0] ^ transLth(x[1] ^ x[2] ^ x[3] ^ rk[r]);
            x[1] = x[1] ^ transLth(x[2] ^ x[3] ^ x[0] ^ rk[r + 1]);
            x[2] = x[2] ^ transLth(x[3] ^ x[0] ^ x[1] ^ rk[r + 2]);
            x[3] = x[3] ^ transLth(x[0] ^ x[1] ^ x[2] ^ rk[r + 3]);
        }
        // Reverse
        for (int j = ZERO; j < BLOCK; j += FOUR) {
            output[j] = (byte) (x[3 - j / 4] >>> 24 & 0xFF);
            output[j + 1] = (byte) (x[3 - j / 4] >>> 16 & 0xFF);
            output[j + 2] = (byte) (x[3 - j / 4] >>> 8 & 0xFF);
            output[j + 3] = (byte) (x[3 - j / 4] & 0xFF);
        }
    }

    private void getValue(byte[] input, int[] x, int[] tmp) {
        for (int i = ZERO; i < FOUR; i++) {
            tmp[0] = input[4 * i] & 0xff;
            tmp[1] = input[1 + 4 * i] & 0xff;
            tmp[2] = input[2 + 4 * i] & 0xff;
            tmp[3] = input[3 + 4 * i] & 0xff;
            x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
        }
    }


    /**
     * @param in        需加密或者解密的字节数组
     * @param inLen     加密解密的字节长度
     * @param key       秘钥
     * @param out       加密解密后的字节数组,用来返回
     * @param cryptFlag 加解密标识
     * @Description 加密 解密方法
     * @Author tanp
     */
    private byte[] sms4(byte[] in, int inLen, byte[] key, byte[] out, int cryptFlag) {
        int point = 0;
        //获取轮秘钥
        int[] roundKey = sm4KeyExt(key, cryptFlag);
        byte[] input;
        byte[] output = new byte[16];

        while (inLen >= BLOCK) {
            input = Arrays.copyOfRange(in, point, point + 16);
            //每16个字节执行一次轮函数
            sms4Crypt(input, output, roundKey);
            System.arraycopy(output, 0, out, point, BLOCK);
            inLen -= BLOCK;
            point += BLOCK;
        }
        return out;
    }

    /**
     * 字符串加密
     *
     * @param plaintext 明文
     * @param key       秘钥
     * @return 加密后的明文字符串
     * @Author tanp
     */
    private static String encodeSms4ToHex(String plaintext, byte[] key) {
        if (plaintext == null || plaintext.length() <= 0) {
            return null;
        }
        StringBuilder plaintextBuilder = new StringBuilder(plaintext);
        for (int i = plaintextBuilder.toString().getBytes().length % BLOCK; i < BLOCK; i++) {
            plaintextBuilder.append('\0');
        }
        plaintext = plaintextBuilder.toString();
        return bytesToHexString(encodeSms4(plaintext.getBytes(), key));
    }

    /**
     * 字符串形式的密文解密成明文
     *
     * @param enHex 密文
     * @param key   秘钥
     * @return 解密后的明文
     * @Author tanp
     */
    private static String decodeSms4HexToString(String enHex, byte[] key) {
        byte[] plaintext = decodeSms4(hexStringToBytes(enHex),key);
        return new String(plaintext).trim();
    }


    /**
     * SMS4加密,加密字符数组
     *
     * @param plaintext 字节数组形式的明文
     * @param key       秘钥
     * @return 明文加密后的字接数组
     */
    private static byte[] encodeSms4(byte[] plaintext, byte[] key) {
        byte[] ciphering = new byte[plaintext.length];
        int k = 0;
        int plainLen = plaintext.length;
        while (k + BLOCK <= plainLen) {
            byte[] cellPlain = new byte[16];
            System.arraycopy(plaintext, k, cellPlain, 0, 16);
            byte[] cellCipher = encode16(cellPlain, key);
            System.arraycopy(cellCipher, 0, ciphering, k, cellCipher.length);
            k += 16;
        }
        return ciphering;
    }

    /**
     * 不限明文长度的SMS4解密
     *
     * @param ciphering 需要解密的字节数组
     * @param key 秘钥
     * @return 解密后的字节数组
     */
    private static byte[] decodeSms4(byte[] ciphering, byte[] key) {
        byte[] plaintext = new byte[ciphering.length];
        int k = 0;
        int cipherLen = ciphering.length;
        while (k + BLOCK <= cipherLen) {
            byte[] cellCipher = new byte[16];
            System.arraycopy(ciphering, k, cellCipher, 0, 16);
            byte[] cellPlain = decode16(cellCipher, key);
            System.arraycopy(cellPlain, 0, plaintext, k, cellPlain.length);
            k += BLOCK;
        }

        return plaintext;
    }



    /**
     * 只加密16位明文
     *
     * @param plaintext 明文字节数组
     * @param key       秘钥
     * @return 加密后的字节数组
     */
    private static byte[] encode16(byte[] plaintext, byte[] key) {
        byte[] cipher = new byte[16];
        Sm4Util sm4 = new Sm4Util();
        //调用加密方法
        return sm4.sms4(plaintext, 16, key, cipher, ENCRYPT);
    }

    /**
     * 只解密16位密文
     *
     * @param ciphering 需解密的密文
     * @param key 秘钥
     * @return 解密后的明文字节
     */
    private static byte[] decode16(byte[] ciphering, byte[] key) {
        byte[] plain = new byte[16];
        Sm4Util sm4 = new Sm4Util();
        sm4.sms4(ciphering, 16, key, plain, DECRYPT);
        return plain;
    }

    /**
     * 只加密32位明文
     *
     * @param plaintext 明文字节数组
     * @param key       秘钥
     * @return 加密后的字节数组
     */
    private static byte[] encode32(byte[] plaintext, byte[] key) {
        byte[] cipher = new byte[32];
        Sm4Util sm4 = new Sm4Util();
        return sm4.sms4(plaintext, 32, key, cipher, ENCRYPT);
    }

    /**
     * 只解密32位密文
     *
     * @param ciphering 需解密的密文
     * @param key 秘钥
     * @return 解密后的明文字节
     */
    private static byte[] decode32(byte[] ciphering, byte[] key) {
        byte[] plain = new byte[32];
        Sm4Util sm4 = new Sm4Util();
        sm4.sms4(ciphering, 32, key, plain, DECRYPT);
        return plain;
    }

    /**
     * 字节数组转字符串
     *
     * @param src 字节数组
     * @return String
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (byte aSrc : src) {
            int v = aSrc & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 字符串转字节数组
     *
     * @param hexString the hex string
     * @return byte[]
     */
    private static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.length() <= 0) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    /**
     * Convert char to byte
     *
     * @param c char
     * @return byte
     */
    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }


    /**
     * @Description 随机获取中文
     * @Date 2020/5/9 14:17
     * @Author tanp
     */
    private static char getRandomChar() {
        String str = "";
        int hightPos;
        int lowPos;
        Random random = new Random();
        hightPos = (176 + Math.abs(random.nextInt(39)));
        lowPos = (161 + Math.abs(random.nextInt(93)));
        byte[] b = new byte[2];
        b[0] = (Integer.valueOf(hightPos)).byteValue();
        b[1] = (Integer.valueOf(lowPos)).byteValue();
        try {
            str = new String(b, "GBK");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            System.out.println("错误");
        }
        return str.charAt(0);
    }

    public static void main(String[] args) {
        final byte[] key = {0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab,
                (byte) 0xcd, (byte) 0xef, (byte) 0xfe, (byte) 0xdc,
                (byte) 0xba, (byte) 0x98, 0x76, 0x54, 0x32, 0x10};
        StringBuilder msg = new StringBuilder();
        for(int a=0;a<ROUND;a++){
            for (int i = 1; i < ROUND; i++) {
                msg.append(getRandomChar());
            }
            System.out.println("加密前:" + msg.toString());
            String enStr = encodeSms4ToHex(msg.toString(), key);
            System.out.println("加密后:" + enStr);
            String deStr = decodeSms4HexToString(enStr, key);
            System.out.println("解密后:" + deStr);
            //查看经过加密再解密后的字符串是否与最开始的原生字符串是否一致
            System.out.println(msg.toString().equals(deStr));
        }

    }


}

 

五、参考文献

SM4分组密码算法:https://wenku.baidu.com/view/e66938055acfa1c7aa00cca7.html?from=search

SM4分组密码算法综述:https://wenku.baidu.com/view/5c900609001ca300a6c30c22590102020640f252.html?fr=search

SM4算法及实现方式:http://www.mamicode.com/info-detail-2603734.html

SM4加密解密:https://blog.csdn.net/Mr_ye931/article/details/105680359

六、总结

本篇博客为查看参考文献中的相关文档学习总结所得,有错误的地方大家多多指教

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/185344.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • IntelliJ IDEA 2021.5 激活码【在线注册码/序列号/破解码】[通俗易懂]

    IntelliJ IDEA 2021.5 激活码【在线注册码/序列号/破解码】,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月19日
  • [USACO12JAN]视频游戏的连击Video Game Combos「建议收藏」

    很早之前就做过啦补一下题解F(i,j)前i个的字符为j的匹配注意end要累加#include&lt;iostream&gt;#include&lt;cstdio&gt;#include&lt;cstring&gt;#include&lt;cmath&gt;#include&lt;algorithm&gt;#include&lt;queue&gt;usingnam…

    2022年4月10日
  • pytest 执行用例_测试用例执行结果有哪些

    pytest 执行用例_测试用例执行结果有哪些前言平常我们功能测试用例非常多时,比如有1千条用例,假设每个用例执行需要1分钟,如果单个测试人员执行需要1000分钟才能跑完当项目非常紧急时,会需要协调多个测试资源来把任务分成两部分,于是执行时间

    2022年7月30日
  • 什么是光栅化?_光栅成像

    什么是光栅化?_光栅成像光栅化首先,光栅化(Rasterize/rasteriztion)。这个词儿Adobe官方翻译成栅格化或者像素化。没错,就是把矢量图形转化成像素点儿的过程。我们屏幕上显示的画面都是由像素组成,而三维物体都是点线面构成的。要让点线面,变成能在屏幕上显示的像素,就需要Rasterize这个过程。就是从矢量的点线面的描述,变成像素的描述。如下图,这是一个放大了1200%的屏幕,前面是告诉计算机我有一个圆形,后面就是计算机把圆形转换成可以显示的像素点。这个过程就是Rasterize。参考链接如何理解Open

    2022年10月19日
  • Mysql自连接查询「建议收藏」

    Mysql自连接查询「建议收藏」自连接查询假想以下场景:某一电商网站想要对站内产品做层级分类,一个类别下面有若干子类,子类下面也会有别的子类。例如数码产品这个类别下面有笔记本,台式机,智能手机等;笔记本,台式机,智能手机又可以按照品牌分类;品牌又可以按照价格分类,等等。也许这些分类会达到一个很深的层次,呈现一种树状的结构。那么这些数据要怎么在数据库中表示呢?我们可以在数据库中创建两个字段来存储id和类别名称,使用第三个字段存

    2022年6月10日
  • invalid python sdk怎么办_pycharm一直创建虚拟环境

    invalid python sdk怎么办_pycharm一直创建虚拟环境解决pycharm创建虚拟环境时出现的invalidpythonSDK问题

    2022年8月27日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号