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]

... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
1755정성태9/22/201434193오류 유형: 241. Unity Web Player를 설치해도 여전히 설치하라는 화면이 나오는 경우 [4]
1754정성태9/22/201424525VC++: 80. 내 컴퓨터에서 C++ AMP 코드가 실행이 될까요? [1]
1753정성태9/22/201420544오류 유형: 240. Lync로 세미나 참여 시 소리만 들리지 않는 경우 [1]
1752정성태9/21/201440996Windows: 100. 윈도우 8 - RDP 연결을 이용해 VNC처럼 사용자 로그온 화면을 공유하는 방법 [5]
1751정성태9/20/201438885.NET Framework: 464. 프로세스 간 통신 시 소켓 필요 없이 간단하게 Pipe를 열어 통신하는 방법 [1]파일 다운로드1
1750정성태9/20/201423807.NET Framework: 463. PInvoke 호출을 이용한 비동기 파일 작업파일 다운로드1
1749정성태9/20/201423718.NET Framework: 462. 커널 객체를 위한 null DACL 생성 방법파일 다운로드1
1748정성태9/19/201425355개발 환경 구성: 238. [Synergy] 여러 컴퓨터에서 키보드, 마우스 공유
1747정성태9/19/201428361오류 유형: 239. psexec 실행 오류 - The system cannot find the file specified.
1746정성태9/18/201426000.NET Framework: 461. .NET EXE 파일을 닷넷 프레임워크 버전에 상관없이 실행할 수 있을까요? - 두 번째 이야기 [6]파일 다운로드1
1745정성태9/17/201422965개발 환경 구성: 237. 리눅스 Integration Services 버전 업그레이드 하는 방법 [1]
1744정성태9/17/201430974.NET Framework: 460. GetTickCount / GetTickCount64와 0x7FFE0000 주솟값 [4]파일 다운로드1
1743정성태9/16/201420936오류 유형: 238. 설치 오류 - Failed to get size of pseudo bundle
1742정성태8/27/201426915개발 환경 구성: 236. Hyper-V에 설치한 리눅스 VM의 VHD 크기 늘리는 방법 [2]
1741정성태8/26/201421295.NET Framework: 459. GetModuleHandleEx로 알아보는 .NET 메서드의 DLL 모듈 관계파일 다운로드1
1740정성태8/25/201432464.NET Framework: 458. 닷넷 GC가 순환 참조를 해제할 수 있을까요? [2]파일 다운로드1
1739정성태8/24/201426463.NET Framework: 457. 교착상태(Dead-lock) 해결 방법 - Lock Leveling [2]파일 다운로드1
1738정성태8/23/201422000.NET Framework: 456. C# - CAS를 이용한 Lock 래퍼 클래스파일 다운로드1
1737정성태8/20/201419690VS.NET IDE: 93. Visual Studio 2013 동기화 문제
1736정성태8/19/201425535VC++: 79. [부연] CAS Lock 알고리즘은 과연 빠른가? [2]파일 다운로드1
1735정성태8/19/201418128.NET Framework: 455. 닷넷 사용자 정의 예외 클래스의 최소 구현 코드 - 두 번째 이야기
1734정성태8/13/201419778오류 유형: 237. Windows Media Player cannot access the file. The file might be in use, you might not have access to the computer where the file is stored, or your proxy settings might not be correct.
1733정성태8/13/201426259.NET Framework: 454. EmptyWorkingSet Win32 API를 사용하는 C# 예제파일 다운로드1
1732정성태8/13/201434388Windows: 99. INetCache 폴더가 다르게 보이는 이유
1731정성태8/11/201426970개발 환경 구성: 235. 점(.)으로 시작하는 파일명을 탐색기에서 만드는 방법
1730정성태8/11/201422077개발 환경 구성: 234. Royal TS의 터미널(Terminal) 연결에서 한글이 깨지는 현상 해결 방법
... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...