웹에서 이미지를 바이너리로 읽어서 새이미지로 저장이 가능한지요?
PHP도 초보이고 나머지 프로그래밍도 겉핧기정도입니다.
먼저 하고픈 기능은 파일속에 포함되어 있는 썸네일 이미지를 바이너리로 읽어들여서
썸네일파일로 저장이 가능한가 입니다.
오토캐드 확장자인 *dwg 파일은 내부에 썸네일을 가지고있습니다. (첨부한 pdf파일을 확인하시고)
인터넷에서 구한 소스는 비베소스이고 파일을 불러와서 썸네일을 보여주는 소스입니다.
private void button1_Click(object sender, EventArgs e)
{
Image image = GetThumbnailFromDwg(@"파일이름.dwg");
pictureBox1.Image = image;
}
Bitmap GetThumbnailFromDwg(string fileName)
{
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (BinaryReader br = new BinaryReader(fs))
{
fs.Seek(0xD, SeekOrigin.Begin);
fs.Seek(0x14 + br.ReadInt32(), SeekOrigin.Begin);
byte bytCnt = br.ReadByte();
if (bytCnt <= 1)
return null;
int imageHeaderStart;
int imageHeaderSize;
byte imageCode;
for (short i = 1; i <= bytCnt; i++)
{
imageCode = br.ReadByte();
imageHeaderStart = br.ReadInt32();
imageHeaderSize = br.ReadInt32();
if (imageCode == 2) // (R14 ~ 2009)
{
fs.Seek(imageHeaderStart, SeekOrigin.Begin);
br.ReadBytes(0xE);
ushort biBitCount = br.ReadUInt16();
br.ReadBytes(4);
uint biSizeImage = br.ReadUInt32();
fs.Seek(imageHeaderStart, SeekOrigin.Begin);
byte[] bitmapBuffer = br.ReadBytes(imageHeaderSize);
uint colorTableSize = (uint)((biBitCount< 9) ? 4 * Math.Pow(2, biBitCount) : 0);
using (MemoryStream ms = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
bw.Write((ushort)0x4D42);
bw.Write(54U + colorTableSize + biSizeImage);
bw.Write(new ushort());
bw.Write(new ushort());
bw.Write(54U + colorTableSize);
bw.Write(bitmapBuffer);
return new Bitmap(ms);
}
}
}
else if (imageCode == 6) // (2010 ~ 2014)
{
fs.Seek(imageHeaderStart, SeekOrigin.Begin);
using (MemoryStream ms = new MemoryStream())
{
fs.CopyTo(ms, imageHeaderStart);
Image img = Image.FromStream(ms);
return new Bitmap(img);
}
}
else if (imageCode == 3)
{
return null;
}
}
}
}
return null;
}
하지만 웹에서 가능한지... 가능하다면 어떻게 해야할지 , 검색해도 이부분에 있어서는 검색이 안되더군요.
이미지를 리사이징해서 썸네일로 변환하는 php 소스는 아주 간단했습니다.
파라메터값이 좀 많긴했지만...
$original_path="images/original.gif";
$origin_img=imagecreatefromgif($original_path);
$new_img=imagecreatetruecolor(200,100); // 가로 200 픽셀, 세로 100 픽셀
imagecopyresampled($new_img, $origin_img, 0, 0, 0, 0, 200, 100, 500, 300);
$save_path="images/resized.gif";
imagegif($new_img, $save_path);
방법좀 가르켜주시면 감사하겠습니다.
혹시 예제소스라도 있으시면 링크 부탁드립니다.
첨부 | 파일 크기 |
---|---|
OpenDesign_Specification_for_.dwg_files.pdf | 532.82 KB |
올려주신 코드는 아래 페이지에 있던 샘플인 것
올려주신 코드는 아래 페이지에 있던 샘플인 것 같은데요.
http://blog.daum.net/cafeofhtewinter/527
php로 포팅해봤습니다.
원 코드는 dwg 파일을 열어서 추출한 썸네일의 Bitmap 오브젝트를 반환하는 식이지만
php에서는 썸네일을 bmp 파일로 저장하도록 했습니다.
.net과 php 모두 잘 모르는 상태에서 연습삼아 해 본 것이니 감안하시고,
적당히 고쳐서 쓰세요. 오류처리하는 코드도 전혀 없습니다.
일단 아래 페이지에서 dwg 샘플을 받아서 돌려보니 동작은 되는 것 같습니다.
http://usa.autodesk.com/adsk/servlet/index?linkID=9240618&id=12456726&siteID=123112
감사합니다.
else if ($imageCode == 6) // (2010 ~ 2014)
{
fseek($f, $imageHeaderStart);
위에서 빠진부분이 있어서 동작안했었지만 작동잘됩니다.
몇가지 테스트를 해봐야 겠지만 현재로선 어려운 부분이 해결되어 기분이 좋네요.
제가 인터넷에서 구한 dwg 파일은 모두 "if
제가 인터넷에서 구한 dwg 파일은 모두 "if ($imageCode == 2) // (R14 ~ 2009)" 에 해당되어
"else if ($imageCode == 6) // (2010 ~ 2014)" 인 경우의 코드는 테스트할 수 없었습니다.
말씀하신 fseek()의 버그만 고치면, ($imageCode == 6)인 경우도 잘 동작하나요?
몇가지 버전으로 테스트해봣습니다.
2000 버전 2004 버젼 2012 버전까지 작동 잘됩니다.
감사합니다.
ps. 이전에 똑같은 내용으로 답변납겼는데 익스플로러 오류인지 등록이안되었네요.
확인 감사합니다. 전에 올린 코드는 C#의
확인 감사합니다.
전에 올린 코드는 C#의 using 문을 무시하고 서둘러 포팅하다보니
fopen()한 파일에 대해 fclose()는 하지 않은채로 return 할 가능성이 있었습니다.
php에서 그런식으로 자원관리를 무시했을때 실제로 부작용이 생기는지는 모르겠지만
어쨌든 그런 경우를 없애기 위해 조금 수정해둔 코드를 올립니다.
추가문의드려도될런지요.
감사합니다.
위 소스로 XE에 페이지를 만들고 열어서 첨부된 파일에대해 썸네일추출후 보여줄려고했는데
첨부파일은 기존의파일과는 달라서 소스적용이 안되는듯합니다.
추가로 검토중인 것이 elfinderxe 라는 XE모듈입니다.
업로드시 이미지파일은 썸네일을 만들어서 보여줍니다. 여기에 dwg썸네일도 추가하고싶은데 알아보기가 힘드네요.
http://tuwlab.com/computer/9086
http://www.xpressengine.com/index.php?mid=download&category_srl=18322923&search_keyword=ELFINDER&package_srl=21643227
웹기반의 파일매니져인데 아직 부족한부분이 많이 보이지만 나름 유용할것같아 소스를 살피는 중입니다만
썸네일생성부분이 쉽게 알아볼수 있게 되어 있지는 않습니다.
많은기능을 가지고가다보니 저처럼 초급자에겐 무리네요.
아래는 소스 일부분입니다.섬네일 생성부분인데 무슨 라이브러리를 이용하는거 같기도 하구요. ^^;
모듈 첨부합니다.
xe 1.5 버전에서 동작하기에 링크해둡니다.
http://mhlee.nflint.com/index.php?mid=board0&document_srl=117
/**
* Return true if required file can be resized.
* By default - the same as canCreateTmb
*
* @param string $path thumnbnail path
* @param array $stat file stat
* @return string|bool
* @author Dmitry (dio) Levashov
**/
protected function canResize($path, $stat) {
return $this->canCreateTmb($path, $stat);
}
/**
* Create thumnbnail and return it's URL on success
*
* @param string $path file path
* @param string $mime file mime type
* @return string|false
* @author Dmitry (dio) Levashov
**/
protected function createTmb($path, $stat) {
if (!$stat || !$this->canCreateTmb($path, $stat)) {
return false;
}
$name = $this->tmbname($stat);
$tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
// copy image into tmbPath so some drivers does not store files on local fs
if (($src = $this->_fopen($path, 'rb')) == false) {
return false;
}
if (($trg = fopen($tmb, 'wb')) == false) {
$this->_fclose($src, $path);
return false;
}
while (!feof($src)) {
fwrite($trg, fread($src, 8192));
}
$this->_fclose($src, $path);
fclose($trg);
$result = false;
$tmbSize = $this->tmbSize;
if (($s = getimagesize($tmb)) == false) {
return false;
}
/* If image smaller or equal thumbnail size - just fitting to thumbnail square */
if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
$result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' );
} else {
if ($this->options['tmbCrop']) {
/* Resize and crop if image bigger than thumbnail */
if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize) ) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
$result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
}
if (($s = getimagesize($tmb)) != false) {
$x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize)/2) : 0;
$y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize)/2) : 0;
$result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png');
}
} else {
$result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, $this->imgLib, 'png');
$result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' );
}
}
if (!$result) {
unlink($tmb);
return false;
}
return $name;
}
/**
* Resize image
*
* @param string $path image file
* @param int $width new width
* @param int $height new height
* @param bool $keepProportions crop image
* @param bool $resizeByBiggerSide resize image based on bigger side if true
* @param string $destformat image destination format
* @return string|false
* @author Dmitry (dio) Levashov
* @author Alexey Sukhotin
**/
protected function imgResize($path, $width, $height, $keepProportions = false, $resizeByBiggerSide = true, $destformat = null) {
if (($s = @getimagesize($path)) == false) {
return false;
}
$result = false;
list($size_w, $size_h) = array($width, $height);
if ($keepProportions == true) {
list($orig_w, $orig_h, $new_w, $new_h) = array($s[0], $s[1], $width, $height);
/* Calculating image scale width and height */
$xscale = $orig_w / $new_w;
$yscale = $orig_h / $new_h;
/* Resizing by biggest side */
if ($resizeByBiggerSide) {
if ($orig_w > $orig_h) {
$size_h = $orig_h * $width / $orig_w;
$size_w = $width;
} else {
$size_w = $orig_w * $height / $orig_h;
$size_h = $height;
}
} else {
if ($orig_w > $orig_h) {
$size_w = $orig_w * $height / $orig_h;
$size_h = $height;
} else {
$size_h = $orig_h * $width / $orig_w;
$size_w = $width;
}
}
}
switch ($this->imgLib) {
case 'imagick':
try {
$img = new imagick($path);
} catch (Exception $e) {
return false;
}
$img->resizeImage($size_w, $size_h, Imagick::FILTER_LANCZOS, true);
$result = $img->writeImage($path);
return $result ? $path : false;
break;
case 'gd':
if ($s['mime'] == 'image/jpeg') {
$img = imagecreatefromjpeg($path);
} elseif ($s['mime'] == 'image/png') {
$img = imagecreatefrompng($path);
} elseif ($s['mime'] == 'image/gif') {
$img = imagecreatefromgif($path);
} elseif ($s['mime'] == 'image/xbm') {
$img = imagecreatefromxbm($path);
}
if ($img && false != ($tmp = imagecreatetruecolor($size_w, $size_h))) {
if (!imagecopyresampled($tmp, $img, 0, 0, 0, 0, $size_w, $size_h, $s[0], $s[1])) {
return false;
}
if ($destformat == 'jpg' || ($destformat == null && $s['mime'] == 'image/jpeg')) {
$result = imagejpeg($tmp, $path, 100);
} else if ($destformat == 'gif' || ($destformat == null && $s['mime'] == 'image/gif')) {
$result = imagegif($tmp, $path, 7);
} else {
$result = imagepng($tmp, $path, 7);
}
imagedestroy($img);
imagedestroy($tmp);
return $result ? $path : false;
}
break;
}
return false;
}
/**
* Crop image
*
* @param string $path image file
* @param int $width crop width
* @param int $height crop height
* @param bool $x crop left offset
* @param bool $y crop top offset
* @param string $destformat image destination format
* @return string|false
* @author Dmitry (dio) Levashov
* @author Alexey Sukhotin
**/
protected function imgCrop($path, $width, $height, $x, $y, $destformat = null) {
if (($s = @getimagesize($path)) == false) {
return false;
}
$result = false;
switch ($this->imgLib) {
case 'imagick':
try {
$img = new imagick($path);
} catch (Exception $e) {
return false;
}
$img->cropImage($width, $height, $x, $y);
$result = $img->writeImage($path);
return $result ? $path : false;
break;
case 'gd':
if ($s['mime'] == 'image/jpeg') {
$img = imagecreatefromjpeg($path);
} elseif ($s['mime'] == 'image/png') {
$img = imagecreatefrompng($path);
} elseif ($s['mime'] == 'image/gif') {
$img = imagecreatefromgif($path);
} elseif ($s['mime'] == 'image/xbm') {
$img = imagecreatefromxbm($path);
}
if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) {
if (!imagecopy($tmp, $img, 0, 0, $x, $y, $width, $height)) {
return false;
}
if ($destformat == 'jpg' || ($destformat == null && $s['mime'] == 'image/jpeg')) {
$result = imagejpeg($tmp, $path, 100);
} else if ($destformat == 'gif' || ($destformat == null && $s['mime'] == 'image/gif')) {
$result = imagegif($tmp, $path, 7);
} else {
$result = imagepng($tmp, $path, 7);
}
imagedestroy($img);
imagedestroy($tmp);
return $result ? $path : false;
}
break;
}
return false;
}
XE는 아마 제로보드를 이어서 좀 더 일반화한
XE는 아마 제로보드를 이어서 좀 더 일반화한 소프트웨어인 모양이군요. 웹하드 기능을 제공하는 제3의 소프트웨어인 elfinder라는 것을 포장해서 XE용 모듈로 만든 것이 elFinderXE이고요. (문제되는 부분은 아니지만 라이센스가 LGPLv2, BSD, GPLv2 등 제각각이네요)
소스를 예시해주신대로, elfinder 패키지의 elFinderVolumeDriver.class.php 안에 썸네일 만드는 기능이 들어있는데, 그 작업과정에 이미지 라이브러리로 'gd'를 쓸 수도 있고 'imagick'을 쓸 수도 있는 모양입니다. gd는 bmp 포맷을 지원하지 않아서 dwg에서 추출한 bmp를 다룰 수 없으므로, imagick을 쓰는 경우에만 dwg 썸네일 지원이 가능하겠습니다.
아래의 세 부분을 수정해 봤습니다.
수정한 코드는 아래와 같습니다. 저는 웹작업에 익숙치 않아 위의 패키지들을 설치하고 돌려보려면 배보다 배꼽이 더 커지게 되므로 동작확인까지는 하지 못했습니다. 이를 감안하시고 그냥 출발점 정도로 삼으시면 좋겠습니다.
TODO: GD 라이브러리에 빠져있는 imagecreatefrombmp() 함수를 사람들이 나름대로 구현한 코드가 돌아다니는 것 같습니다. google 뒤지면 많이 나오는데 그 가운데 제대로 구현된 것을 찾아 쓰면 'gd'를 쓰는 경우에도 dwg 썸네일 처리가 가능해질 것입니다.
버그를 고쳐서 지금은 dwg 파일 업로드할 때
이전에 올린 코드는 php에 Imagick이 설치되어 있어야 동작이 가능한데 (사실 제대로 테스트된 코드도 아니지만..), 시스템에는 보통 Imagick이 없는 것 같더군요. 그래서 GD 라이브러리 상에서 동작할 수 있도록 수정했습니다.
이 코드를 쓰면 dwg 파일 업로드할 때 썸네일이 만들어집니다. 그런데 dwg에서 추출된 bmp 파일 중 처리되는 않는 것도 있네요. 인터넷에 굴러다니는 imagecreatefrombmp()를 몇 개 가져다 테스트해봤는데 마찬가지였습니다. 제가 테스트했던 imagecreatefrombmp() 버전들은 모두 묶어 첨부했으니 참고하시고요.
안정적으로 bmp -> png 변환할 방법만 찾으면 잘 동작할 것 같습니다.
TODO:
GD 라이브러리 위에서 동작하는 PHP Image Magician 이란 것이 있기에 가져다 실험해봤는데, imagecreatefrombmp()과 마찬가지였습니다.
잘 안되는 bmp 파일과 그 bmp 파일을 추출했던 dwg 파일도 첨부했습니다.
( dwg 파일 출처: http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=12456726&linkID=9240618 )
삭제함
댓글 달기