android音频资源,android音频编辑之音频裁剪的示例代码

article/2025/5/8 22:18:56

前言

本篇开始讲解音频编辑的具体操作,从相对简单的音频裁剪开始。要进行音频裁剪,我的方案是开启一个Service服务用于音频裁剪的耗时操作,主界面发送裁剪命令,同时注册EventBus接受裁剪的消息(当然也可以使用广播接受的方式)。因此,在本篇主要会讲解以下内容:

音频编辑项目的整体结构

音频裁剪方法的流程实现

获取音频文件相关信息

计算裁剪时间点对应文件中数据的位置

写入wav文件头信息

写入wav文件裁剪部分的音频数据

下面是音频裁剪效果图:

0405c9d3f971ee98750981eb461b7281.png

音频编辑项目的整体结构

该音频测试项目的结构其实很简单,大致就是以Fragment为基础的各个界面,以IntentService为基础的后台服务,以及最重要的音频编辑工具类实现。大致结构如下:

CutFragment,裁剪页面。选择音频,裁剪音频,播放裁剪后的音频,同时注册了EventBus以便接受后台音频编辑操作发送的消息进行更新。

AudioTaskService,音频编辑服务Service。继承自IntentService,可以在后台任务的线程中执行耗时音频编辑操作。

AudioTaskCreator,音频编辑任务命令发送器。通过它可以启动音频编辑服务AudioTaskService,并发送具体的编辑操作给它。

AudioTaskHandler,音频编辑任务处理器。AudioTaskService接受到的intent任务都交给它去处理。这里具体处理裁剪,合成等操作。

AudioEditUtil, 音频编辑工具类。提供裁剪,合成等音频编辑的方法。

另外还有其他相关的音频工具类。

现在我们看看它们之间的主要流程实现:

CutFragment发起音频裁剪任务,同时接收更新音频编辑消息

public class CutFragment extends Fragment {

...

/**

* 裁剪音频

*/

private void cutAudio() {

String path1 = tvAudioPath1.getText().toString();

if(TextUtils.isEmpty(path1)){

ToastUtil.showToast("音频路径为空");

return;

}

float startTime = Float.valueOf(etStartTime.getText().toString());

float endTime = Float.valueOf(etEndTime.getText().toString());

if(startTime <= 0){

ToastUtil.showToast("时间不对");

return;

}

if(endTime <= 0){

ToastUtil.showToast("时间不对");

return;

}

if(startTime >= endTime){

ToastUtil.showToast("时间不对");

return;

}

//调用AudioTaskCreator发起音频裁剪任务

AudioTaskCreator.createCutAudioTask(getContext(), path1, startTime, endTime);

}

/**

* 接收并更新裁剪消息

*/

@Subscribe(threadMode = ThreadMode.MAIN) public void onReceiveAudioMsg(AudioMsg msg) {

if(msg != null && !TextUtils.isEmpty(msg.msg)){

tvMsgInfo.setText(msg.msg);

mCurPath = msg.path;

}

}

}

AudioTaskCreator启动音频裁剪任务AudioTaskService

public class AudioTaskCreator {

...

/**

* 启动音频裁剪任务

* @param context

* @param path

*/

public static void createCutAudioTask(Context context, String path, float startTime, float endTime){

Intent intent = new Intent(context, AudioTaskService.class);

intent.setAction(ACTION_AUDIO_CUT);

intent.putExtra(PATH_1, path);

intent.putExtra(START_TIME, startTime);

intent.putExtra(END_TIME, endTime);

context.startService(intent);

}

}

AudioTaskService服务将接受的Intent任务交给AudioTaskHandler处理

/**

* 执行后台任务的服务

*/

public class AudioTaskService extends IntentService {

private AudioTaskHandler mTaskHandler;

public AudioTaskService() {

super("AudioTaskService");

}

@Override public void onCreate() {

super.onCreate();

mTaskHandler = new AudioTaskHandler();

}

/**

* 实现异步任务的方法

*

* @param intent Activity传递过来的Intent,数据封装在intent中

*/

@Override protected void onHandleIntent(Intent intent) {

if (mTaskHandler != null) {

mTaskHandler.handleIntent(intent);

}

}

}

AudioTaskService服务将接受的Intent任务交给AudioTaskHandler处理,根据不同的Intent action,调用不同的处理方法

/**

*

*/

public class AudioTaskHandler {

public void handleIntent(Intent intent){

if(intent == null){

return;

}

String action = intent.getAction();

switch (action){

case AudioTaskCreator.ACTION_AUDIO_CUT:

{

//裁剪

String path = intent.getStringExtra(AudioTaskCreator.PATH_1);

float startTime = intent.getFloatExtra(AudioTaskCreator.START_TIME, 0);

float endTime = intent.getFloatExtra(AudioTaskCreator.END_TIME, 0);

cutAudio(path, startTime, endTime);

}

break;

//其他编辑任务

...

default:

break;

}

}

/**

* 裁剪音频

* @param srcPath 源音频路径

* @param startTime 裁剪开始时间

* @param endTime 裁剪结束时间

*/

private void cutAudio(String srcPath, float startTime, float endTime){

//具体裁剪操作

}

}

音频裁剪方法的实现

接下来是音频裁剪的具体操作。还记得上一篇文章说的,音频的裁剪操作都是要基于PCM文件或者WAV文件上进行的,所以对于一般的音频文件都是需要先解码得到PCM文件或者WAV文件,才能进行具体的音频编辑操作。因此音频裁剪操作需要经历以下步骤:

计算解码后的wav音频路径

对源音频进行解码,得到解码后源WAV文件

创建源wav文件和目标WAV音频频的RandomAccessFile,以便对它们后面对它们进行读写操作

根据采样率,声道数,采样位数,和当前时间,计算开始时间和结束时间对应到源文件的具体位置

根据采样率,声道数,采样位数,裁剪音频数据大小等,计算得到wav head文件头byte数据

将wav head文件头byte数据写入到目标文件中

将源文件的开始位置到结束位置的数据复制到目标文件中

删除源wav文件,重命名目标wav文件为源wav文件,即得到最终裁剪后的wav文件

如下,对源音频进行解码,得到解码后的音频文件,然后根据解码音频文件得到Audio音频相关信息,里面记录音频相关的信息如采样率,声道数,采样位数等。

/**

*

*/

public class AudioTaskHandler {

/**

* 裁剪音频

* @param srcPath 源音频路径

* @param startTime 裁剪开始时间

* @param endTime 裁剪结束时间

*/

private void cutAudio(String srcPath, float startTime, float endTime){

String fileName = new File(srcPath).getName();

String nameNoSuffix = fileName.substring(0, fileName.lastIndexOf('.'));

fileName = nameNoSuffix + Constant.SUFFIX_WAV;

String outName = nameNoSuffix + "_cut.wav";

//裁剪后音频的路径

String destPath = FileUtils.getAudioEditStorageDirectory() + File.separator + outName;

//解码源音频,得到解码后的文件

decodeAudio(srcPath, destPath);

if(!FileUtils.checkFileExist(destPath)){

ToastUtil.showToast("解码失败" + destPath);

return;

}

//获取根据解码后的文件得到audio数据

Audio audio = getAudioFromPath(destPath);

//裁剪操作

if(audio != null){

AudioEditUtil.cutAudio(audio, startTime, endTime);

}

//裁剪完成,通知消息

String msg = "裁剪完成";

EventBus.getDefault().post(new AudioMsg(AudioTaskCreator.ACTION_AUDIO_CUT, destPath, msg));

}

/**

* 获取根据解码后的文件得到audio数据

* @param path

* @return

*/

private Audio getAudioFromPath(String path){

if(!FileUtils.checkFileExist(path)){

return null;

}

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {

try {

Audio audio = Audio.createAudioFromFile(new File(path));

return audio;

} catch (Exception e) {

e.printStackTrace();

}

}

return null;

}

}

获取音频文件相关信息

而获取Audio信息其实就是解码时获取MediaFormat,然后获取音频相关的信息的。

/**

* 音频信息

*/

public class Audio {

private String path;

private String name;

private float volume = 1f;

private int channel = 2;

private int sampleRate = 44100;

private int bitNum = 16;

private int timeMillis;

...

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) public static Audio createAudioFromFile(File inputFile) throws Exception {

MediaExtractor extractor = new MediaExtractor();

MediaFormat format = null;

int i;

try {

extractor.setDataSource(inputFile.getPath());

}catch (Exception ex){

ex.printStackTrace();

extractor.setDataSource(new FileInputStream(inputFile).getFD());

}

int numTracks = extractor.getTrackCount();

for (i = 0; i < numTracks; i++) {

format = extractor.getTrackFormat(i);

if (format.getString(MediaFormat.KEY_MIME).startsWith("audio/")) {

extractor.selectTrack(i);

break;

}

}

if (i == numTracks) {

throw new Exception("No audio track found in " + inputFile);

}

Audio audio = new Audio();

audio.name = inputFile.getName();

audio.path = inputFile.getAbsolutePath();

audio.sampleRate = format.containsKey(MediaFormat.KEY_SAMPLE_RATE) ? format.getInteger(MediaFormat.KEY_SAMPLE_RATE) : 44100;

audio.channel = format.containsKey(MediaFormat.KEY_CHANNEL_COUNT) ? format.getInteger(MediaFormat.KEY_CHANNEL_COUNT) : 1;

audio.timeMillis = (int) ((format.getLong(MediaFormat.KEY_DURATION) / 1000.f));

//根据pcmEncoding编码格式,得到采样精度,MediaFormat.KEY_PCM_ENCODING这个值不一定有

int pcmEncoding = format.containsKey(MediaFormat.KEY_PCM_ENCODING) ? format.getInteger(MediaFormat.KEY_PCM_ENCODING) : AudioFormat.ENCODING_PCM_16BIT;

switch (pcmEncoding){

case AudioFormat.ENCODING_PCM_FLOAT:

audio.bitNum = 32;

break;

case AudioFormat.ENCODING_PCM_8BIT:

audio.bitNum = 8;

break;

case AudioFormat.ENCODING_PCM_16BIT:

default:

audio.bitNum = 16;

break;

}

extractor.release();

return audio;

}

}

这里要注意,通过MediaFormat获取音频信息的时候,获取采样位数是要先查找MediaFormat.KEY_PCM_ENCODING这个key对应的值,如果是AudioFormat.ENCODING_PCM_8BIT,则是8位采样精度,如果是AudioFormat.ENCODING_PCM_16BIT,则是16位采样精度,如果是AudioFormat.ENCODING_PCM_FLOAT(android 5.0 版本新增的类型),则是32位采样精度。当然可能MediaFormat中没有包含MediaFormat.KEY_PCM_ENCODING这个key信息,这时就使用默认的AudioFormat.ENCODING_PCM_16BIT,即默认的16位采样精度(也可以说2个字节作为一个采样点编码)。

接下来就是真正的裁剪操作了。根据audio中的音频信息得到将要写入的wav文件头信息字节数据,创建随机读写文件,写入文件头数据,然后源随机读写文件移动到指定的开始时间开始读取,目标随机读写文件将读取的数据写入,知道源随机文件读到指定的结束时间停止,这样就完成了音频文件的裁剪操作。

public class AudioEditUtil {

/**

* 裁剪音频

* @param audio 音频信息

* @param cutStartTime 裁剪开始时间

* @param cutEndTime 裁剪结束时间

*/

public static void cutAudio(Audio audio, float cutStartTime, float cutEndTime){

if(cutStartTime == 0 && cutEndTime == audio.getTimeMillis() / 1000f){

return;

}

if(cutStartTime >= cutEndTime){

return;

}

String srcWavePath = audio.getPath();

int sampleRate = audio.getSampleRate();

int channels = audio.getChannel();

int bitNum = audio.getBitNum();

RandomAccessFile srcFis = null;

RandomAccessFile newFos = null;

String tempOutPath = srcWavePath + ".temp";

try {

//创建输入流

srcFis = new RandomAccessFile(srcWavePath, "rw");

newFos = new RandomAccessFile(tempOutPath, "rw");

//源文件开始读取位置,结束读取文件,读取数据的大小

final int cutStartPos = getPositionFromWave(cutStartTime, sampleRate, channels, bitNum);

final int cutEndPos = getPositionFromWave(cutEndTime, sampleRate, channels, bitNum);

final int contentSize = cutEndPos - cutStartPos;

//复制wav head 字节数据

byte[] headerData = AudioEncodeUtil.getWaveHeader(contentSize, sampleRate, channels, bitNum);

copyHeadData(headerData, newFos);

//移动到文件开始读取处

srcFis.seek(WAVE_HEAD_SIZE + cutStartPos);

//复制裁剪的音频数据

copyData(srcFis, newFos, contentSize);

} catch (Exception e) {

e.printStackTrace();

return;

}finally {

//关闭输入流

if(srcFis != null){

try {

srcFis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(newFos != null){

try {

newFos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

// 删除源文件,

new File(srcWavePath).delete();

//重命名为源文件

FileUtils.renameFile(new File(tempOutPath), audio.getPath());

}

}

计算裁剪时间点对应文件中数据的位置

需要注意的是根据时间计算在文件中的位置,它是这么实现的:

/**

* 获取wave文件某个时间对应的数据位置

* @param time 时间

* @param sampleRate 采样率

* @param channels 声道数

* @param bitNum 采样位数

* @return

*/

private static int getPositionFromWave(float time, int sampleRate, int channels, int bitNum) {

int byteNum = bitNum / 8;

int position = (int) (time * sampleRate * channels * byteNum);

//这里要特别注意,要取整(byteNum * channels)的倍数

position = position / (byteNum * channels) * (byteNum * channels);

return position;

}

这里要特别注意,因为time是个float的数,所以计算后的position取整它并不一定是(byteNum * channels)的倍数,而position的位置必须要是(byteNum * channels)的倍数,否则后面的音频数据就全部乱了,那么在播放时就是撒撒撒撒的噪音,而不是原来的声音了。原因是音频数据是按照一个个采样点来计算的,一个采样点的大小就是(byteNum * channels),所以要取(byteNum * channels)的整数倍。

写入wav文件头信息

接着看看往新文件写入wav文件头是怎么实现的,这个在上一篇中也是有讲过的,不过还是列出来吧:

/**

* 获取Wav header 字节数据

* @param totalAudioLen 整个音频PCM数据大小

* @param sampleRate 采样率

* @param channels 声道数

* @param bitNum 采样位数

* @throws IOException

*/

public static byte[] getWaveHeader(long totalAudioLen, int sampleRate, int channels, int bitNum) throws IOException {

//总大小,由于不包括RIFF和WAV,所以是44 - 8 = 36,在加上PCM文件大小

long totalDataLen = totalAudioLen + 36;

//采样字节byte率

long byteRate = sampleRate * channels * bitNum / 8;

byte[] header = new byte[44];

header[0] = 'R'; // RIFF

header[1] = 'I';

header[2] = 'F';

header[3] = 'F';

header[4] = (byte) (totalDataLen & 0xff);//数据大小

header[5] = (byte) ((totalDataLen >> 8) & 0xff);

header[6] = (byte) ((totalDataLen >> 16) & 0xff);

header[7] = (byte) ((totalDataLen >> 24) & 0xff);

header[8] = 'W';//WAVE

header[9] = 'A';

header[10] = 'V';

header[11] = 'E';

//FMT Chunk

header[12] = 'f'; // 'fmt '

header[13] = 'm';

header[14] = 't';

header[15] = ' ';//过渡字节

//数据大小

header[16] = 16; // 4 bytes: size of 'fmt ' chunk

header[17] = 0;

header[18] = 0;

header[19] = 0;

//编码方式 10H为PCM编码格式

header[20] = 1; // format = 1

header[21] = 0;

//通道数

header[22] = (byte) channels;

header[23] = 0;

//采样率,每个通道的播放速度

header[24] = (byte) (sampleRate & 0xff);

header[25] = (byte) ((sampleRate >> 8) & 0xff);

header[26] = (byte) ((sampleRate >> 16) & 0xff);

header[27] = (byte) ((sampleRate >> 24) & 0xff);

//音频数据传送速率,采样率*通道数*采样深度/8

header[28] = (byte) (byteRate & 0xff);

header[29] = (byte) ((byteRate >> 8) & 0xff);

header[30] = (byte) ((byteRate >> 16) & 0xff);

header[31] = (byte) ((byteRate >> 24) & 0xff);

// 确定系统一次要处理多少个这样字节的数据,确定缓冲区,通道数*采样位数

header[32] = (byte) (channels * 16 / 8);

header[33] = 0;

//每个样本的数据位数

header[34] = 16;

header[35] = 0;

//Data chunk

header[36] = 'd';//data

header[37] = 'a';

header[38] = 't';

header[39] = 'a';

header[40] = (byte) (totalAudioLen & 0xff);

header[41] = (byte) ((totalAudioLen >> 8) & 0xff);

header[42] = (byte) ((totalAudioLen >> 16) & 0xff);

header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

return header;

}

这里比上一篇中精简了一些,只要传入音频数据大小,采样率,声道数,采样位数这四个参数,就可以得到wav文件头信息了,然后再将它写入到wav文件开始处。

/**

* 复制wav header 数据

*

* @param headerData wav header 数据

* @param fos 目标输出流

*/

private static void copyHeadData(byte[] headerData, RandomAccessFile fos) {

try {

fos.seek(0);

fos.write(headerData);

} catch (Exception ex) {

ex.printStackTrace();

}

}

写入wav文件裁剪部分的音频数据

接下来就是将裁剪部分的音频数据写入到文件中了。这里要先移动源文件的读取位置到裁剪起始处,即

//移动到文件开始读取处

srcFis.seek(WAVE_HEAD_SIZE + cutStartPos);

这样就可以从源文件读取裁剪处的数据了

/**

* 复制数据

*

* @param fis 源输入流

* @param fos 目标输出流

* @param cooySize 复制大小

*/

private static void copyData(RandomAccessFile fis, RandomAccessFile fos, final int cooySize) {

byte[] buffer = new byte[2048];

int length;

int totalReadLength = 0;

try {

while ((length = fis.read(buffer)) != -1) {

fos.write(buffer, 0, length);

totalReadLength += length;

int remainSize = cooySize - totalReadLength;

if (remainSize <= 0) {

//读取指定位置完成

break;

} else if (remainSize < buffer.length) {

//离指定位置的大小小于buffer的大小,换remainSize的buffer

buffer = new byte[remainSize];

}

}

} catch (Exception ex) {

ex.printStackTrace();

}

}

上面代码目的就是读取startPos开始,到startPos+copySize之间的数据。

总结

到这里的话,想必对裁剪的整体流程有一定的了解了,总结起来的话,首先是对音频解码,得到解码后的wav文件或者pcm文件,然后取得音频的文件头信息(包括采样率,声道数,采样位数,时间等),然后计算得到裁剪时间对应到文件中数据位置,以及裁剪的数据大小,然后计算得到裁剪后的wav文件头信息,并写入新文件中,最后将源文件裁剪部分的数据写入到新文件中,最终得到裁剪后的wav文件了。

读者可能会有疑问,我想要裁剪的是mp3文件,这里只是得到裁剪后的wav文件,那怎么得到裁剪后的mp3文件呢?这个就需要对该wav文件进行mp3编码压缩了,具体实现可以参考我的Github项目 AudioEdit

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。


http://chatgpt.dhexx.cn/article/F8csa0fB.shtml

相关文章

android裁剪控件,Android 仿抖音音频裁剪控件

效果图 QQ图片20201126164657.jpg 功能要求:绘制音频效果,音乐播放后进度滚动,控件可拖动,拖动后获取新的起始时间 (后期会加入根据音乐各个时段分贝大小来动态显示音律线的长短) 控件功能实现具体代码: package com.cj.customwidget.widget import android.content.Conte…

如何剪切音乐的一部分?来试试这个方法

音频剪切和合并是音频编辑中常见的操作&#xff0c;它可以用来去除不必要的部分或者将多个音频片段组合成一个完整的作品。在今天的数字化时代&#xff0c;有许多软件和工具可以帮助我们完成这个任务。 那你们知道具体的音频剪切合并的方法是什么吗&#xff1f;如果还不太清楚…

如何裁剪音频文件?裁剪音频的方法有什么?

通常我们在剪辑视频时&#xff0c;为了让视频更加有感染力&#xff0c;我们会加上各种各样的音频丰富视频的内容&#xff0c;而且在选取音频时&#xff0c;一般都是会采用它的高潮部分。那么如何裁剪音频文件来达到想要的效果呢&#xff1f;裁剪音频的方法又有什么&#xff1f;…

常用停用词表整理(哈工大停用词表,百度停用词表等)

辣鸡CSDN https://github.com/goto456/stopwords https://zhuanlan.zhihu.com/p/30002654 转载于:https://www.cnblogs.com/0n-the-way/p/10544285.html

文本分析--停用词集合(结合哈工大停用词表、四川大学机器智能实验室停用词库、百度停用词表等)

文本分析过程中&#xff0c;中文文本分析是一个非常重要的环节&#xff0c;而停用词表的选择也是非常关键的&#xff0c;网络流行了多种版本的停用词表&#xff0c;都具有各自的特点&#xff0c;现在对网络流行的多种停用词表继续去重处理&#xff0c;综合实现新的停用词表。 …

【python】构建停用词表(文末附链接)

构建停用词表 构建停用词表是数据预处理的必要步骤&#xff0c;可以减小不必要的开销。 哈工大、百度、川大等停用词表见GitHub链接&#xff1a;https://github.com/goto456/stopwords 经实验和观察证明&#xff0c;’cn_stopwords.txt‘文件的停用词大多是否定词&#xff1…

stopwords.txt中英文数据集,四川大学机器智能实验室停用词库,哈工大停用词表,中文停用词表,百度停用词表百度网盘下载

今天找stopwords.txt数据集找了好长时间&#xff0c;真是气死了&#xff0c;好多都是需要金币&#xff0c;这数据集不是应该共享的么。故搜集了一些数据集&#xff0c;主要包括四川大学机器智能实验室停用词库,哈工大停用词表,中文停用词表,百度停用词表和一些其他的stopword.t…

python停用词表整理_python停用词表

广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! stop_words:设置停用词表,这样的词我们就不会统计出来(多半是虚拟词,冠词等等),需要列表结构,所以代码中定义了一个函数来处理停用词表...前言前文给大家…

python文本分析--停用词表的使用

之前听说停用词表&#xff0c;没有上手使用过&#xff0c;真正操作的时候发现有很多东西没有学透彻。这里总结一下&#xff0c;去停用词的思想&#xff1a;在原始文本集中去掉不需要的词汇&#xff0c;字符。虽然有通用的停用词表&#xff0c;但是如果想提高后续的分词效果&…

uniapp使用阿里图标

效果图&#xff1a; 前言 随着uniApp的深入人心&#xff0c;我司也陆续做了几个使用uniapp做的移动端跨平台软件&#xff0c;在学习使用的过程中深切的感受到了其功能强大和便捷&#xff0c;今日就如何在uniapp项目中使用阿里字体图标的问题为大家献上我的一点心得&#xff0…

iconfont—阿里图标的使用

阿里图标库为我们提供了许多丰富精美的图标&#xff0c; 可以通过代码引入的方式将图标库引入到我们的项目中&#xff0c;用来美化我们的界面。iconfont 的使用方式有以下几种&#xff1a; 方式一&#xff1a;font-class 在线引入 打开网址进入首页&#xff0c;输入我们想要的…

java前端中的icon_阿里巴巴矢量图标库Iconfont的使用方法

前言 现在网络上有很多矢量图标库&#xff0c;但是能自定义的却很少&#xff0c;不能自定义的体积就很大&#xff0c;造成不必要的浪费。阿里巴巴矢量图标库Iconfont很好的规避了这个问题&#xff0c;能够自定义添加图标到你定义的项目中&#xff0c;运用也很简单。 选择图标 打…

MUI项目中使用阿里巴巴矢量图标库(保姆篇)

话不多说,直接进入主题. 一、要在MUI项目中使用阿里图标库&#xff0c; 就得先进入阿里图标库的官网 这里是官网网址: https://www.iconfont.cn/ 下图是首页的样子 二、使用阿里图标的方法有很多种,&#xff0c;这里就说一下我使用的这种 1.在搜索框中输入关键字&#xff0c;…

微信小程序如何使用阿里妈妈iconfont图标库

1、首先进入iconfont首页&#xff0c;没有账号的先注册账号 http://www.iconfont.cn/ 2、选择需要的图标&#xff0c;加入到你的小车中 3、在这里新建一个项目将图标加进去&#xff0c;这个时候就可以查看并且下载下来了 4、点击download code将图标代码下载下来&#xff0c;…

基于Java的阿里妈妈数据抓取技术

基于Java的阿里妈妈数据抓取技术 前言&#xff1a; 对于需要登录的网站爬虫最大的困难就是需要登录&#xff0c;然后才能获取到数据&#xff0c;如微博&#xff0c;阿里妈妈&#xff0c;webqq等。之前也有看过使用浏览器登录到网站后直接从浏览器中获取cookie的文章&#xff0…

uni-app中引入iconfont阿里巴巴矢量图标库

一&#xff1a;首先看一下图标 二&#xff1a;将icon.css文件放到项目中。 在static下面新建icon.css文件&#xff08;一般是建在common文件下面&#xff0c;建在其他位置上也可以&#xff09;&#xff0c;将iconfont里面的内容复制到icon.css。 这里要对icon.css内容做一些改变…

引入阿里iconfont图标方法以及注意事项

背景 在我们做日常项目时&#xff0c;通常会用到icon图标或者是一些图标字体&#xff0c;阿里iconfont是我们选择的较多的一种&#xff0c;下面我将会介绍使用方法和几种常用的引用方式 iconfont新建项目 官网&#xff1a;https://www.iconfont.cn/ 在首页选择【图标管理】-…

如何在代码里添加并使用阿里巴巴矢量图标-iconfont,在此常用有三种引入方法

iconfont-阿里巴巴矢量图库 在登录好账号的前提下进行以下操作&#xff1a; 添加icon&#xff1a; 首先搜索你想要的icon名&#xff0c;比如&#xff1a;首页选好你想要的图——加入购物车——添加至项目&#xff08;没有项目的话可以新建项目&#xff0c;如果需要很多icon&a…

阿里巴巴icon图标尽在掌握(前端如何引入icon库,美丽图标随你处置T.T)

前端如何引入icon库 挑选图标1.进入阿里矢量图标库[iconfont图标库地址](https://www.iconfont.cn/)2.寻找自己需要的图标加入购物车3.进入购物车&#xff0c;下载代码 引用图标我们先来看看下载的需要加入的css代码直接调用封装好的调用效果展示 挑选图标 1.进入阿里矢量图标…

项目中引入阿里巴巴图标——iconfont图标的使用-svg格式

项目中引入阿里巴巴图标——iconfont图标的使用-svg格式 一、下载图标 1、先进入iconfont.cn页面 iconfont官网&#xff1a;https://www.iconfont.cn/ 2、登陆&#xff0c;并选择你要用的图标进行下载 3、点击下载&#xff0c;并选择弹框下面的色值和大小&#xff0c;点击sv…