画像を減色して保存する際の重要な注意(Hyper-Paint チュートリアル 使い方 講座)


Hyper-Paintで画像を減色して保存した画像をIEなどで表示した場合に正しく表示されない場合があります。
詳しく説明すると例えば背景が青い画像を減色してPNG保存してIEなどで表示すると下図のように背景が赤ぽくなってしまう場合があります。
原因はIEとGLDPNGのパレットが若干違う仕様になっているからです、これはPNG読み込みに使っているGLDPNGのバグなのかIEのバクなのかは判然としませんが(IEのパレットが反対になっているのでIEのバグと言えるようだ)、パレットの1番目の赤と青が反対になっている為に起こります。
これには困りましたが仕方なく下図の保存ウインドウの○印の所に小さなボタンを取り付けました。もし上記のようにIEで表示した時に色が変わってしまう場合には○印のボタンを押し下げて保存して下さい、パレットの一番目の赤と青を入れ替えますのでIEで正常に表示されるようになります。但しその画像はHyper-Paintで表示すると色が変わってしまいますが。この現象はBMPやGIFで保存する際には起こりません。

IEで表示した場合に下図のような色に表示された場合に

○印のボタンを押し下げて保存するとパレットの1番目の赤と青が入れ替わり下図のように表示される。


追伸
Hyper-Paint ver.118B以降GLDPNGのソ−スを変更して上記の現象が起きないように修整しました。
つまり BMP、GIF、PNGに関わらず減色する時1番目のパレットの赤と青を入れ替えています、BMPとGIFはこうして保存するとIEや他のソフトで正常に表示されます、PNGは更に保存の際にGLDPNGで1番目のパレットの赤と青を入れ替えています、こうするとPNGの保存の際は減色してからパレットを入れ替えていないのと同じです、こうしてPNGをIEで表示すると正常ですがGLDPNGで読み込むと色がおかしくなりますので読み込みの際にGLDPNGで1番目のパレットの赤と青を入れ替えています、こうすると正常に表示されます、だいぶややこしい話なので混乱しないように。

IEにこのようなバグがあってもこのことはどこでも聞いたことがないのが不思議だがかなり長期間に渡ってしまうと他のソフトがこのバグが出ないように対応してしまっていると今更IEを正常に修正するわけにもいかないのだろう。もし正常になるよう修正するとバグに対応した全てのソフトもまたそれに合わせなければならずとんでもない混乱を引き起こすことになるわけで、そういうわけで今更バグ取りもできないというわけだ。
またこのようなバグは通常の作成では起こりにくいものでどういうわけで起こったのか興味津々でもある、まさかIEのその部分の作成者が何かしらのイタズラでこのようにしたのか?どんな人が行ったのか興味がつきない。

GLDPNGStream.pas

procedure TGLDPNGWriteStream.WritePLTE;
   ・
   ・
   ・
  try
  len:=GetPaletteColorTable(Palette,PGLDPalRGB(ps));
  if len>0 then
  begin
   for i:=0 to Pred(len) do
   begin
    if i=0 then
    begin
     PArrayByte(pd)^[i*3+0]:=PArrayRGB(ps)^[i].rgbBlue; //ここで赤に青を入れる
     PArrayByte(pd)^[i*3+1]:=PArrayRGB(ps)^[i].rgbGreen;
     PArrayByte(pd)^[i*3+2]:=PArrayRGB(ps)^[i].rgbRed; //ここで青に赤を入れる
    end
    else
    begin
     PArrayByte(pd)^[i*3+0]:=PArrayRGB(ps)^[i].rgbRed;
     PArrayByte(pd)^[i*3+1]:=PArrayRGB(ps)^[i].rgbGreen;
     PArrayByte(pd)^[i*3+2]:=PArrayRGB(ps)^[i].rgbBlue;
    end;
   end;
   WriteChunk(PLTE,pd,len*sizeof(TPNGRGB));
 end;
 finally
 FreeMem(ps);
 FreeMem(pd);
 end;
  ・
  ・
  ・
 


procedure TGLDPNGReadStream.ReadPalette;
  ・
  ・
  ・
  // RGBデータ読み込み
   if len>0 then
    for i:=0 to Pred(len) do
    begin
     ReadByte(@paldat,sizeof(paldat));
     with PArrayRGB(ColorTBLBuf)^[i] do
     begin
      if i=0 then
      begin
       rgbRed:=paldat.B; //ここで赤に青を入れる
       rgbGreen:=paldat.G;
       rgbBlue:=paldat.R; //ここで青に赤を入れる
      end
      else
      begin
       rgbRed:=paldat.R;
       rgbGreen:=paldat.G;
       rgbBlue:=paldat.B;
      end;
     end;
   end;
   Dec(FChunkSize,len*sizeof(paldat));
   PaletteSize:=len;
   FChunkFlag:=FChunkFlag+[pcPLTE];
   // コールバック
   DoCallBack(0);
   ・
   ・
   ・
GLDPngのCopyRight表記



ネストしたフォルダを一度に作成する
通常webにはソ−スを載せないつもりでいますがこれを使いたい人のために一つ上げておきます、この手続きにパスを渡すともしそのパスが存在しない場合にフォルダを作成してくれます、しかも例えば c:\test1\test2\test3\test4\test5 を渡すと c: に test1 のフォルダを作り test1の下にtest2を作り test2の下にtest3を作り test3の下にtest4を作り test4の下にtest5を作りを作ってくれます、途中まで例えばtest3までフォルダが存在してもかまいません。通常Delphiの MkDir 手続きはこういうことを行ってくれません、但し一応フォルダのネストは9個までとなっています。While文を使えばもっとスッキリするでしょうけど一応使えるしめんどくさいので誰かやって下さい。

procedure make_dir(dir:string);
label ttt;
var
 i,i1,i2,i3,i4,i5,i6,i7,i8,i9:integer;
 sss,s1,s2,s3,s4,s5,s6,s6_1,s6_2,s6_3,s6_4,s6_5,s6_6,s6_7,s6_8,s6_9:string;
 searchrecx:TSearchrec;
begin
 sss:=GetCurrentDir;
 s6_1:='';
 for i1:=1 to length(dir) do
 begin
  s6_1:=s6_1+' ';
  s6_1[i1]:=dir[i1];
  if i1=length(dir) then
  begin
   s6:='';
   for i:=1 to length(s6_1)-1 do
   begin
    s6:=s6+' ';
    s6[i]:=s6_1[i];
   end;
   if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_1);
   goto ttt;
  end;
  if (comparetext(dir[i1],'\')=0) and (i1>3) then
  begin
   s6:='';
   for i:=1 to length(s6_1)-1 do
   begin
    s6:=s6+' ';
    s6[i]:=s6_1[i];
   end;
   if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_1);
   chDir(s6_1);
   s6_2:='';
   for i2:=i1+1 to length(dir) do
   begin
    s6_2:=s6_2+' ';
    s6_2[i2-i1]:=dir[i2];
    if i2=length(dir) then
    begin
     s6:='';
     for i:=1 to length(s6_2)-1 do
     begin
      s6:=s6+' ';
      s6[i]:=s6_2[i];
     end;
     if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_2);
     goto ttt;
    end;
    if comparetext(dir[i2],'\')=0 then
    begin
     s6:='';
     for i:=1 to length(s6_2)-1 do
     begin
      s6:=s6+' ';
      s6[i]:=s6_2[i];
     end;
     if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_2);
     chDir(s6_2);
     s6_3:='';
     for i3:=i2+1 to length(dir) do
     begin
      s6_3:=s6_3+' ';
      s6_3[i3-i2]:=dir[i3];
      if i3=length(dir) then
      begin
       s6:='';
       for i:=1 to length(s6_3)-1 do
       begin
        s6:=s6+' ';
        s6[i]:=s6_3[i];
       end;
       if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_3);
       goto ttt;
      end;
      if comparetext(dir[i3],'\')=0 then
      begin
       s6:='';
       for i:=1 to length(s6_3)-1 do
       begin
        s6:=s6+' ';
        s6[i]:=s6_3[i];
       end;
       if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_3);
       chDir(s6_3);
       s6_4:='';
       for i4:=i3+1 to length(dir) do
       begin
        s6_4:=s6_4+' ';
        s6_4[i4-i3]:=dir[i4];
        if i4=length(dir) then
        begin
         s6:='';
         for i:=1 to length(s6_4)-1 do
         begin
          s6:=s6+' ';
          s6[i]:=s6_4[i];
         end;
         if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_4);
         goto ttt;
        end;
        if comparetext(dir[i4],'\')=0 then
        begin
         s6:='';
         for i:=1 to length(s6_4)-1 do
         begin
          s6:=s6+' ';
          s6[i]:=s6_4[i];
         end;
         if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_4);
         chDir(s6_4);
         s6_5:='';
         for i5:=i4+1 to length(dir) do
         begin
          s6_5:=s6_5+' ';
          s6_5[i5-i4]:=dir[i5];
          if i5=length(dir) then
          begin
           s6:='';
           for i:=1 to length(s6_5)-1 do
           begin
            s6:=s6+' ';
            s6[i]:=s6_5[i];
           end;
           if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_5);
           goto ttt;
          end;
          if comparetext(dir[i5],'\')=0 then
          begin
           s6:='';
           for i:=1 to length(s6_5)-1 do
           begin
            s6:=s6+' ';
            s6[i]:=s6_5[i];
           end;
           if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_5);
           chDir(s6_5);
           s6_6:='';
           for i6:=i5+1 to length(dir) do
           begin
            s6_6:=s6_6+' ';
            s6_6[i6-i5]:=dir[i6];
            if i6=length(dir) then
            begin
             s6:='';
             for i:=1 to length(s6_6)-1 do
             begin
              s6:=s6+' ';
              s6[i]:=s6_6[i];
             end;
             if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_6);
             goto ttt;
            end;
            if comparetext(dir[i6],'\')=0 then
            begin
             s6:='';
             for i:=1 to length(s6_6)-1 do
             begin
              s6:=s6+' ';
              s6[i]:=s6_6[i];
             end;
             if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_6);
             chDir(s6_6);
             s6_7:='';
             for i7:=i6+1 to length(dir) do
             begin
              s6_7:=s6_7+' ';
              s6_7[i7-i6]:=dir[i7];
              if i7=length(dir) then
              begin
               s6:='';
               for i:=1 to length(s6_7)-1 do
               begin
                s6:=s6+' ';
                s6[i]:=s6_7[i];
               end;
               if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_7);
               goto ttt;
              end;
              if comparetext(dir[i7],'\')=0 then
              begin
               s6:='';
               for i:=1 to length(s6_7)-1 do
               begin
                s6:=s6+' ';
                s6[i]:=s6_7[i];
               end;
               if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_7);
               chDir(s6_7);
               s6_8:='';
               for i8:=i7+1 to length(dir) do
               begin
                s6_8:=s6_8+' ';
                s6_8[i8-i7]:=dir[i8];
                if i8=length(dir) then
                begin
                 s6:='';
                 for i:=1 to length(s6_8)-1 do
                 begin
                  s6:=s6+' ';
                  s6[i]:=s6_8[i];
                 end;
                 if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_8);
                 goto ttt;
                end;
                if comparetext(dir[i8],'\')=0 then
                begin
                 s6:='';
                 for i:=1 to length(s6_8)-1 do
                 begin
                  s6:=s6+' ';
                  s6[i]:=s6_8[i];
                 end;
                 if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_8);
                 chDir(s6_8);
                 s6_9:='';
                 for i9:=i8+1 to length(dir) do
                 begin
                  s6_9:=s6_9+' ';
                  s6_9[i9-i8]:=dir[i9];
                  if i9=length(dir) then
                  begin
                   s6:='';
                   for i:=1 to length(s6_9)-1 do
                   begin
                    s6:=s6+' ';
                    s6[i]:=s6_9[i];
                   end;
                   if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_9);
                   goto ttt;
                  end;
                  if comparetext(dir[i9],'\')=0 then
                  begin
                   s6:='';
                   for i:=1 to length(s6_9)-1 do
                   begin
                    s6:=s6+' ';
                    s6[i]:=s6_9[i];
                   end;
                   if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_9);
                   MessageDlg(s6_9+'以上の深いネストのフォルダは作成できません!',mtwarning,[mbOK],0);
                   chDir(sss);
                   exit;
                  end;
                 end;
                end;
               end;
              end;
             end;
            end;
           end;
          end;
         end;
        end;
       end;
      end;
     end;
    end;
   end;
  end;
 end;
 ttt:
 chDir(sss);
end;

再帰を使った場合
フォルダネストが深くなると再帰する回数がおおくなりその分スタックが消費されるが通常この場合100回や200回再帰されたとしてもスタックオ−バ−フロウにはならないだろうし現実問題200回以上フォルダがネストされるようなことは無いと考えて問題はない。

procedure make_dir(dir:string);
var
  i,i1:integer;
  s6,s6_1,sss:string;
  searchrecx:TSearchrec;
begin
  s6_1:='';
  for i1:=1 to length(dir) do
  begin
    s6_1:=s6_1+' ';
    s6_1[i1]:=dir[i1];
    if i1=length(dir) then
    begin
      s6:='';
      for i:=1 to length(s6_1)-1 do
      begin
        s6:=s6+' ';
        s6[i]:=s6_1[i];
      end;
      if DirectoryExists(s6)=false then mkdir(s6_1);
      exit;
    end;
    if (comparetext(dir[i1],'\')=0) and (i1>3) then
    begin
      s6:='';
      for i:=1 to length(s6_1)-1 do
      begin
        s6:=s6+' ';
        s6[i]:=s6_1[i];
      end;
      if DirectoryExists(s6)=false then mkdir(s6_1);
      make_dir(s6_1);
    end;
  end;
end;

上の再帰のものはフォルダのネストが14とか17とかになると遅くなるし経験上FileExists手続きがLanなどで接続した他のパソコンに対しては確か機能しないことからお仲間のDirectoryExistsやForceDirectoriesも機能しない可能性があるので(確かめていないが)これらを解決すると下記のようになるのではないだろうか。

procedure make_dir(dir:string);
var
 i,i1:integer;
 s6,s6_1,sss:string;
 searchrecx:TSearchrec;
begin
 s6_1:='';
 for i1:=1 to length(dir) do
 begin
  s6_1:=s6_1+' ';
  s6_1[i1]:=dir[i1];
  if i1=length(dir) then
  begin
   s6:='';
   for i:=1 to length(s6_1)-1 do
   begin
    s6:=s6+' ';
    s6[i]:=s6_1[i];
   end;
   if dir_nest>12 then
   begin
    if (findfirst(s6,fadirectory,SearchRecx)<>0) then ForceDirectories(dir);
   end
   else if (findfirst(s6,fadirectory,SearchRecx)<>0) then mkdir(s6_1);
   exit;
  end;
  if ((comparetext(dir[i1],'\')=0) or (comparetext(dir[i1],'/')=0)) and (i1>3) then
  begin
   s6:='';
   for i:=1 to length(s6_1)-1 do
   begin
    s6:=s6+' ';
    s6[i]:=s6_1[i];
   end;
   if ((findfirst(s6,fadirectory,SearchRecx)<>0) and (comparetext(dir[i1],'\')=0)) or ((directoryExists(s6)=true) and (comparetext(dir[i1],'/')=0)) then
   begin
    if dir_nest>12 then
    begin
     ForceDirectories(dir);
     exit;
    end
    else
    begin
     if (comparetext(dir[i1],'/')=0) then ForceDirectories(s6_1)
     else mkdir(s6_1);
    end;
   end;
   inc(dir_nest);
   make_dir(s6_1);
  end;
 end;
end;

                Home


inserted by FC2 system