一篇文章實現Android圖片拼接并保存至相冊

系列文章目錄

一篇文章實現Android圖片拼接并保存至相冊


在這里插入圖片描述

文章目錄

  • 系列文章目錄
  • 前言
  • 實現功能
  • 類定義和成員變量
    • onCreate方法
    • 權限檢查和圖片選擇
    • 處理選擇的圖片
    • 圖片拼接功能
    • 圖片保存功能
  • 使用ImageStitcher類拼接圖片
  • 代碼解釋:ImageStitcher.java
    • 類定義和方法
    • 計算拼接后圖片的尺寸
    • 計算邏輯
    • 創建并繪制拼接后的圖片
    • 繪制過程
    • 注意事項
  • 效果圖
  • 源碼
    • MainActivity.java
    • ImageStitcher.java
    • AndroidManifest權限申明
    • activity_main.xml
  • 總結


前言

好久沒有寫Android系列的文章了,最近有小伙伴問到了Android圖片拼接的問題,寫一篇相關的博客。

在Android應用中實現圖片拼接功能并保存到相冊是一個常見的需求,比如制作全景圖、拼圖應用或照片編輯工具。本文將介紹如何實現一個完整的圖片拼接應用,包括圖片選擇、拼接和保存功能。


實現功能

  1. 檢查并請求必要的存儲權限
  2. 允許用戶從相冊選擇一張或多張圖片
  3. 異步加載選中的圖片
  4. 使用ImageStitcher類拼接圖片
  5. 將拼接后的圖片保存到相冊
  6. 在整個過程中顯示適當的進度指示和操作反饋

類定義和成員變量

其中包括圖片選擇請求碼,讀取權限請求碼, 寫入權限請求碼,保存目錄名稱,以及相關控件。

public class MainActivity extends AppCompatActivity {private static final int PICK_IMAGE_REQUEST = 1;  // 圖片選擇請求碼private static final int REQUEST_PERMISSION = 2;  // 讀取權限請求碼private static final int REQUEST_WRITE_PERMISSION = 3;  // 寫入權限請求碼private static final String SAVE_DIRECTORY = "ImageStitcher";  // 保存目錄名稱private List<Bitmap> selectedImages = new ArrayList<>();  // 存儲選擇的圖片private ImageView resultView;  // 顯示拼接結果的ImageViewprivate ProgressBar progressBar;  // 進度條private Button selectBtn, stitchBtn, saveBtn;  // 按鈕控件

onCreate方法

初始化控件以及設置監聽

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);  // 設置布局文件// 初始化視圖控件resultView = findViewById(R.id.jm_result_image);progressBar = findViewById(R.id.jm_progress_bar);selectBtn = findViewById(R.id.jm_select_btn);stitchBtn = findViewById(R.id.jm_stitch_btn);saveBtn = findViewById(R.id.jm_save_btn);saveBtn.setVisibility(View.GONE);  // 初始時隱藏保存按鈕// 設置按鈕點擊監聽器selectBtn.setOnClickListener(v -> checkPermissionAndOpenChooser());stitchBtn.setOnClickListener(v -> stitchImagesAsync());
}

權限檢查和圖片選擇

不動態申請權限小心報錯:has no access to content
需在AndroidManifest.xml聲明READ_EXTERNAL_STORAGE權限,Android Q及以上版本必須使用MediaStore API訪問公共目錄文件。

private void checkPermissionAndOpenChooser() {// 檢查是否有讀取外部存儲權限if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED) {openImageChooser();  // 有權限則直接打開圖片選擇器} else {// 沒有權限則請求權限ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},REQUEST_PERMISSION);}
}private void openImageChooser() {// 創建選擇圖片的IntentIntent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType("image/*");  // 設置類型為圖片intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);  // 允許多選startActivityForResult(Intent.createChooser(intent, "選擇圖片"), PICK_IMAGE_REQUEST);
}// 權限請求結果回調
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == REQUEST_PERMISSION && grantResults.length > 0&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {openImageChooser();  // 權限被授予后打開圖片選擇器}
}

處理選擇的圖片

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {handleSelectedImages(data);  // 處理選擇的圖片}
}private void handleSelectedImages(Intent data) {progressBar.setVisibility(View.VISIBLE);  // 顯示進度條ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(() -> {try {if (data.getClipData() != null) {processMultipleImages(data.getClipData());  // 處理多張圖片} else if (data.getData() != null) {processSingleImage(data.getData());  // 處理單張圖片}} finally {runOnUiThread(() -> progressBar.setVisibility(View.GONE));  // 隱藏進度條}});
}private void processMultipleImages(ClipData clipData) {for (int i = 0; i < clipData.getItemCount(); i++) {loadAndAddImage(clipData.getItemAt(i).getUri());  // 加載并添加每張圖片}
}private void processSingleImage(Uri uri) {loadAndAddImage(uri);  // 加載并添加單張圖片
}private void loadAndAddImage(Uri uri) {try (InputStream is = getContentResolver().openInputStream(uri)) {Bitmap bitmap = BitmapFactory.decodeStream(is);  // 從URI加載圖片runOnUiThread(() -> {selectedImages.add(bitmap);  // 添加到圖片列表Toast.makeText(this, "成功加載圖片", Toast.LENGTH_SHORT).show();});} catch (Exception e) {runOnUiThread(() ->Toast.makeText(this, "加載失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());}
}

圖片拼接功能

private void stitchImagesAsync() {if (selectedImages.isEmpty()) return;  // 如果沒有選擇圖片則返回saveBtn.setVisibility(View.VISIBLE);  // 顯示保存按鈕progressBar.setVisibility(View.VISIBLE);  // 顯示進度條ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(() -> {// 調用ImageStitcher類拼接圖片Bitmap stitched = ImageStitcher.stitchImages(selectedImages.toArray(new Bitmap[0]), 0);runOnUiThread(() -> {resultView.setImageBitmap(stitched);  // 顯示拼接結果progressBar.setVisibility(View.GONE);  // 隱藏進度條saveBtn.setVisibility(View.VISIBLE);  // 確保保存按鈕可見// 設置保存按鈕點擊監聽器saveBtn.setOnClickListener(v -> saveImageToGallery(stitched));});});
}

圖片保存功能

private void saveImageToGallery(Bitmap bitmap) {// 檢查是否有寫入外部存儲權限if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {// 沒有權限則請求權限ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_WRITE_PERMISSION);return;}// 在新線程中執行保存操作new Thread(() -> {String fileName = "stitched_" + System.currentTimeMillis() + ".jpg";ContentValues values = new ContentValues();values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");// 對于Android Q及以上版本if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + SAVE_DIRECTORY);values.put(MediaStore.Images.Media.IS_PENDING, 1);}try {// 插入媒體庫記錄Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);try (OutputStream os = getContentResolver().openOutputStream(uri)) {// 壓縮并寫入圖片數據bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);// 對于Android Q及以上版本,更新IS_PENDING標志if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.Images.Media.IS_PENDING, 0);getContentResolver().update(uri, values, null, null);}// 顯示保存成功提示runOnUiThread(() ->Toast.makeText(this, "圖片已保存至相冊", Toast.LENGTH_SHORT).show());}} catch (Exception e) {// 顯示保存失敗提示runOnUiThread(() ->Toast.makeText(this, "保存失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());}}).start();
}

使用ImageStitcher類拼接圖片

代碼解釋:ImageStitcher.java

這是一個用于拼接多張圖片的工具類,提供了將多張圖片橫向或縱向拼接成一張大圖的功能。下面是對代碼的詳細解釋:

類定義和方法

public class ImageStitcher {public static Bitmap stitchImages(Bitmap[] images, int direction) {// 檢查輸入參數是否有效if (images == null || images.length == 0) return null;

計算拼接后圖片的尺寸

        int width = images[0].getWidth();int height = images[0].getHeight();// 計算拼接后圖片的總尺寸if (direction == 0) { // 橫向拼接for (int i = 1; i < images.length; i++) {width += images[i].getWidth();  // 累加寬度height = Math.max(height, images[i].getHeight());  // 取最大高度}} else { // 縱向拼接for (int i = 1; i < images.length; i++) {height += images[i].getHeight();  // 累加高度width = Math.max(width, images[i].getWidth());  // 取最大寬度}}

計算邏輯

  • 橫向拼接:總寬度為所有圖片寬度之和,高度為所有圖片中的最大高度
  • 縱向拼接:總高度為所有圖片高度之和,寬度為所有圖片中的最大寬度

創建并繪制拼接后的圖片

        // 創建拼接后的BitmapBitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(result);// 繪制圖片int currentPos = 0;for (Bitmap image : images) {if (direction == 0) { // 橫向拼接canvas.drawBitmap(image, currentPos, 0, null);  // 在當前位置繪制圖片currentPos += image.getWidth();  // 更新橫向位置} else { // 縱向拼接canvas.drawBitmap(image, 0, currentPos, null);  // 在當前位置繪制圖片currentPos += image.getHeight();  // 更新縱向位置}}return result;  // 返回拼接后的圖片}
}

繪制過程

  1. 創建一個新的空白Bitmap,大小為之前計算的總尺寸
  2. 使用Canvas在這個Bitmap上繪制所有輸入圖片
  3. 根據拼接方向,依次將每張圖片繪制到正確的位置
  4. 更新當前位置指針(currentPos),以便下一張圖片繪制在正確的位置

注意事項

  • 所有輸入圖片應為非空且尺寸相同(代碼中未做嚴格檢查)
  • 拼接方向通過簡單的int值判斷(0為橫向,非0為縱向)
  • 使用了ARGB_8888配置創建Bitmap,保證圖片質量
  • 這是一個基礎實現,沒有處理圖片尺寸不一致時的縮放或裁剪

效果圖

在這里插入圖片描述

源碼

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import android.Manifest;
import android.content.ClipData;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class MainActivity extends AppCompatActivity {private static final int PICK_IMAGE_REQUEST = 1;private static final int REQUEST_PERMISSION = 2;private List<Bitmap> selectedImages = new ArrayList<>();private ImageView resultView;private ProgressBar progressBar;private static final int REQUEST_WRITE_PERMISSION = 3;private static final String SAVE_DIRECTORY = "JmImgStitcher";private Button selectBtn,stitchBtn,saveBtn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);resultView = findViewById(R.id.jm_result_image);progressBar = findViewById(R.id.jm_progress_bar);selectBtn = findViewById(R.id.jm_select_btn);stitchBtn = findViewById(R.id.jm_stitch_btn);// 初始化保存按鈕saveBtn = findViewById(R.id.jm_save_btn);saveBtn.setVisibility(View.GONE);selectBtn.setOnClickListener(v -> checkPermissionAndOpenChooser());stitchBtn.setOnClickListener(v -> stitchImagesAsync());}private void checkPermissionAndOpenChooser() {if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED) {openImageChooser();} else {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},REQUEST_PERMISSION);}}private void openImageChooser() {Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType("image/*");intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);startActivityForResult(Intent.createChooser(intent, "選擇圖片"), PICK_IMAGE_REQUEST);}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == REQUEST_PERMISSION && grantResults.length > 0&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {openImageChooser();}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {handleSelectedImages(data);}}private void handleSelectedImages(Intent data) {progressBar.setVisibility(View.VISIBLE);ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(() -> {try {if (data.getClipData() != null) {processMultipleImages(data.getClipData());} else if (data.getData() != null) {processSingleImage(data.getData());}} finally {runOnUiThread(() -> progressBar.setVisibility(View.GONE));}});}private void processMultipleImages(ClipData clipData) {for (int i = 0; i < clipData.getItemCount(); i++) {loadAndAddImage(clipData.getItemAt(i).getUri());}}private void processSingleImage(Uri uri) {loadAndAddImage(uri);}private void loadAndAddImage(Uri uri) {try (InputStream is = getContentResolver().openInputStream(uri)) {Bitmap bitmap = BitmapFactory.decodeStream(is);runOnUiThread(() -> {selectedImages.add(bitmap);Toast.makeText(this, "成功加載圖片", Toast.LENGTH_SHORT).show();});} catch (Exception e) {runOnUiThread(() ->Toast.makeText(this, "加載失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());}}// 修改stitchImagesAsync方法private void stitchImagesAsync() {if (selectedImages.isEmpty()) return;saveBtn.setVisibility(View.VISIBLE);progressBar.setVisibility(View.VISIBLE);ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(() -> {Bitmap stitched = ImageStitcher.stitchImages(selectedImages.toArray(new Bitmap[0]), 0);runOnUiThread(() -> {resultView.setImageBitmap(stitched);progressBar.setVisibility(View.GONE);//設置出現saveBtn.setVisibility(View.VISIBLE);saveBtn.setOnClickListener(v -> saveImageToGallery(stitched));});});}private void saveImageToGallery(Bitmap bitmap) {if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_WRITE_PERMISSION);return;}new Thread(() -> {String fileName = "stitched_" + System.currentTimeMillis() + ".jpg";ContentValues values = new ContentValues();values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + SAVE_DIRECTORY);values.put(MediaStore.Images.Media.IS_PENDING, 1);}try {Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);try (OutputStream os = getContentResolver().openOutputStream(uri)) {bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.Images.Media.IS_PENDING, 0);getContentResolver().update(uri, values, null, null);}runOnUiThread(() ->Toast.makeText(this, "圖片已保存至相冊", Toast.LENGTH_SHORT).show());}} catch (Exception e) {runOnUiThread(() ->Toast.makeText(this, "保存失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());}}).start();}}

ImageStitcher.java


import android.graphics.Bitmap;
import android.graphics.Canvas;public class ImageStitcher {public static Bitmap stitchImages(Bitmap[] images, int direction) {if (images == null || images.length == 0) return null;int width = images[0].getWidth();int height = images[0].getHeight();// 計算拼接后圖片的總尺寸if (direction == 0) { // 橫向拼接for (int i = 1; i < images.length; i++) {width += images[i].getWidth();height = Math.max(height, images[i].getHeight());}} else { // 縱向拼接for (int i = 1; i < images.length; i++) {height += images[i].getHeight();width = Math.max(width, images[i].getWidth());}}// 創建拼接后的BitmapBitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(result);// 繪制圖片int currentPos = 0;for (Bitmap image : images) {if (direction == 0) { // 橫向拼接canvas.drawBitmap(image, currentPos, 0, null);currentPos += image.getWidth();} else { // 縱向拼接canvas.drawBitmap(image, 0, currentPos, null);currentPos += image.getHeight();}}return result;}
}

AndroidManifest權限申明

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- Android 10+ 需要添加 --><uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"android:maxSdkVersion="29" />

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ProgressBarandroid:id="@+id/jm_progress_bar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:visibility="gone"/><Buttonandroid:id="@+id/jm_select_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="選擇要拼接的圖片"/><Buttonandroid:id="@+id/jm_stitch_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="開始拼接圖片"/><Buttonandroid:id="@+id/jm_save_btn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="保存圖片"android:visibility="gone"/><ImageViewandroid:id="@+id/jm_result_image"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerInside"/>
</LinearLayout>

總結

此文章可以作為基礎,根據具體需求進行擴展和優化。歡迎留言,如有問題可以聯系計蒙。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/908396.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/908396.shtml
英文地址,請注明出處:http://en.pswp.cn/news/908396.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2025.06.06【Ribo-seq】|riboWaltz:P-site定位與三堿基周期性分析流程

文章目錄 一、前言二、riboWaltz簡介三、安裝與依賴四、分析流程總覽1. 數據準備2. 典型分析流程2.1 讀取注釋和BAM2.2 P-site定位2.3 三堿基周期性與元分析2.4 密碼子使用偏好分析 五、可視化與結果解讀六、常見問題與注意事項七、實戰經驗與建議八、參考資料九、結語 一、前言…

思維鏈的 內部機制和簡單理解

思維鏈的 內部機制和簡單理解 思維鏈是對解決問題的步驟進行規劃,規劃后將作為上下文 在LLM中繼續輸出。因為Transform都是一個一個單詞生成,沒新生成一個單詞都會將新生的作為上下文。 可以這么理解,但更準確的簡化描述是: 思維鏈是讓模型在回答問題時,先“內部生成”或…

Charles 全流程指南:安裝、設置、抓包與注意事項

Charles 是一款功能強大的網絡抓包工具&#xff0c;支持 HTTP/HTTPS 流量監控、請求/響應分析、斷點調試等功能。本文將從安裝到實戰抓包&#xff0c;提供完整流程及關鍵注意事項。 一、安裝 Charles 官網下載&#xff1a;訪問 Charles 官網&#xff0c;選擇對應系統版本&…

全球長序列高分辨率光合有效輻射(PAR)(1984-2018)

時間分辨率&#xff1a;時空間分辨率&#xff1a;1km - 10km共享方式&#xff1a;開放獲取數據大小&#xff1a;188.92 GB數據時間范圍&#xff1a;1984-01-01 — 2018-12-31元數據更新時間&#xff1a;2022-04-29 數據集摘要 本數據集是一個包含接近35年&#xff08;1984-201…

【Zephyr 系列 11】使用 NVS 實現 BLE 參數持久化:掉電不丟配置,開機自動加載

??關鍵詞:Zephyr、NVS、非易失存儲、掉電保持、Flash、AT命令保存、配置管理 ??目標讀者:希望在 BLE 模塊中實現掉電不丟配置、支持產測參數注入與自動加載功能的開發者 ??文章長度:約 5200 字 ?? 為什么要使用 NVS? 在實際產品中,我們經常面臨以下場景: 用戶或…

解鎖Java線程池:性能優化的關鍵

一、引言 在 Java 并發編程的世界里&#xff0c;線程池是一個至關重要的概念。簡單來說&#xff0c;線程池就是一個可以復用線程的 “池子”&#xff0c;它維護著一組線程&#xff0c;這些線程可以被重復使用來執行多個任務&#xff0c;而不是為每個任務都創建一個新的線程。?…

一站式直播工具:助力內容創作者高效開啟直播新時代

近年來&#xff0c;隨著互聯網技術的不斷進步和短視頻、直播行業的爆發式增長&#xff0c;越來越多的企業和個人投入到直播電商、互動娛樂、在線教育等場景。直播運營過程中&#xff0c;涉及到數據統計、彈幕互動、流程自動化、內容同步等諸多環節。如何提升運營效率、減少人工…

數論——同余問題全家桶3 __int128和同余方程組

數論——同余問題全家桶3 __int128和同余方程組 快速讀寫和__int128快速讀寫__int128 中國剩余定理和線性同余方程組中國剩余定理(CRT)中國剩余定理OJ示例模板題曹沖養豬 - 洛谷模板題猜數字 - 洛谷 擴展中國剩余定理擴展中國剩余定理OJ示例模板題擴展中國剩余定理&#xff08;…

Python爬蟲實戰:研究MechanicalSoup庫相關技術

一、MechanicalSoup 庫概述 1.1 庫簡介 MechanicalSoup 是一個 Python 庫,專為自動化交互網站而設計。它結合了 requests 的 HTTP 請求能力和 BeautifulSoup 的 HTML 解析能力,提供了直觀的 API,讓我們可以像人類用戶一樣瀏覽網頁、填寫表單和提交請求。 1.2 主要功能特點…

祝?高考加油

以下是極為詳細的高考注意事項清單&#xff0c;涵蓋考前、考中、考后全流程&#xff0c;建議逐條核對&#xff1a; 一、考前準備 1. 證件與物品 必帶清單&#xff1a; 準考證&#xff1a;打印2份&#xff08;1份備用&#xff09;&#xff0c;塑封或夾在透明文件袋中防皺濕。身…

學習路之PHP--webman安裝及使用、webman/admin安裝

學習路之PHP--webman安裝及使用、webman/admin安裝 一、安裝webman二、運行三、安裝webman/admin四、效果五、配置Nginx反向代理&#xff08;生產環境&#xff1a;可選&#xff09;六、win10運行問題集七、使用 一、安裝webman 準備&#xff1a; PHP > 8.1 Composer > 2…

mamba架構和transformer區別

Mamba 架構和 Transformer 架構存在多方面的區別&#xff0c;具體如下&#xff1a; 計算復雜度1 Transformer&#xff1a;自注意力機制的計算量會隨著上下文長度的增加呈平方級增長&#xff0c;例如上下文增加 32 倍時&#xff0c;計算量可能增長 1000 倍&#xff0c;在處理長序…

Python爬蟲實戰:研究mechanize庫相關技術

1. 引言 隨著互聯網數據量的爆炸式增長,網絡爬蟲已成為數據采集和信息挖掘的重要工具。Python 作為一種功能強大且易于學習的編程語言,擁有豐富的爬蟲相關庫,如 Requests、BeautifulSoup、Scrapy 等。Mechanize 庫作為其中的一員,特別擅長處理復雜的表單提交和會話管理,為…

如何使用索引和條件批量更改Series數據

視頻演示 如何通過索引與布爾條件修改 pandas Series&#xff1f;實操演示來了 一、前言&#xff1a;掌握Series數據修改是數據處理的基礎 在使用Python進行數據分析時&#xff0c;Pandas庫的Series對象是最常用的結構之一。在上一個視頻中我們已經學習了如何創建Series對象&a…

CentOS 7 如何安裝llvm-project-10.0.0?

CentOS 7 如何安裝llvm-project-10.0.0&#xff1f; 需要先升級gcc至7.5版本&#xff0c;詳見CentOS 7如何編譯安裝升級gcc版本?一文 # 備份之前的yum .repo文件至 /tmp/repo_bak 目錄 mkdir -p /tmp/repo_bak && cd /etc/yum.repo.d && /bin/mv ./*.repo …

6個月Python學習計劃 Day 15 - 函數式編程、高階函數、生成器/迭代器

第三周 Day 1 &#x1f3af; 今日目標 掌握 Python 中函數式編程的核心概念熟悉 map()、filter()、reduce() 等高階函數結合 lambda 和 列表/字典 進行數據處理練習了解生成器與迭代器基礎&#xff0c;初步掌握惰性計算概念 &#x1f9e0; 函數式編程基礎 函數式編程是一種…

SpringCloud Gateway 集成 Sentinel 詳解 及實現動態監聽Nacos規則配置實時更新流控規則

目錄 一、前言二、版本選擇和適配 2.1、本文使用各組件版本2.2、官方推薦版本 三、部署sentinel-dashboard 3.1、下載 sentinel-dashboard jar包3.2、啟動 sentinel-dashboard 四、Gateway 集成 Sentinel實現控制臺配置流控規則測試 4.1、添加Gateway 集成 Sentinel 包4.2、添加…

Linux八股【1】-----虛擬內存

參考&#xff1a;小林coding 虛擬內存存在的目的&#xff1f; 為了能夠同時運行多個進程同時進程之間互不干擾 虛擬地址通過MMU找到物理地址 物理內存怎么映射的&#xff1f; 物理內存的映射方法主要有兩種&#xff0c;內存分段和內存分頁 內存分段 把程序的不同區&#…

驚艷呈現:探索數據可視化的藝術與科學

一張圖表真能勝過千言萬語&#xff1f;當超市銷售數據變成跳動的熱力圖&#xff0c;當城市交通擁堵狀況化作流動的光帶&#xff0c;數據可視化正以超乎想象的方式重塑我們認知世界的維度。但你是否想過&#xff0c;那些看似精美直觀的圖表背后&#xff0c;藏著怎樣精密的科學邏…

06-排序

排序 1. 排序的概念及其應用 1.1 排序的概念 排序&#xff1a;所謂排序&#xff0c;就是使一串記錄&#xff0c;按照其中的某個或某些關鍵字的大小&#xff0c;遞增或遞減的排列起來的操作。 穩定性&#xff1a;假定在待排序的記錄序列中&#xff0c;存在多個具有相同的關鍵…