Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

C# - EXE/DLL로부터 추출한 이미지/아이콘의 배경색 투명 처리

지난번에 EXE/DLL로부터 이미지 추출하는 방법을 설명했는데요.

프로그램에 보여지는 리소스(예: 아이콘) 추출하는 방법
; https://www.sysnet.pe.kr/2/0/1524

실제로 해보니, 아이콘은 투명 처리가 잘 되어 있는데 이미지의 경우에는 BMP 파일로 저장되어 불투명 이미지가 나왔습니다. 그래서 투명 처리가 필요했는데요. 그래픽 툴을 사용하는 것보다 명령행 도구가 없나 해서 검색해 보았더니 다음의 도구가 나오는군요. ^^

ImageMagick  - Convert, Edit, and Compose Images
; http://www.imagemagick.org

Windows Binary Release
; http://www.imagemagick.org/script/binary-releases.php#windows

압축 버전도 제공하므로 이를 내려받아 해제합니다. exe 파일이 몇 개 나오는데, 그중에서 convert.exe 실행 파일을 이용하면 됩니다.

예를 들어 BMP 이미지에서 0xFF00FF RGB 색을 투명으로 처리하고 싶다면 이렇게 실행해 줍니다.

convert file.bmp -transparent #ff00ff file.png

그런데, EXE/DLL로부터 추출된 이미지 같은 경우에는 가끔 다음과 같은 식으로 오류가 발생하면서 처리가 안 될 때가 있습니다.

C:temp>convert file.bmp -transparent #ff00ff file.png
convert.exe: Length and filesize do not match `file.bmp' @ error/bmp.c/ReadBMPImage/817. 

혹시나 싶어, convert.exe 폴더에 있는 다른 실행 파일인 imdisplay.exe로 파일을 열어도 역시 마찬가지의 오류가 발생합니다.

IMDisplayDoc function [DoReadImage] reported an error.
IMDisplay.exe: length and filesize do not match '...' @ error/bmp.c/ReadBMPImage/817

가만보니, palette가 구성된 이미지인 경우인데 Visual Studio로 확인하면 다음과 같이 왼쪽에 팔렛트가 펼쳐집니다.

bmp2png_transparent_1.png

이런 BMP 파일은 그냥 그림판(mspaint.exe)으로 열어서 24bit BMP 파일로 저장해 주고 convert 프로그램을 실행하면 됩니다.




ImageMagick의 convert.exe에는 많은 옵션이 있지만 투명 처리 정도는 C#으로도 간단히 할 수 있습니다. 다음은 이에 대한 코드를 담고 있는 글입니다.

Setting transparency in an image
; http://blogs.msdn.com/b/jmstall/archive/2007/08/06/setting-transparency-in-an-image.aspx

나중에 찾아 보기 쉽도록 여기다 코드를 그대로 복사해 두죠. ^^

// Simple tool to mark a color on the bitmap transparent.
// http://blogs.msdn.com/jmstall
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;

namespace MakeTransparent
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine(
@"Usage:
    MakeTransparent <filename>

Makes the background color in the image transparent. 
This assumes the pixel at 0,0 is the background color. 

This saves it as a new file appended with '.t', so that it doesn't erase 
the original filename.  For example 'c:\dir\a.bmp' becomes 'c:\dir\a.t.bmp'.
Callers can rename as needed.
");
                return;
            }

            string filename = args[0];
            filename = Path.GetFullPath(filename);
            Console.WriteLine("Loading image from:{0}", filename);

            Bitmap myBitmap = new Bitmap(filename);

            // Get the color of a background pixel.
            // Assume upper left corner is opaque.
            Color backColor = myBitmap.GetPixel(0, 0);

            Console.WriteLine("Choosing background color based of pixel at (0,0). Color ={0}", backColor.ToString());

            // Make backColor transparent for myBitmap. This is the heart of the program.
            myBitmap.MakeTransparent(backColor);

            // Change "c:\dir\thing.bmp" to "c:\dir\thing.t.bmp"
            string left = Path.ChangeExtension(filename, null);
            string ext = Path.GetExtension(filename); // includes period ".bmp"
                        
            string outFile = left + ".t" + ext;
            Console.WriteLine("Saving back to file: {0}", outFile);

            myBitmap.Save(outFile);
        }
    }
}

주석에도 달려 있지만, (0,0) 위치의 색을 투명색으로 지정할 뿐 별다르게 특별한 처리는 없습니다.




// https://twitter.com/PR0GRAMMERHUM0R/status/1773122861487575208/photo/1

from rembg import remove
from PIL import Image

input = Image.open('cl.jpg')
output = remove(input)
output.save('output.png')




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 3/29/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2018-12-18 08시10분
[초보입니다] 안녕하세요 다름이 아니라..

아이콘 만들기에 대해 자세히 알고 계신거 같아서 질문드립니다..

저는 해당 exe경로로부터 절대경로든 상대 경로든 일단 프로세스 라이브러리를 통해 실행파일을 만들었으나 해당 exe파일도 절대경로 혹은 상대경로에 따른 exe경로의 ico도 같이 들고와 적용 시키려 합니다... 이것이 가능할까요??
[guest]
2018-12-18 08시12분
[초보입니다] 혹은.. 바로가기 만드는 방법으로 바로가기를 생성했으나..

해당 생성 exe의 속성에 바로가기 탭에 파일경로가 다 들어나기에 해당 서버로 공유 스토리지가 사용자에게 들어납니다..

이것을 제어 할 수 있는 방법중 둘중 어느것이 더 좋을지 잘모르겠으나 방법 또한 찾기가 힘듭니다.. 도움을 주셧으면 감사하겠습니다
[guest]
2018-12-18 10시00분
죄송한데요, 질문의 의도를 전혀 모르겠습니다. 다시, 제가 전혀 모르는 사람이라고 생각하고 질문해 주세요.
정성태
2018-12-18 12시56분
[초보입니다] 죄송합니다.
일단 하고자하는 목표는 이렇습니다.
AD정책을 사용하여 exe 포터블 파일를 사용자에게 날리려 합니다.
로그온 스크립트 사용하여 해당 서버로부터 즉 batch 파일의 형식의 파일을 해당 cmd 명령어 copy로 USER로 전달하는 형식입니다.

해당 파일 크기도 크고 용량을 최대한 줄이기 위해서 바로가기를 만들어 바로가기 아이콘 탭의 바로가기 - 파일 위치 열기를 누르면 해당 서버의 공유 폴더에 접근이 되기에 우회 할 수 없도록 코딩을 하고싶은게 저의 목표입니다.

그래서 고안한게..

using IWshRuntimeLibrary;
using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace ConsoleApp1
{
    class Program
    {
       // static string _createInk = Console.ReadLine();
       // static string _executeEXE = Console.ReadLine();
        static void Main(string[] args)
        {
            string a = @"C:\Documents and Settings\OSH\DESKTOP\lol_Test.lnk";
            //string a = $@"C:\Documents and Settings\OSH\DESKTOP\{_createInk}.lnk";
            if (!System.IO.File.Exists(a))
            {
                CreateEXE();
                ExecutionStartLocation();
            }
            else
            {
                ExecutionStartLocation();
            }
        }
        public static void CreateEXE()
        {
            Process[] processes = Process.GetProcessesByName("ConsoleApp1");
            foreach (var process in processes)
            {
                //dll, exe 모듈을 가져옵니다.
                ProcessModule mainModule = process.MainModule;
                string fileName = mainModule.FileName.ToString();

                string path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
                var wsh = new WshShell();
                IWshRuntimeLibrary.IWshShortcut myShortcut;
                myShortcut = (IWshRuntimeLibrary.IWshShortcut)wsh.CreateShortcut(path + "/lol_Test.lnk");


                myShortcut.TargetPath = fileName; //@"C:\Users\OSH\source\repos\ConsoleApp1\ConsoleApp1\bin\Debug\ConsoleApp1.exe";
                myShortcut.Description = "osh test";
                myShortcut.IconLocation = @"%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe";
                //myShortcut.IconLocation = $@"D:\lol\LeagueClient.exe";
                //myShortcut.IconLocation = $@"D:\lol\{_executeEXE}.exe";
                //@"c:\reg\assign.ico";
                myShortcut.Save();
            }

            
        }
        public static void ExecutionStartLocation()
        {
            System.Diagnostics.Process ps = new System.Diagnostics.Process();
            //ps.StartInfo.FileName = @"D:\lol\LeagueClient.exe";
            ps.StartInfo.FileName = @"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe";
            //ps.StartInfo.FileName = $@"D:\lol\{_executeEXE}.exe";
            ps.Start();
        }
    }
}

이러한 코딩이 되고.. 공유폴더로 접근하는 방법을 ps.StartInfo.FileName = @"D:\\AD-SEVER\test\LeagueClient.exe"; 이런식으로 접근함으로서도..
사용자에게 실제적 위치를 보여줄 수 없게 해놨습니다.
하지만 단점이 해당 ConsoleApp1.exe이라는 exe가 없으면 실행이 되지않기에.. 더좋은 방법이 없을까하고 질문드렸습니다.
[guest]
2018-12-18 01시16분
그러니까, 간단하게 정리해 보면.

test.exe를 실행하는 바로가기 아이콘을 만들어 놓으면 그 바로가기의 속성으로 test.exe를 찾을 수 있으니까, proxy.exe를 대신 사용자 컴퓨터에 로그온 스크립트로 다운로드하게 만들어 놓고 바로가기 아이콘은 그 proxy.exe를 가리키게 한 후 proxy.exe에서는 내부적으로 test.exe를 실행시키도록 (현재 그렇게) 만들었다는 거죠?

그런데 그 방법이 마음에 들지 않아 proxy.exe를 만들지 않고도 test.exe를 실행하는 바로가기 아이콘을 만들고 싶은데 test.exe임을 숨기는 방법이 없냐고 묻는 것이고요? 맞나요?
정성태
2018-12-18 01시31분
[초보입니다] 네네 정확합니다.
제가 워낙 초보자라 설명법이 너무 부족합니다 ㅠㅠ
[guest]
2018-12-18 02시17분
일단, 바로가기 아이콘으로는 해당 문제를 해결할 수 없습니다. 그렇긴 한데, 나름 재치있게 잘 하셨는데요, 딱히 더 나은 방법이 있을 것 같진 않습니다. 가령 mklink를 이용해 또 다른 symbolic link를 만드는 것도 가능하긴 하지만 그것 역시 속성 창을 통해 원래 파일의 위치가 알려집니다.
정성태
2018-12-18 02시29분
[초보입니다] 아하.. 그렇군요..
속성창을 사용자가 제어를 못하게 막던지..
혹은 기존 바로가기와 같은 기능을 만들어야하는데..
해당 C# 콘솔 어플리케이션 라이브러리에서는 ICON만 떠와서 만들 수 있는 기능없는거같고 바로가기를 만드는 과정이 그냥 있는거같아 두가지중 하나를 나름 해결해야보려 하는데.. 저도 여기까지가 한계인거같아 최대한으로 해보고 질문 드려본거라..
해당 작성된 콘솔 앱과 콘솔로 작성하여 만들어진 바로가기 exe를 같이 들고가는 방법으로 콘솔앱을 숨겨서 가져가는 방법도 있는거같은데..
해당 사항에 대해 윗 선임분한테 여쭤봐야할거같습니다..

다른 방법또한 있으신데 비슷하다 하니 참고한번해보겠습니다 ^^
[guest]

[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13606정성태4/24/202465닷넷: 2247. C# - tensorflow 연동 (MNIST 예제)파일 다운로드1
13605정성태4/23/2024322닷넷: 2246. C# - Python.NET을 이용한 파이썬 소스코드 연동파일 다운로드1
13604정성태4/22/2024338오류 유형: 901. Visual Studio - Unable to set the next statement. Set next statement cannot be used in '[Exception]' call stack frames.
13603정성태4/21/2024564닷넷: 2245. C# - IronPython을 이용한 파이썬 소스코드 연동파일 다운로드1
13602정성태4/20/2024795닷넷: 2244. C# - PCM 오디오 데이터를 연속(Streaming) 재생 (Windows Multimedia)파일 다운로드1
13601정성태4/19/2024837닷넷: 2243. C# - PCM 사운드 재생(NAudio)파일 다운로드1
13600정성태4/18/2024846닷넷: 2242. C# - 관리 스레드와 비관리 스레드
13599정성태4/17/2024862닷넷: 2241. C# - WAV 파일의 PCM 사운드 재생(Windows Multimedia)파일 다운로드1
13598정성태4/16/2024884닷넷: 2240. C# - WAV 파일 포맷 + LIST 헤더파일 다운로드2
13597정성태4/15/2024864닷넷: 2239. C# - WAV 파일의 PCM 데이터 생성 및 출력파일 다운로드1
13596정성태4/14/20241049닷넷: 2238. C# - WAV 기본 파일 포맷파일 다운로드1
13595정성태4/13/20241050닷넷: 2237. C# - Audio 장치 열기 (Windows Multimedia, NAudio)파일 다운로드1
13594정성태4/12/20241068닷넷: 2236. C# - Audio 장치 열람 (Windows Multimedia, NAudio)파일 다운로드1
13593정성태4/8/20241079닷넷: 2235. MSBuild - AccelerateBuildsInVisualStudio 옵션
13592정성태4/2/20241217C/C++: 165. CLion으로 만든 Rust Win32 DLL을 C#과 연동
13591정성태4/2/20241193닷넷: 2234. C# - WPF 응용 프로그램에 Blazor App 통합파일 다운로드1
13590정성태3/31/20241078Linux: 70. Python - uwsgi 응용 프로그램이 k8s 환경에서 OOM 발생하는 문제
13589정성태3/29/20241150닷넷: 2233. C# - 프로세스 CPU 사용량을 나타내는 성능 카운터와 Win32 API파일 다운로드1
13588정성태3/28/20241262닷넷: 2232. C# - Unity + 닷넷 App(WinForms/WPF) 간의 Named Pipe 통신 [2]파일 다운로드1
13587정성태3/27/20241168오류 유형: 900. Windows Update 오류 - 8024402C, 80070643
13586정성태3/27/20241328Windows: 263. Windows - 복구 파티션(Recovery Partition) 용량을 늘리는 방법
13585정성태3/26/20241112Windows: 262. PerformanceCounter의 InstanceName에 pid를 추가한 "Process V2"
13584정성태3/26/20241060개발 환경 구성: 708. Unity3D - C# Windows Forms / WPF Application에 통합하는 방법파일 다운로드1
13583정성태3/25/20241195Windows: 261. CPU Utilization이 100% 넘는 경우를 성능 카운터로 확인하는 방법
13582정성태3/19/20241454Windows: 260. CPU 사용률을 나타내는 2가지 수치 - 사용량(Usage)과 활용률(Utilization)파일 다운로드1
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...