Re: PSA Using Python Pillow to foil camera image PRNU fingerprinting

Maria Sophia <[email protected]> Fri, 31 Jul 2026 15:02:08 -0800
Newsgroups rec.photo.digital,comp.lang.python,alt.comp.os.windows-10
Organization BWH Usenet Archive (https://usenet.blueworldhosting.com)
Message-ID <[email protected]>
Maria Sophia wrote:
> 1. Run adbcopy.bat to copy your images over Wi-Fi to your desktop

For those who don't have the aforementioned adbcopy.bat, here it is.
I wrote it for my filespecs, so you need to change the defaults.

It is designed to copy images to/from desktop/phone using Wi-Fi or USB.
Mostly Wi-Fi (since with USB you can more easily drag and drop using MTP).

The result is you can copy any images to and from any Android on your LAN.


  :: adbcopy.bat
  :: Uses desktop adb to copy image files to:from Android:Windows (Wi-Fi:USB)
  :: -------------------------------------------------------------------------
  :: v3p4 20260727 Added checks for typos when inputting Windows file paths
  :: v3p3 20260727 Added Windows browsing capability if full path is not known
  :: v3p2 20260726 Added choice of known Android destinations for convenience
  :: v3p1 20260725 Added Windows push to Android using a known full path
  ::               Added broadcast registration so images can quickly be found
  :: v3p0 20260708 added dual-layer deletion (filesystem + mediastore)
  ::               which prevents FUSE from repeatedly restoring ghost files
  ::               and which handles private-app sandbox directories
  :: v2p9 20260707 fixed quoting and path issues caused by filenames with spaces
  :: v2p8 20260707 added skipping of empty directories before prompting user
  :: v2p7 20260702 changed to delete only files (not folders)
  :: v2p6 20260701 added auto-detect all DCIM subdirectories
  :: v2p5 20260701 expanded image file matching
  :: v2p4 20260701 added internal DCIM/Camera option
  :: v2p3 20260621 open destination folder when done
  :: v2p2 20260617 added screenshot directory detection
  :: v2p2 20260612 fixed quoting bug in DCIM ls command
  :: v2p1 20260607 added Windows-to-Android APK install mode
  :: v2p0 20260603 added Screenshot directory support
  :: v1p9 20260528 trim trailing spaces from destination path
  :: v1p8 20260528 replaced destructive path truncation with CR stripping
  :: v1p7 20260528 escaped redirection character in backtick loop
  :: v1p6 20260528 updated external SD card path handling
  :: v1p5 20260528 fixed null-redirection error and stabilized extraction
  :: v1p4 20260528 fixed "unexpected at this time" crash
  :: v1p3 20260528 fixed crash on empty variable comparison
  :: v1p2 20260528 fixed multi-device detection and nested quoting
  :: v1p1 20260528 added debug output for failure cases
  :: v1p0 20260528 initial version: copy images by date
  :: -------------------------------------------------------------------------
  
  @echo off
  setlocal enabledelayedexpansion
  
  cd /d "%~dp0"
  set "ADB_EXE=c:\app\editor\android\scrcpy\adb.exe"
  
  :: --- DEVICE DETECTION ---
  for /f "skip=1 tokens=1" %%g in ('"%ADB_EXE%" devices') do (
      if not "%%g"=="" (
          if "!ADB_TARGET!"=="" set "ADB_TARGET=%%g"
      )
  )
  
  if "!ADB_TARGET!"=="" (
      echo [ERROR] No connected ADB devices found.
      pause
      exit /b
  )
  
  echo Targeting device: %ADB_TARGET%
  echo ----------------
  
  :: --- MAIN DIRECTION MENU --- default is [1] ---
  echo Select Direction:
  echo [1] Android to Windows (Pull Images/Screenshots) [Default]
  echo [2] Windows to Android (Copy/Install APK)
  echo.
  set "CHOICE=1"
  set /p "CHOICE=Enter choice [1 or 2]: "
  
  if "%CHOICE%"=="2" goto :windows_to_android
  if "%CHOICE%"=="1" goto :android_to_windows
  goto :android_to_windows
  
  :windows_to_android
  echo.
  echo --- Windows to Android Push Mode ---
  
  :: begin file selection
  echo Select file input mode:
  echo [0] Browse for file (no full path needed)
  echo [1] Enter full path manually
  echo.
  set /p "FILE_MODE=Enter choice [0 or 1]: "
  
  if "%FILE_MODE%"=="0" (
      echo Opening file browser...
      for /f "delims=" %%F in ('powershell -command "Add-Type -AssemblyName System.Windows.Forms; $f=New-Object System.Windows.Forms.OpenFileDialog; $f.Filter='Images|*.jpg;*.jpeg;*.png;*.gif'; if($f.ShowDialog() -eq 'OK'){Write-Output $f.FileName}"') do set "SRC_FILE=%%F"
  ) else (
      :ask_path
      set /p "SRC_FILE=Enter full path of file to push: "
      if "%SRC_FILE%"=="" (
          echo You must enter a full path or choose option 0.
          goto ask_path
      )
  )
  
  if not exist "%SRC_FILE%" (
      echo [ERROR] File not found: %SRC_FILE%
      pause
      exit /b
  )
  
  :: end file selection
  
  :: Extract just the filename (e.g., pizzamyheart.jpg)
  for %%F in ("%SRC_FILE%") do set "SRC_NAME=%%~nxF"
  
  echo.
  echo Select Android destination:
  echo [1] /storage/emulated/0/DCIM/Camera
  echo [2] /storage/emulated/0/DCIM/Screenshots
  echo [3] /storage/emulated/0/Pictures
  echo [4] /storage/emulated/0/Pictures/Screenshots
  echo [5] /storage/emulated/0/Download
  echo [6] /storage/emulated/0/Snapseed
  echo [7] /storage/emulated/0/Samsung
  echo [8] /storage/emulated/0/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp Images
  echo.
  set /p "DEST_CHOICE=Enter choice [1-8]: "
  
  if "%DEST_CHOICE%"=="1" set "DEST_DIR=/storage/emulated/0/DCIM/Camera"
  if "%DEST_CHOICE%"=="2" set "DEST_DIR=/storage/emulated/0/DCIM/Screenshots"
  if "%DEST_CHOICE%"=="3" set "DEST_DIR=/storage/emulated/0/Pictures"
  if "%DEST_CHOICE%"=="4" set "DEST_DIR=/storage/emulated/0/Pictures/Screenshots"
  if "%DEST_CHOICE%"=="5" set "DEST_DIR=/storage/emulated/0/Download"
  if "%DEST_CHOICE%"=="6" set "DEST_DIR=/storage/emulated/0/Snapseed"
  if "%DEST_CHOICE%"=="7" set "DEST_DIR=/storage/emulated/0/Samsung"
  if "%DEST_CHOICE%"=="8" set "DEST_DIR=/storage/emulated/0/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp Images"
  
  echo.
  echo Pushing "%SRC_FILE%" to "%DEST_DIR%"
  "%ADB_EXE%" -s %ADB_TARGET% push "%SRC_FILE%" "%DEST_DIR%"
  
  echo Forcing media scan...
  "%ADB_EXE%" -s %ADB_TARGET% shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://%DEST_DIR%/%SRC_NAME%
  
  echo Done.
  pause
  exit /b
  
  :: ROUTINE: ANDROID TO WINDOWS
  :android_to_windows
  echo.
  echo --- Running Android to Windows Pull ---
  
  echo.
  echo What do you want to pull?
  echo [1] Camera photos (SD Card DCIM/Camera)
  echo [2] Screenshots
  echo [3] Camera photos (Internal Storage DCIM/Camera)
  echo [4] Pull directories one-by-one (user selected)
  set "PULL_CHOICE=1"
  set /p "PULL_CHOICE=Enter choice [1, 2, 3 or 4]: "
  
  :: Only ask for date if pulling dated files
  if "%PULL_CHOICE%"=="4" goto :skip_date
  
  :: --- DATE DETECTION ---
  for /f "tokens=2 delims==" %%i in ('wmic os get localdatetime /value') do set "dt=%%i"
  set "DETECTED_DATE=%dt:~0,8%"
  
  echo Detected Date: %DETECTED_DATE%
  set /p "USER_DATE=Press Enter to confirm, or type a different date (YYYYMMDD): "
  if "%USER_DATE%"=="" (
      set "TARGET_DATE=%DETECTED_DATE%"
  ) else (
      set "TARGET_DATE=%USER_DATE%"
  )
  
  :skip_date
  
  echo.
  if "%PULL_CHOICE%"=="4" (
      rem Interactive, pulling everything ¡V no date-based subfolder
      set "DEST_DIR=H:\003_camera\20260701" 
      
  ) else (
      rem Date-based pulls still go into YYYYMMDD subfolder
      set "DEST_DIR=H:\004_upload\home\pool\assay\%TARGET_DATE%"
  )
  
  set /p "USER_DIR=Enter destination directory [Default: %DEST_DIR%]: "
  if not "%USER_DIR%"=="" set "DEST_DIR=%USER_DIR%"
  
  :: Remove quotes
  set "DEST_DIR=%DEST_DIR:"=%"
  
  :: Trim trailing spaces
  :trim
  if "!DEST_DIR:~-1!"==" " (
      set "DEST_DIR=!DEST_DIR:~0,-1!"
      goto trim
  )
  
  if not exist "%DEST_DIR%" (
      echo Creating directory: %DEST_DIR%
      mkdir "%DEST_DIR%"
  )
  
  if "%PULL_CHOICE%"=="1" goto :pull_camera
  if "%PULL_CHOICE%"=="2" goto :pull_screenshots
  if "%PULL_CHOICE%"=="3" goto :pull_camera_internal
  if "%PULL_CHOICE%"=="4" goto :pull_interactive_dirs
  
  goto :pull_camera
  
  if "%PULL_CHOICE%"=="1" goto :pull_camera
  if "%PULL_CHOICE%"=="2" goto :pull_screenshots
  if "%PULL_CHOICE%"=="3" goto :pull_camera_internal
  if "%PULL_CHOICE%"=="4" goto :pull_interactive_dirs
  
  goto :pull_camera
  
  :: PULL CAMERA (DCIM)
  :pull_camera
  echo.
  echo Pulling CAMERA images matching *%TARGET_DATE%*.jpg ...
  echo Sending files to: "%DEST_DIR%"
  echo ----------------
  
  for /f "usebackq delims=" %%i in (`
      %ADB_EXE% -s !ADB_TARGET! shell ls /storage/0CA4-352D/DCIM/Camera/*%TARGET_DATE%*.jpg
  `) do (
      set "FILE_PATH=%%i"
      for /f "delims=" %%r in ("!FILE_PATH!") do set "FILE_PATH=%%r"
      if not "!FILE_PATH!"=="" (
          echo Pulling: !FILE_PATH!
          "%ADB_EXE%" -s !ADB_TARGET! pull "!FILE_PATH!" "%DEST_DIR%"
      )
  )
  
  goto :complete
  
  :: PULL SCREENSHOTS (handle both directories explicitly)
  :pull_screenshots
  echo.
  echo Pulling SCREENSHOTS matching *%TARGET_DATE%*.jpg ...
  echo Sending files to: "%DEST_DIR%"
  echo ----------------
  
  :: Directory A Android 11 legacy
  for /f "usebackq delims=" %%i in (`
      %ADB_EXE% -s !ADB_TARGET! shell ls /sdcard/DCIM/Screenshots/*%TARGET_DATE%*.jpg
  `) do (
      set "FILE_PATH=%%i"
      if not "!FILE_PATH!"=="" (
          echo Pulling (legacy): !FILE_PATH!
          "%ADB_EXE%" -s !ADB_TARGET! pull "!FILE_PATH!" "%DEST_DIR%"
      )
  )
  
  :: Directory B Android 13 modern
  for /f "usebackq delims=" %%i in (`
      %ADB_EXE% -s !ADB_TARGET! shell ls /storage/emulated/0/DCIM/Screenshots/*%TARGET_DATE%*.jpg
  `) do (
      set "FILE_PATH=%%i"
      if not "!FILE_PATH!"=="" (
          echo Pulling (modern): !FILE_PATH!
          "%ADB_EXE%" -s !ADB_TARGET! pull "!FILE_PATH!" "%DEST_DIR%"
      )
  )
  
  goto :complete
  
  :: PULL CAMERA (INTERNAL STORAGE DCIM)
  :pull_camera_internal
  echo.
  echo Pulling CAMERA images from INTERNAL STORAGE matching *%TARGET_DATE%*.jpg ...
  echo Sending files to: "%DEST_DIR%"
  echo ----------------
  
  for /f "usebackq delims=" %%i in (`
      %ADB_EXE% -s !ADB_TARGET! shell ls /storage/emulated/0/DCIM/Camera/*%TARGET_DATE%*.jpg
  `) do (
      set "FILE_PATH=%%i"
      for /f "delims=" %%r in ("!FILE_PATH!") do set "FILE_PATH=%%r"
      if not "!FILE_PATH!"=="" (
          echo Pulling: !FILE_PATH!
          "%ADB_EXE%" -s !ADB_TARGET! pull "!FILE_PATH!" "%DEST_DIR%"
      )
  )
  goto :complete
  
  :: FINALIZE
  :complete
  start "" "%DEST_DIR%"
  echo Process complete
  pause
  exit /b
  
  :pull_interactive_dirs
  echo.
  echo --- Interactive Directory Pull Mode ---
  echo Destination: "%DEST_DIR%"
  
  echo.
  
  :: --- Detect ALL folders under /storage/emulated/0/DCIM ---
  echo Detecting DCIM folders...
  
  rem Correct quoting: do NOT quote the ls command
  "%ADB_EXE%" -s %ADB_TARGET% shell ls -d /storage/emulated/0/DCIM/*/ > "%TEMP%\dcimdirs.txt" 2>&1
  
  echo.
  echo --- Interactive Directory Pull Mode (adb uses the FUSE layer) ---
  echo Destination: "%DEST_DIR%"
  echo.
  
  :: First pull all DCIM subfolders dynamically
  for /f "usebackq delims=" %%D in ("%TEMP%\dcimdirs.txt") do (
      echo Found DCIM folder: %%D
      call :pull_dir "%%D"
  )
  
  :: Then pull the other known directories
  call :pull_dir "/storage/emulated/0/Pictures"
  call :pull_dir "/storage/emulated/0/Download"
  call :pull_dir "/storage/emulated/0/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp Images"
  call :pull_dir "/storage/emulated/0/Android/media/net.psyberia.offlinemaps/OfflineMaps Exports"
  call :pull_dir "/storage/emulated/0/ReadEra/Covers"
  call :pull_dir "/storage/emulated/0/OziExplorer/System Data"
  call :pull_dir "/storage/0CA4-352D/DCIM/Camera"
  call :pull_dir "/sdcard/DCIM/Screenshots"
  
  goto :eod
  
  :pull_dir
  set "DIR=%~1"
  
  echo.
  echo Directory: %DIR%
  
  echo Listing files in %DIR% ...
  %ADB_EXE% -s %ADB_TARGET% shell ls "%DIR%" > "%TEMP%\filelist_raw.txt"
  
  :: Filter out directories so as to keep only real files
  > "%TEMP%\filelist.txt" (
      for /f "usebackq delims=" %%Z in ("%TEMP%\filelist_raw.txt") do (
          %ADB_EXE% -s %ADB_TARGET% shell "[ -f \"%DIR%/%%Z\" ]" && echo %%Z
      )
  )
  
  :: Check if any real files exist
  set "HASFILES="
  for /f "usebackq delims=" %%Z in ("%TEMP%\filelist.txt") do set "HASFILES=1"
  
  if not defined HASFILES (
      echo No files found in %DIR%. Skipping.
      goto :eod
  )
  
  :: Print the actual file list (Option A)
  echo Files found:
  type "%TEMP%\filelist.txt"
  echo.
  
  :: Ask user only if real files exist
  set /p "ANS=Pull this directory? [y/N]: "
  if /i not "%ANS%"=="y" goto :eod
  
  echo Checking directory: %DIR%
  
  :: Count files
  set "COUNT=0"
  for /f "usebackq delims=" %%C in ("%TEMP%\filelist.txt") do set /a COUNT+=1
  echo Found %COUNT% files in %DIR%.
  
  echo Pulling files...
  for /f "usebackq delims=" %%F in ("%TEMP%\filelist.txt") do (
      echo Pulling: %DIR%/%%F
      %ADB_EXE% -s %ADB_TARGET% pull "%DIR%/%%F" "%DEST_DIR%"
  )
  
  :: delete the file and the MediaStore entry and handle space differences
  :: Take into account many mediastore naming syntax and access intricacies
  set /p "DEL=Delete original files from phone (and MediaStore)? [y/N]: "
  if /i "%DEL%"=="y" (
      echo Deleting originals and MediaStore entries...
  
      for /f "usebackq delims=" %%F in ("%TEMP%\filelist.txt") do (
  
          rem --- Delete file (handles spaces correctly) ---
          echo Deleting file: %DIR%/%%F
          "%ADB_EXE%" -s %ADB_TARGET% shell rm "\"%DIR%/%%F\""
  
          rem --- Delete MediaStore entry using full filename (with spaces) ---
          echo Deleting MediaStore entry for: %%F
          "%ADB_EXE%" -s %ADB_TARGET% shell content delete --uri content://media/external/images/media --where "\"_data LIKE '%/%%F'\""
      )
  )
  
  :eod
  exit /b
  
  REM end of adbcopy.bat

-- 
It takes a different kind of person to automate every action on a device.